Index: /BAORadio/libindi/v1/.cproject
===================================================================
--- /BAORadio/libindi/v1/.cproject	(revision 500)
+++ /BAORadio/libindi/v1/.cproject	(revision 500)
@@ -0,0 +1,596 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?fileVersion 4.0.0?>
+
+<cproject>
+<storageModule moduleId="org.eclipse.cdt.core.settings">
+<cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.557086600">
+<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.557086600" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+<externalSettings/>
+<extensions>
+<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+</extensions>
+</storageModule>
+<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+<configuration artifactName="indi" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.557086600" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug">
+<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.557086600." name="/" resourcePath="">
+<toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.1496458516" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug">
+<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.1493776148" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/>
+<builder buildPath="${workspace_loc:/libindi/Debug}" id="cdt.managedbuild.target.gnu.builder.exe.debug.2046089588" managedBuildOn="true" name="Gnu Make Builder.Debug" superClass="cdt.managedbuild.target.gnu.builder.exe.debug"/>
+<tool id="cdt.managedbuild.tool.gnu.archiver.base.1783151451" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.986177655" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug">
+<option id="gnu.cpp.compiler.exe.debug.option.optimization.level.1175093219" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
+<option id="gnu.cpp.compiler.exe.debug.option.debugging.level.1357679403" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
+<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.46160672" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.1814206380" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug">
+<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.1010619280" superClass="gnu.c.compiler.exe.debug.option.optimization.level" valueType="enumerated"/>
+<option id="gnu.c.compiler.exe.debug.option.debugging.level.957962666" superClass="gnu.c.compiler.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
+<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1411412652" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1840070313" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug"/>
+<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.878976688" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug">
+<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1999376674" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+</inputType>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.299231340" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug">
+<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1427500530" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+</tool>
+</toolChain>
+</folderInfo>
+</configuration>
+</storageModule>
+<storageModule moduleId="scannerConfiguration">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.557086600;cdt.managedbuild.config.gnu.exe.debug.557086600.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.1814206380;cdt.managedbuild.tool.gnu.c.compiler.input.1360452063">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.557086600;cdt.managedbuild.config.gnu.exe.debug.557086600.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.986177655;cdt.managedbuild.tool.gnu.cpp.compiler.input.304542328">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+</storageModule>
+<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+</cconfiguration>
+<cconfiguration id="cdt.managedbuild.config.gnu.exe.release.466318095">
+<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.466318095" moduleId="org.eclipse.cdt.core.settings" name="Release">
+<externalSettings/>
+<extensions>
+<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+</extensions>
+</storageModule>
+<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+<configuration artifactName="indi" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.466318095" name="Release" parent="cdt.managedbuild.config.gnu.exe.release">
+<folderInfo id="cdt.managedbuild.config.gnu.exe.release.466318095." name="/" resourcePath="">
+<toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.1611427858" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release">
+<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.1982761447" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/>
+<builder buildPath="${workspace_loc:/libindi/Release}" id="cdt.managedbuild.target.gnu.builder.exe.release.441935396" managedBuildOn="true" name="Gnu Make Builder.Release" superClass="cdt.managedbuild.target.gnu.builder.exe.release"/>
+<tool id="cdt.managedbuild.tool.gnu.archiver.base.1069994617" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.262033190" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release">
+<option id="gnu.cpp.compiler.exe.release.option.optimization.level.1354959650" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+<option id="gnu.cpp.compiler.exe.release.option.debugging.level.1014587091" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.2114334407" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.207936269" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release">
+<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.1191429656" superClass="gnu.c.compiler.exe.release.option.optimization.level" valueType="enumerated"/>
+<option id="gnu.c.compiler.exe.release.option.debugging.level.1364432506" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.630339819" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.1620907224" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release"/>
+<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.917553405" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release">
+<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.783757087" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+</inputType>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.assembler.exe.release.2082543307" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release">
+<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1630269364" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+</tool>
+</toolChain>
+</folderInfo>
+</configuration>
+</storageModule>
+<storageModule moduleId="scannerConfiguration">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.557086600;cdt.managedbuild.config.gnu.exe.debug.557086600.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.1814206380;cdt.managedbuild.tool.gnu.c.compiler.input.1360452063">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.557086600;cdt.managedbuild.config.gnu.exe.debug.557086600.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.986177655;cdt.managedbuild.tool.gnu.cpp.compiler.input.304542328">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="false" filePath=""/>
+<parser enabled="false"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+</storageModule>
+<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+</cconfiguration>
+</storageModule>
+<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+<project id="indi.cdt.managedbuild.target.gnu.exe.1859822007" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/>
+</storageModule>
+</cproject>
Index: /BAORadio/libindi/v1/.kdev4/libindi.kdev4
===================================================================
--- /BAORadio/libindi/v1/.kdev4/libindi.kdev4	(revision 500)
+++ /BAORadio/libindi/v1/.kdev4/libindi.kdev4	(revision 500)
@@ -0,0 +1,14 @@
+[Buildset]
+BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x0e\x00l\x00i\x00b\x00i\x00n\x00d\x00i)
+
+[CMake]
+BuildDirs=/home/richard/libindi/libindi_build
+CMakeDir=/usr/share/cmake/Modules
+Current CMake Binary=file:///usr/bin/cmake
+CurrentBuildDir=file:///home/richard/libindi/libindi_build
+CurrentBuildType=
+CurrentInstallDir=file:///usr
+ProjectRootRelative=./
+
+[Project]
+VersionControlSupport=kdevsubversion
Index: /BAORadio/libindi/v1/.project
===================================================================
--- /BAORadio/libindi/v1/.project	(revision 500)
+++ /BAORadio/libindi/v1/.project	(revision 500)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>Project-Source@libindi</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+	</buildSpec>
+	<natures>
+	</natures>
+</projectDescription>
Index: /BAORadio/libindi/v1/AUTHORS
===================================================================
--- /BAORadio/libindi/v1/AUTHORS	(revision 500)
+++ /BAORadio/libindi/v1/AUTHORS	(revision 500)
@@ -0,0 +1,5 @@
+Jasem Mutlaq <mutlaqja@ikarustech.com>
+Elwood C. Downey <ecdowney@clearskyinstitute.com>
+
+INDI drivers were written by numerous volunteers across the globe. Please refer to each driver to find the author's contact info. Thank you for making INDI such a great software!
+
Index: /BAORadio/libindi/v1/BAOTest/BAOtest_main.cpp
===================================================================
--- /BAORadio/libindi/v1/BAOTest/BAOtest_main.cpp	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/BAOtest_main.cpp	(revision 500)
@@ -0,0 +1,307 @@
+/**************************************************************************************
+** Petit simulateur d'antenne
+** BAORadio
+** Franck RICHARD
+***************************************************************************************/
+
+#include "ClientSocket.h"
+#include "ServerSocket.h"
+#include "SocketException.h"
+#include <iostream>
+#include <string>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+
+using namespace std;
+
+
+/**************************************************************************************
+** Extraction de la position de l'antenne
+**
+***************************************************************************************/
+
+Position ExtractPosition(std::string str)
+{
+    Position result;
+
+    std::string str2, str3;
+
+    result.x=-1;
+    result.y=-1;
+
+    int pos = str.find("#");
+
+    if (pos!=string::npos)
+    {
+        str2 = str.substr(pos+2);
+
+        pos = str2.find("Az");
+
+        result.x=atoi(str2.substr(0, pos-1).c_str());
+
+        pos = str2.find("#");
+
+        if (pos!=string::npos)
+        {
+            str3 = str2.substr(pos+2);
+
+            pos = str3.find("Alt");
+
+            result.y=atoi(str3.substr(0, pos-1).c_str());;
+
+        }
+    }
+
+    return result;
+}
+
+Position ExtractPosition2(std::string str)
+{
+    Position result;
+
+    result.x=0;
+    result.y=0;
+
+    if (str.length()>2)
+    {
+        result.x=atoi(str.substr(2, 4).c_str());
+
+        result.y=atoi(str.substr(7, 4).c_str());
+
+        if (str[1]=='f') result.x=-result.x;
+
+        if (str[6]=='f') result.y=-result.y;
+    }
+
+    return result;
+}
+
+/**************************************************************************************
+** CreÌation de l'identifiant de l'antenne aÌ partir de l'IP
+**
+***************************************************************************************/
+/*
+int NumeroServeur()
+{
+    std::string str, str2;
+
+    int fd;
+    struct ifreq ifr;
+
+    fd=socket(AF_INET, SOCK_DGRAM, 0);
+
+    ifr.ifr_addr.sa_family=AF_INET;
+
+    strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);
+
+    ioctl(fd, SIOCGIFADDR, &ifr);
+
+    close(fd);
+
+    str=(std::string)inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
+
+    int pos = str.find_last_of(".");
+
+    if (pos!=string::npos)
+    {
+        str2 = str.substr(pos+1);
+
+        return atoi(str2.c_str());
+    }
+
+    return -1;
+}
+*/
+
+
+/**************************************************************************************
+** MAIN
+**
+***************************************************************************************/
+
+#define ERREURS 50
+
+int main ( int argc, int argv[] )
+{
+    Position Pos, Pos2;
+    char cIP;
+    char IP[20];
+    bool Aleat;
+
+    // Parametres sups
+    bool ErreursAleatoires=false;
+    bool Affichage=true;
+
+    // Position PARK
+    Pos.x=0;
+    Pos.y=0;
+
+    //init nbs aleÌatoires
+    if (ErreursAleatoires) srand(time(NULL));
+
+    
+
+    std::cout <<  "******************\n";
+    std::cout <<  "* Simulateur BAO *\n";
+    std::cout <<  "******************\n\n";
+    std::cout <<  "Adresse IP du serveur :\n";
+    std::cout <<  "1)-  192.168.0.1\n";
+    std::cout <<  "2)-  127.0.0.1\n\n? ";
+    std::cin >> cIP;
+
+    if (cIP=='1') strcpy(IP, "192.168.0.1");
+    else strcpy(IP, "127.0.0.1");
+
+
+    try
+    {
+       ClientSocket client_socket ( IP, 8000 );
+        
+       // ServerSocket socket ( 8000 );        
+       // ServerSocket client_socket;
+       // socket.accept ( client_socket );
+
+        std::string reply;
+        std::string asks,memasks;
+        char chaine[5000];
+
+        while (true)
+        {
+            
+                client_socket.recv(asks);
+
+                int pos=asks.find("\n");
+                memasks=asks;
+		
+                while ((pos!=string::npos) && (asks.length()>1))
+                {
+                    memasks=asks.substr(pos+1);
+                    asks=asks.substr(0,pos);
+
+                    strcpy(chaine, "");
+
+                   
+                        if (ErreursAleatoires) Aleat=rand()%ERREURS != 1; else Aleat=1;
+
+                        if (Affichage) std::cout <<  "Pilote BAO : " << asks << "\n" ;
+         
+
+			if (asks.find("P")!=string::npos)
+                        {
+
+                           strcpy(chaine,"ACK/POSITION\n");
+                           client_socket << chaine;
+//usleep(10000);
+                            if (Affichage) std::cout <<  "MicrocontroÌleur : " << chaine;
+
+                            if (Aleat)
+                            {
+                                sprintf(chaine, "POSITION/%04i/%04i/\n", Pos.x, Pos.y);
+                            }
+                            else
+                            {
+                                strcpy(chaine, "NACK/HALT/POSITION/\n");   //erreur moteur !
+                            }
+                        }
+
+                        if (asks.find("G")!=string::npos)
+                        {
+			
+                            Pos2=ExtractPosition2(asks);
+			    
+			    Pos.x-=Pos2.x;
+			    Pos.y-=Pos2.y;
+
+                            strcpy(chaine,"ACK/GOTO/\n");
+                            client_socket << chaine;
+
+                            if (Affichage)
+			    { 
+                               std::cout <<  "MicrocontroÌleur : " << chaine;
+
+                               std::cout <<  "Positionnement de l antenne...\n";
+                            }
+
+                            // sleep(rand()%10);
+
+                            if (Aleat)
+                            {
+                                strcpy(chaine, "OK/GOTO/\n");
+                            }
+                            else
+                            {
+                                strcpy(chaine, "NACK/HALT/GOTO/\n");   //erreur moteur !
+                            }
+                        }
+
+                        if (asks.find("Z")!=string::npos)
+                        {
+
+                            strcpy(chaine, "ACK/PARK\n");
+                            client_socket << chaine;
+
+                            if (Affichage) std::cout <<  "MicrocontroÌleur : " << chaine;
+
+                            if (Aleat)
+                            {
+                                strcpy(chaine, "OK/PARK/\n");
+                            }
+                            else
+                            {
+                                strcpy(chaine, "NACK/HALT/PARK/\n");   //erreur
+                            }
+                        }
+
+                        if (asks.find("A")!=string::npos)
+                        {
+
+                            strcpy(chaine,"ACK/ABORT\n");
+                            client_socket << chaine;
+
+                            if (Affichage) std::cout <<  "MicrocontroÌleur : " << chaine;
+
+                            if (Aleat)
+                            {
+                                strcpy(chaine, "OK/ABORT/\n");
+                            }
+                            else
+                            {
+                                strcpy(chaine, "NACK/HALT/ABORT/\n");   //erreur
+                            }
+                        }
+
+                        if (strlen(chaine)>1)
+                        {
+                            //   usleep(200);
+
+                            client_socket << chaine;
+
+
+                            if (Affichage)
+                            {
+                                std::cout <<  "MicrocontroÌleur : " << chaine;
+
+                                std::cout <<  "---------\n";
+                            }
+                        }
+                    
+
+                    asks=memasks;
+                    pos=asks.find("\n");
+                }           
+            
+        }
+    }
+    catch ( SocketException& e )
+    {
+        std::cout << "Exception was caught:" << e.description() << "\n";
+    }
+
+    return 0;
+}
Index: /BAORadio/libindi/v1/BAOTest/ClientSocket.cpp
===================================================================
--- /BAORadio/libindi/v1/BAOTest/ClientSocket.cpp	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/ClientSocket.cpp	(revision 500)
@@ -0,0 +1,64 @@
+// Implementation of the ClientSocket class
+
+#include "ClientSocket.h"
+#include "SocketException.h"
+
+
+#include <iostream>
+#include <string>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+ClientSocket::ClientSocket ( std::string host, int port )
+{
+  if ( ! Socket::create() )
+    {
+      throw SocketException ( "Could not create client socket." );
+    }
+
+  if ( ! Socket::connect ( host, port ) )
+    {
+      throw SocketException ( "Could not bind to port." );
+    }
+}
+
+
+const ClientSocket& ClientSocket::operator << ( const std::string& s ) const
+{
+  if ( ! Socket::send ( s ) )
+    {
+     // throw SocketException ( "Could not write to socket." );
+    }
+
+  return *this;
+
+}
+
+
+const ClientSocket& ClientSocket::operator >> ( std::string& s ) const
+{
+  if ( ! Socket::recv ( s ) )
+    {
+    //   throw SocketException ( "Could not read from socket." );
+    }
+
+  return *this;
+}
+
+
+void ClientSocket::recv( std::string& s ) 
+{
+  if ( ! Socket::recv ( s ) )
+    {
+      sleep(1);
+
+      if (! Socket::shutdown() ) std::cout << "shutdown impossible.\n";
+
+      if (! Socket::create() ) std::cout << "create impossible.\n";
+
+      if (! Socket::connect((std::string)"192.168.0.1", 8000)) { std::cout << "connect impossible.\n"; Socket::shutdown(); } else {   std::cout << "Reconnexion reussie.\n"; }
+    }
+}
+
Index: /BAORadio/libindi/v1/BAOTest/ClientSocket.h
===================================================================
--- /BAORadio/libindi/v1/BAOTest/ClientSocket.h	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/ClientSocket.h	(revision 500)
@@ -0,0 +1,28 @@
+// Definition of the ClientSocket class
+
+#ifndef ClientSocket_class
+#define ClientSocket_class
+
+#include "Socket.h"
+
+struct Position
+{
+   int x;
+   int y;
+};
+
+class ClientSocket : private Socket
+{
+ public:
+
+  ClientSocket ( std::string host, int port );
+  virtual ~ClientSocket(){};
+
+  const ClientSocket& operator << ( const std::string& ) const;
+  const ClientSocket& operator >> ( std::string& ) const;
+
+void recv( std::string& s ); 
+};
+
+
+#endif
Index: /BAORadio/libindi/v1/BAOTest/Makefile
===================================================================
--- /BAORadio/libindi/v1/BAOTest/Makefile	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/Makefile	(revision 500)
@@ -0,0 +1,30 @@
+# Makefile for the socket programming example
+#
+
+simple_server_objects = ServerSocket.o Socket.o simple_server_main.o
+simple_client_objects = ClientSocket.o Socket.o simple_client_main.o
+BAOtest_objects = ClientSocket.o ServerSocket.o Socket.o BAOtest_main.o
+
+
+all : simple_server simple_client BAOtest
+
+simple_server: $(simple_server_objects)
+	g++ -o simple_server $(simple_server_objects)
+
+
+simple_client: $(simple_client_objects)
+	g++ -o simple_client $(simple_client_objects)
+
+BAOtest: $(BAOtest_objects)
+	g++ -o BAOtest $(BAOtest_objects)
+
+
+Socket: Socket.cpp
+ServerSocket: ServerSocket.cpp
+ClientSocket: ClientSocket.cpp
+simple_server_main: simple_server_main.cpp
+simple_client_main: simple_client_main.cpp
+BAOtest_main: BAOtest_main.cpp
+
+clean:
+	rm -f *.o *.cpp~ *.h~ simple_server simple_client BAOtest
Index: /BAORadio/libindi/v1/BAOTest/ServerSocket.cpp
===================================================================
--- /BAORadio/libindi/v1/BAOTest/ServerSocket.cpp	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/ServerSocket.cpp	(revision 500)
@@ -0,0 +1,67 @@
+// Implementation of the ServerSocket class
+
+#include "ServerSocket.h"
+#include "SocketException.h"
+
+
+ServerSocket::ServerSocket ( int port )
+{
+  if ( ! Socket::create() )
+    {
+      throw SocketException ( "Could not create server socket." );
+    }
+
+  if ( ! Socket::bind ( port ) )
+    {
+      throw SocketException ( "Could not bind to port." );
+    }
+
+  if ( ! Socket::listen() )
+    {
+      throw SocketException ( "Could not listen to socket." );
+    }
+//Socket::set_non_blocking(true);
+}
+
+ServerSocket::~ServerSocket()
+{
+}
+
+
+const ServerSocket& ServerSocket::operator << ( const std::string& s ) const
+{
+  if ( ! Socket::send ( s ) )
+    {
+      throw SocketException ( "Could not write to socket." );
+    }
+
+  return *this;
+
+}
+
+
+const ServerSocket& ServerSocket::operator >> ( std::string& s ) const
+{
+  if ( ! Socket::recv ( s ) )
+    {
+     throw SocketException ( "Could not read from socket." );
+    }
+
+  return *this;
+}
+
+void ServerSocket::accept ( ServerSocket& sock )
+{
+  if ( ! Socket::accept ( sock ) )
+    {
+      throw SocketException ( "Could not accept socket." );
+    }
+}
+
+void ServerSocket::recv( std::string& s ) 
+{
+  if ( ! Socket::recv ( s ) )
+    {
+    throw SocketException ( "Could  not read from socket." );
+    }
+}
Index: /BAORadio/libindi/v1/BAOTest/ServerSocket.h
===================================================================
--- /BAORadio/libindi/v1/BAOTest/ServerSocket.h	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/ServerSocket.h	(revision 500)
@@ -0,0 +1,27 @@
+// Definition of the ServerSocket class
+
+#ifndef ServerSocket_class
+#define ServerSocket_class
+
+#include "Socket.h"
+
+
+class ServerSocket : private Socket
+{
+ public:
+
+  ServerSocket ( int port );
+  ServerSocket (){};
+  virtual ~ServerSocket();
+
+  const ServerSocket& operator << ( const std::string& ) const;
+  const ServerSocket& operator >> ( std::string& ) const;
+
+  void recv( std::string& s );
+
+  void accept ( ServerSocket& );
+
+};
+
+
+#endif
Index: /BAORadio/libindi/v1/BAOTest/Socket.cpp
===================================================================
--- /BAORadio/libindi/v1/BAOTest/Socket.cpp	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/Socket.cpp	(revision 500)
@@ -0,0 +1,226 @@
+// Implementation of the Socket class.
+
+
+#include "Socket.h"
+#include "string.h"
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <iostream>
+#include <netinet/tcp.h>
+
+
+
+
+
+Socket::Socket() :
+        m_sock ( -1 )
+{
+
+    memset ( &m_addr,
+             0,
+             sizeof ( m_addr ) );
+
+}
+
+Socket::~Socket()
+{
+    if ( is_valid() )
+        ::close ( m_sock );
+}
+
+bool Socket::create()
+{
+    m_sock = socket ( AF_INET,
+                      SOCK_STREAM,
+                      0); //IPPROTO_TCP
+
+    if ( ! is_valid() )
+        return false;
+
+
+   //  TIME_WAIT - argh
+    int on = 1;
+
+    if ( setsockopt ( m_sock, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 ) return false;
+
+    if (setsockopt(m_sock, SOL_TCP, TCP_NODELAY, (const char*) &on, sizeof(on)) <0) return false;
+
+    return true;
+}
+
+
+bool Socket::shutdown()
+{
+  int ret = 0;
+
+  if ( is_valid() )
+      ret =  ::shutdown ( m_sock, 2 );
+  
+  m_sock=-1;
+
+  if ( ret == 0 ) return true;
+
+  return false;
+}
+
+
+bool Socket::bind ( const int port )
+{
+    if ( ! is_valid() ) return false;
+    
+    m_addr.sin_family = AF_INET;
+    m_addr.sin_addr.s_addr = INADDR_ANY;
+    m_addr.sin_port =  htons ( port );
+
+    int bind_return = ::bind ( m_sock,
+                               ( struct sockaddr * ) &m_addr,
+                               sizeof ( m_addr ) );
+
+
+    if ( bind_return == -1 ) return false;
+    
+    return true;
+}
+
+
+bool Socket::listen() const
+{
+    if ( ! is_valid() ) return false;
+    
+    int listen_return = ::listen ( m_sock, MAXCONNECTIONS );
+
+    if ( listen_return == -1 ) return false;
+    
+    return true;
+}
+
+
+bool Socket::accept ( Socket& new_socket ) const
+{
+    int addr_length = sizeof ( m_addr );
+    
+    new_socket.m_sock = ::accept ( m_sock, ( sockaddr * ) &m_addr, ( socklen_t * ) &addr_length );
+
+    if ( new_socket.m_sock <= 0 ) return false;
+        
+    return true;
+}
+
+
+bool Socket::send ( const std::string s ) const
+{
+    int status = ::send ( m_sock, s.c_str(), s.size(), MSG_NOSIGNAL);
+    
+    if ( status == -1 ) return false;
+        
+    return true;    
+}
+
+
+int Socket::recv ( std::string& s ) const
+{
+    int sel;
+    fd_set r;
+    struct timeval timeout;
+
+    if ( ! is_valid() ) return false;
+    
+    s="";
+
+    timeout.tv_sec = 0; // initialise le timeout, ici  les secondes
+    timeout.tv_usec = 1; // les microsecondes
+
+    FD_ZERO(&r); // initialise la liste de fd
+    FD_SET(m_sock, &r); // ajoute la socket dans la liste des fd
+    sel = select(m_sock + 1, &r, NULL, NULL, &timeout);
+    if (sel < 0) // select a rencontrÃ© un problÃšme
+    {
+        return -1;
+    }
+    else if (sel == 0) // timeout
+    {
+	return 1;
+    }
+    else // quelque chose est Ã  lire sur un file descriptor
+    {
+        if (FD_ISSET(m_sock, &r)) // si la socket est prÃªte Ã  Ãªtre lue
+        {
+            char buf [ MAXRECV + 1 ];
+
+            s = "";
+
+            memset ( buf, 0, MAXRECV + 1 );
+
+            int status = ::recv ( m_sock, buf, MAXRECV, 0 );
+
+            if ( status == -1 )
+            {
+	         // lÃ , nous ne sommes pas en prÃ©sence d'une vraie erreur
+		 // car le mode non-bloquant est activÃ© ici
+		 // (consulter la doc de la fct recv...)
+                 if (errno == EAGAIN )
+		 {
+	           return 0;
+		 }
+		 
+		 return -1;
+            }
+            else if ( status == 0 )
+            {
+                return 0;
+            }
+            else
+            {
+                s = buf;
+                return status;
+            }
+        }
+    }
+}
+
+
+
+bool Socket::connect ( const std::string host, const int port )
+{
+    if ( ! is_valid() ) return false;
+
+    memset ( &m_addr,
+             0,
+             sizeof ( m_addr ) );
+
+    m_addr.sin_family = AF_INET;
+    m_addr.sin_port = htons ( port );
+
+    int status = inet_pton ( AF_INET, host.c_str(), &m_addr.sin_addr );
+
+    if ( errno == EAFNOSUPPORT ) return false;
+
+
+    status = ::connect ( m_sock, ( sockaddr * ) &m_addr, sizeof ( m_addr ) );
+
+    if ( status == 0 ) return true;
+    
+    return false;
+}
+
+void Socket::set_non_blocking ( const bool b )
+{
+    int opts;
+
+    opts = fcntl ( m_sock,F_GETFL );
+
+    if ( opts < 0 )
+    {
+        return;
+    }
+
+    if ( b )
+        opts = ( opts | O_NONBLOCK );
+    else
+        opts = ( opts & ~O_NONBLOCK );
+
+    fcntl ( m_sock,
+            F_SETFL,opts );
+
+}
Index: /BAORadio/libindi/v1/BAOTest/Socket.h
===================================================================
--- /BAORadio/libindi/v1/BAOTest/Socket.h	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/Socket.h	(revision 500)
@@ -0,0 +1,61 @@
+// Definition of the Socket class
+
+#ifndef Socket_class
+#define Socket_class
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string>
+#include <arpa/inet.h>
+#include <iostream>
+
+
+const int MAXHOSTNAME = 200;
+const int MAXCONNECTIONS = 5;
+const int MAXRECV = 5000;
+
+
+
+class Socket
+{
+ public:
+  Socket();
+  virtual ~Socket();
+
+
+  // Server initialization
+  bool create();
+  bool bind ( const int port );
+  bool listen() const;
+  bool accept ( Socket& ) const;
+
+  // Client initialization
+  bool connect ( const std::string host, const int port );
+
+  // Data Transimission
+  bool send ( const std::string ) const;
+  int recv ( std::string& ) const;
+
+
+  void set_non_blocking ( const bool );
+
+  bool is_valid() const { return m_sock != -1; }
+
+  bool shutdown();
+
+ private:
+
+  int m_sock;
+  sockaddr_in m_addr;
+
+
+
+
+};
+
+
+#endif
Index: /BAORadio/libindi/v1/BAOTest/SocketException.h
===================================================================
--- /BAORadio/libindi/v1/BAOTest/SocketException.h	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/SocketException.h	(revision 500)
@@ -0,0 +1,23 @@
+// SocketException class
+
+
+#ifndef SocketException_class
+#define SocketException_class
+
+#include <string>
+
+class SocketException
+{
+ public:
+  SocketException ( std::string s ) : m_s ( s ) {};
+  ~SocketException (){};
+
+  std::string description() { return m_s; }
+
+ private:
+
+  std::string m_s;
+
+};
+
+#endif
Index: /BAORadio/libindi/v1/BAOTest/simple_client_main.cpp
===================================================================
--- /BAORadio/libindi/v1/BAOTest/simple_client_main.cpp	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/simple_client_main.cpp	(revision 500)
@@ -0,0 +1,42 @@
+#include "ClientSocket.h"
+#include "SocketException.h"
+#include <iostream>
+#include <string>
+#include <stdio.h>
+
+int main ( int argc, int argv[] )
+{
+  try
+    {
+
+      ClientSocket client_socket ( "192.168.0.1", 8000 );
+
+      std::string reply;
+char chaine[20];
+int i=0;
+
+while(true)
+{
+i++;
+      try
+	{
+sprintf(chaine,"client %i-",i);
+	  client_socket << "Client : " << chaine << "\"\n";
+	  client_socket >> reply;
+	}
+      catch ( SocketException& e) {
+std::cout  << e.description() << "\n";
+break;
+}
+
+      std::cout <<  reply ;
+
+}
+    }
+  catch ( SocketException& e )
+    {
+      std::cout << "Exception was caught:" << e.description() << "\n";
+    }
+
+  return 0;
+}
Index: /BAORadio/libindi/v1/BAOTest/simple_server_main.cpp
===================================================================
--- /BAORadio/libindi/v1/BAOTest/simple_server_main.cpp	(revision 500)
+++ /BAORadio/libindi/v1/BAOTest/simple_server_main.cpp	(revision 500)
@@ -0,0 +1,40 @@
+#include "ServerSocket.h"
+#include "SocketException.h"
+#include <string>
+
+int main ( int argc, int argv[] )
+{
+  std::cout << "running....\n";
+
+  try
+    {
+      // Create the socket
+      ServerSocket server ( 8000 );
+
+      while ( true )
+	{
+
+	  ServerSocket new_sock;
+	  server.accept ( new_sock );
+
+	  try
+	    {
+	      while ( true )
+		{
+		  std::string data;
+		  new_sock >> data;
+		  std::cout << data << "\n";
+		  new_sock << "du serveur\n";
+		}
+	    }
+	  catch ( SocketException& ) {}
+
+	}
+    }
+  catch ( SocketException& e )
+    {
+      std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
+    }
+
+  return 0;
+}
Index: /BAORadio/libindi/v1/CMakeLists.txt
===================================================================
--- /BAORadio/libindi/v1/CMakeLists.txt	(revision 500)
+++ /BAORadio/libindi/v1/CMakeLists.txt	(revision 500)
@@ -0,0 +1,640 @@
+cmake_minimum_required(VERSION 2.4.7)
+
+
+##################  INDI version  ################################
+set(INDI_VERSION "0.6")
+set(INDI_SOVERSION "0")
+
+set(CMAKE_INDI_VERSION_MAJOR 0)
+set(CMAKE_INDI_VERSION_MINOR 6)
+set(CMAKE_INDI_VERSION_RELEASE 1)
+set(CMAKE_INDI_VERSION_STRING "${CMAKE_INDI_VERSION_MAJOR}.${CMAKE_INDI_VERSION_MINOR}.${CMAKE_INDI_VERSION_RELEASE}")
+
+##################  Paths  ################################
+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules/")
+set(DATA_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/indi/")
+set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin")
+set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include")
+
+MESSAGE( STATUS "BIN_INSTALL_DIR: " ${BIN_INSTALL_DIR} )
+
+##################  setup install directories  ################################
+set (LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" )
+set (LIB_DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE STRING "Library directory name")
+## the following are directories where stuff will be installed to
+set(INCLUDE_INSTALL_DIR      "${CMAKE_INSTALL_PREFIX}/include/" CACHE PATH "The subdirectory to the header prefix")
+set(PKGCONFIG_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/pkgconfig/" CACHE STRING "Base directory for pkgconfig files")
+
+##################  Includes  ################################
+Include (CheckCXXSourceCompiles)
+include (MacroOptionalFindPackage)
+include (MacroLogFeature)
+include (MacroBoolTo01)
+include (CheckIncludeFiles)
+
+find_package(ZLIB REQUIRED)
+
+macro_optional_find_package(USB)
+macro_log_feature(LIBUSB_FOUND "libusb" "User level access to USB devices" "http://indi.sf.net" FALSE "" "Provides support for USB based drivers in INDI.")
+
+macro_optional_find_package(CFITSIO)
+
+if (NOT CFITSIO_FOUND OR CFITSIO_VERSION_MAJOR LESS 3)
+  message(FATAL_ERROR "CFITSIO version too old, Please install cfitsio 3.x and try again. http://indi.sf.net")
+endif (NOT CFITSIO_FOUND OR CFITSIO_VERSION_MAJOR LESS 3)
+
+macro_bool_to_01(CFITSIO_FOUND HAVE_CFITSIO_H)
+macro_log_feature(CFITSIO_FOUND "libcfitsio" "A library for reading and writing data files in FITS (Flexible Image Transport System) data format" "http://indi.sf.net" FALSE "3.03" "Provides INDI with FITS I/O support.")
+
+
+macro_optional_find_package(FLI)
+macro_log_feature(FLI_FOUND "libfli" "Finger Lakes Instrument Library" "http://indi.sourceforge.net/" FALSE "1.71" "Provides INDI with support for controlling FLI CCDS & Filter Wheels.")
+
+
+macro_optional_find_package(Nova)
+macro_bool_to_01(NOVA_FOUND HAVE_NOVA_H)
+macro_log_feature(NOVA_FOUND "libnova" "A general purpose, double precision, Celestial Mechanics, Astrometry and Astrodynamics library" "http://indi.sf.net" FALSE "0.12.1" "Provides INDI with astrodynamics library.")
+
+check_include_files(linux/videodev2.h HAVE_LINUX_VIDEODEV2_H)
+check_include_files(termios.h TERMIOS_FOUND)
+macro_bool_to_01(TERMIOS_FOUND HAVE_TERMIOS_H)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h )
+
+include_directories( ${CMAKE_CURRENT_BINARY_DIR})
+include_directories( ${CMAKE_SOURCE_DIR})
+include_directories( ${CMAKE_SOURCE_DIR}/libs)
+include_directories( ${CMAKE_SOURCE_DIR}/libs/webcam)
+
+if (CFITSIO_FOUND)
+  include_directories(${CFITSIO_INCLUDE_DIR})
+endif (CFITSIO_FOUND)
+
+if (NOVA_FOUND)
+    include_directories(${NOVA_INCLUDE_DIR})
+endif (NOVA_FOUND)
+
+if (FLI_FOUND)
+    include_directories(${FLI_INCLUDE_DIR})
+endif (FLI_FOUND)
+
+set(liblilxml_SRCS  ${CMAKE_SOURCE_DIR}/libs/lilxml.c )
+
+set(libindicom_SRCS
+	${CMAKE_SOURCE_DIR}/libs/indicom.c
+	${CMAKE_SOURCE_DIR}/base64.c
+	)
+
+set(libwebcam_SRCS
+	${CMAKE_SOURCE_DIR}/libs/webcam/PPort.cpp
+	${CMAKE_SOURCE_DIR}/libs/webcam/port.cpp
+	${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_base.cpp
+	${CMAKE_SOURCE_DIR}/libs/webcam/ccvt_c2.c
+	${CMAKE_SOURCE_DIR}/libs/webcam/ccvt_misc.c
+	)
+
+set (indimain_SRCS
+	${CMAKE_SOURCE_DIR}/indidrivermain.c
+	${CMAKE_SOURCE_DIR}/eventloop.c
+    )
+
+######################################
+########### INDI SERVER ##############
+######################################
+
+set(indiserver_SRCS indiserver.c fq.c)
+
+add_executable(indiserver ${indiserver_SRCS}  ${liblilxml_SRCS})
+
+target_link_libraries(indiserver  pthread )
+
+if (NOVA_FOUND)
+  target_link_libraries(indiserver ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indiserver RUNTIME DESTINATION bin )
+
+######################################
+######## INDI Static Library #########
+######################################
+add_library(indidriver STATIC ${indimain_SRCS})
+install(TARGETS indidriver ARCHIVE DESTINATION lib${LIB_POSTFIX})
+
+######################################
+######## INDI Shared Library #########
+######################################
+add_library(indi SHARED ${libindicom_SRCS} ${liblilxml_SRCS})
+target_link_libraries(indi m z)
+
+if (NOVA_FOUND)
+target_link_libraries(indi ${NOVA_LIBRARIES})
+endif(NOVA_FOUND)
+if (CFITSIO_FOUND)
+target_link_libraries(indi ${CFITSIO_LIBRARIES})
+endif(CFITSIO_FOUND)
+if (FLI_FOUND)
+target_link_libraries(indi ${FLI_LIBRARIES})
+endif(FLI_FOUND)
+
+install(TARGETS indi LIBRARY DESTINATION lib${LIB_POSTFIX})
+set_target_properties(indi PROPERTIES VERSION ${INDI_VERSION} SOVERSION ${INDI_SOVERSION})
+
+#####################################
+########## TELESCOPE GROUP ##########
+#####################################
+
+########### LX200 Basic #############
+set(lx200basic_SRCS
+   ${indimain_SRCS}
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200basic.cpp )
+
+add_executable(indi_lx200basic ${lx200basic_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_lx200basic ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_lx200basic RUNTIME DESTINATION bin )
+
+#################################################################################
+
+########### LX200 Generic ###########
+set(lx200generic_SRCS
+   ${indimain_SRCS}
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200autostar.cpp
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200_16.cpp
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200gps.cpp
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200generic.cpp
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200classic.cpp
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200apdriver.c
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200ap.cpp )
+
+add_executable(indi_lx200generic ${lx200generic_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_lx200generic  m )
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_lx200generic ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_lx200generic RUNTIME DESTINATION bin )
+
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/make_lx200generic_symlink.cmake
+"exec_program(${CMAKE_COMMAND} ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic ${BUILD_ROOT}${BIN_INSTALL_DIR}/indi_lx200classic)\n
+exec_program(${CMAKE_COMMAND} ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic ${BUILD_ROOT}${BIN_INSTALL_DIR}/indi_lx200autostar)\n
+exec_program(${CMAKE_COMMAND} ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic ${BUILD_ROOT}${BIN_INSTALL_DIR}/indi_lx200_16)\n
+exec_program(${CMAKE_COMMAND} ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic ${BUILD_ROOT}${BIN_INSTALL_DIR}/indi_lx200gps)\n
+exec_program(${CMAKE_COMMAND} ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic ${BUILD_ROOT}${BIN_INSTALL_DIR}/indi_lx200ap)\n
+")
+set_target_properties(indi_lx200generic PROPERTIES POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/make_lx200generic_symlink.cmake)
+#################################################################################
+
+########### Celestron GPS ############
+set(celestrongps_SRCS
+   ${indimain_SRCS}
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/celestronprotocol.c
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/celestrongps.cpp )
+
+add_executable(indi_celestron_gps ${celestrongps_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_celestron_gps m )
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_celestron_gps ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_celestron_gps RUNTIME DESTINATION bin )
+
+#################################################################################
+
+########### Orion Atlas #############
+set(orionatlas_SRCS
+   ${indimain_SRCS}
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/orionatlas.cpp )
+
+add_executable(indi_orion_atlas ${orionatlas_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+#target_link_libraries(indi_orion_atlas ${KDE4_KDECORE_LIBS})
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_orion_atlas ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_orion_atlas RUNTIME DESTINATION bin )
+
+#################################################################################
+
+########### Takahashi Temma ##########
+if (NOVA_FOUND)
+
+set(temma_SRCS
+   ${indimain_SRCS}
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/temmadriver.c )
+
+add_executable(indi_temma ${temma_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_temma  ${NOVA_LIBRARIES} m )
+
+install(TARGETS indi_temma RUNTIME DESTINATION bin )
+
+endif (NOVA_FOUND)
+#################################################################################
+
+########### Sky Commander #############
+set(skycommander_SRCS
+   ${indimain_SRCS}
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/skycommander.c )
+
+add_executable(indi_skycommander ${skycommander_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_skycommander  m )
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_skycommander ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_skycommander  RUNTIME DESTINATION bin )
+
+#################################################################################
+
+########### Intelliscope ###############
+set(intelliscope_SRCS
+   ${indimain_SRCS}
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/intelliscope.c )
+
+add_executable(indi_intelliscope ${intelliscope_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_intelliscope  m )
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_intelliscope ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_intelliscope RUNTIME DESTINATION bin )
+
+########### BAO ###############
+set(BAO_SRCS
+   ${indimain_SRCS}
+${CMAKE_SOURCE_DIR}/drivers/telescope/Socket.cpp
+${CMAKE_SOURCE_DIR}/drivers/telescope/ServerSocket.cpp
+${CMAKE_SOURCE_DIR}/drivers/telescope/astro.cpp
+   ${CMAKE_SOURCE_DIR}/drivers/telescope/BAO.cpp )
+   
+add_executable(indi_BAO ${BAO_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_BAO  m  -lpthread
+)
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_BAO ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_BAO RUNTIME DESTINATION bin )
+
+#####################################
+########## FOCUSER GROUP ############
+#####################################
+
+###### FLI Precision Digital Focuser ######
+if (FLI_FOUND)
+set(flipdf_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/drivers/focuser/fli_pdf.c
+)
+
+add_executable(indi_fli_pdf ${flipdf_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_fli_pdf m ${FLI_LIBRARIES})
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_fli_pdf ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_fli_pdf RUNTIME DESTINATION bin )
+endif(FLI_FOUND)
+#################################################################################
+
+################ Robo Focuser ################
+
+set(robofocus_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/drivers/focuser/robofocus.c
+	${CMAKE_SOURCE_DIR}/drivers/focuser/robofocusdriver.c
+   )
+
+add_executable(indi_robofocus ${robofocus_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_robofocus m)
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_robofocus ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_robofocus RUNTIME DESTINATION bin )
+
+#################################################################################
+
+#####################################
+######## FILTER WHEEL GROUP #########
+#####################################
+
+########## True Technology Wheel ############
+set(trutechwheel_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/drivers/filter_wheel/trutech_wheel.c
+   )
+
+add_executable(indi_trutech_wheel ${trutechwheel_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_trutech_wheel  m)
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_trutech_wheel ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_trutech_wheel RUNTIME DESTINATION bin )
+
+#################################################################################
+
+########## FLI Filter Wheel ############
+if (FLI_FOUND)
+set(fliwheel_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/drivers/filter_wheel/fli_wheel.c
+   )
+
+add_executable(indi_fli_wheel ${fliwheel_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_fli_wheel ${FLI_LIBRARIES} m)
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_fli_wheel ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_fli_wheel RUNTIME DESTINATION bin )
+endif (FLI_FOUND)
+#################################################################################
+
+#######################################
+############# CCD GROUP ###############
+#######################################
+
+############# FLI CCD ###############
+if (CFITSIO_FOUND AND FLI_FOUND)
+
+set(fliccd_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/drivers/ccd/fli_ccd.c
+)
+
+add_executable(indi_fli_ccd ${fliccd_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_fli_ccd ${FLI_LIBRARIES} ${CFITSIO_LIBRARIES} m z)
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_fli_ccd ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_fli_ccd RUNTIME DESTINATION bin )
+
+endif (CFITSIO_FOUND AND FLI_FOUND)
+#################################################################################
+
+#########################################
+########### VIDEO GROUP   ###############
+#########################################
+
+########### STV #######################
+if (CFITSIO_FOUND)
+if (NOVA_FOUND)
+
+set(stv_SRCS
+   ${indimain_SRCS}
+   ${CMAKE_SOURCE_DIR}/drivers/video/stvdriver.c
+   ${CMAKE_SOURCE_DIR}/drivers/video/stv.c )
+
+add_executable(indi_sbig_stv ${stv_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_sbig_stv z m ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES})
+
+install(TARGETS indi_sbig_stv RUNTIME DESTINATION bin )
+
+endif (NOVA_FOUND)
+endif(CFITSIO_FOUND)
+
+#################################################################################
+
+### Meade Lunar Planetary Imager ########
+if (CFITSIO_FOUND)
+
+ADD_DEFINITIONS(-DHAVE_LINUX_VIDEODEV2_H)
+
+set(meade_lpi_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp
+	${CMAKE_SOURCE_DIR}/drivers/video/indi_lpi.cpp
+   )
+
+add_executable(indi_meade_lpi ${meade_lpi_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_meade_lpi z ${CFITSIO_LIBRARIES})
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_meade_lpi ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_meade_lpi RUNTIME DESTINATION bin )
+
+endif (CFITSIO_FOUND)
+
+#################################################################################
+
+########### V4L Philips ##############
+if (CFITSIO_FOUND)
+
+set(v4lphilips_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp
+	${CMAKE_SOURCE_DIR}/drivers/video/v4lphilips.cpp
+	${CMAKE_SOURCE_DIR}/drivers/video/indi_philips.cpp
+)
+
+add_executable(indi_v4l_philips ${v4lphilips_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_v4l_philips m z ${CFITSIO_LIBRARIES})
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_v4l_philips ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_v4l_philips RUNTIME DESTINATION bin )
+
+endif (CFITSIO_FOUND)
+
+#################################################################################
+
+########### Generic V4L Driver ###############
+if (CFITSIO_FOUND)
+
+set(v4ldriver_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp
+	${CMAKE_SOURCE_DIR}/drivers/video/indi_v4l.cpp
+   )
+
+add_executable(indi_v4l_generic ${v4ldriver_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_v4l_generic m z ${CFITSIO_LIBRARIES})
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_v4l_generic ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+install(TARGETS indi_v4l_generic RUNTIME DESTINATION bin )
+
+endif (CFITSIO_FOUND)
+
+#################################################################################
+
+########### getINDI ##############
+set(getindi_SRCS
+	${CMAKE_SOURCE_DIR}/eventloop.c
+	${CMAKE_SOURCE_DIR}/tools/getINDIproperty.c
+   )
+
+add_executable(indi_getprop ${getindi_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_getprop m z)
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_getprop ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+
+install(TARGETS indi_getprop RUNTIME DESTINATION bin )
+
+#################################################################################
+
+########### setINDI ##############
+set(setindi_SRCS
+	${CMAKE_SOURCE_DIR}/eventloop.c
+	${CMAKE_SOURCE_DIR}/tools/setINDIproperty.c
+   )
+
+add_executable(indi_setprop ${setindi_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_setprop m z)
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_setprop ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+
+install(TARGETS indi_setprop RUNTIME DESTINATION bin )
+
+#################################################################################
+
+########### evelINDI ##############
+set(evalindi_SRCS
+	${CMAKE_SOURCE_DIR}/eventloop.c
+	${CMAKE_SOURCE_DIR}/tools/compiler.c
+	${CMAKE_SOURCE_DIR}/tools/evalINDI.c
+   )
+
+add_executable(indi_eval ${evalindi_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(indi_eval m z)
+
+if (NOVA_FOUND)
+  target_link_libraries(indi_eval ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+
+install(TARGETS indi_eval RUNTIME DESTINATION bin )
+
+#################################################################################
+## Build Examples. Not installation
+########### Tutorial one ##############
+set(tutorialone_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/examples/tutorial_one.c
+   )
+
+add_executable(tutorial_one ${tutorialone_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(tutorial_one  m)
+
+if (NOVA_FOUND)
+  target_link_libraries(tutorial_one ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+########### Tutorial two ##############
+set(tutorialtwo_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/examples/tutorial_two.c
+   )
+
+add_executable(tutorial_two ${tutorialtwo_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(tutorial_two  m)
+
+if (NOVA_FOUND)
+  target_link_libraries(tutorial_two ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+########### Tutorial three ##############
+set(tutorialthree_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/examples/tutorial_three.c
+   )
+
+add_executable(tutorial_three ${tutorialthree_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(tutorial_three m z)
+
+if (NOVA_FOUND)
+  target_link_libraries(tutorial_three ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+########### Tutorial dome ##############
+set(tutorialdome_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/examples/tutorial_dome.c
+   )
+
+add_executable(tutorial_dome ${tutorialdome_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(tutorial_dome  m)
+
+if (NOVA_FOUND)
+  target_link_libraries(tutorial_dome ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+########### Tutorial rain ##############
+set(tutorialrain_SRCS
+	${indimain_SRCS}
+	${CMAKE_SOURCE_DIR}/examples/tutorial_rain.c
+   )
+
+add_executable(tutorial_rain ${tutorialrain_SRCS}  ${liblilxml_SRCS} ${libindicom_SRCS})
+
+target_link_libraries(tutorial_rain  m)
+
+if (NOVA_FOUND)
+  target_link_libraries(tutorial_rain ${NOVA_LIBRARIES})
+endif (NOVA_FOUND)
+
+#################################################################################
+
+install( FILES drivers.xml DESTINATION ${DATA_INSTALL_DIR})
+
+install( FILES indiapi.h indidevapi.h base64.h eventloop.h ${CMAKE_SOURCE_DIR}/libs/lilxml.h
+ ${CMAKE_SOURCE_DIR}/libs/indicom.h DESTINATION ${INCLUDE_INSTALL_DIR}/libindi COMPONENT Devel)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libindi.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libindi.pc @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libindi.pc DESTINATION ${PKGCONFIG_INSTALL_PREFIX})
+
Index: /BAORadio/libindi/v1/COPYING.LIB
===================================================================
--- /BAORadio/libindi/v1/COPYING.LIB	(revision 500)
+++ /BAORadio/libindi/v1/COPYING.LIB	(revision 500)
@@ -0,0 +1,489 @@
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+                    59 Temple Place - Suite 330
+                    Boston, MA 02111-1307, USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+          How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
Index: /BAORadio/libindi/v1/ChangeLog
===================================================================
--- /BAORadio/libindi/v1/ChangeLog	(revision 500)
+++ /BAORadio/libindi/v1/ChangeLog	(revision 500)
@@ -0,0 +1,70 @@
+From 0.5 to 0.6
+
+        # Devices:
+                + Astrophysics mount is now working.
+                + Apogee driver is now working.
+        # Features:
+                + New libindi structure to streamline development.
+                + Drivers using Standard Property _REQUEST WO to make requests. This facilitates scripting and automation of drivers.
+                + Updated inter-driver communication with INDI SNOOP.
+
+From 0.4 to 0.5
+
+	# Devices:
+		+ True Technology Filter Wheel
+		+ SBIG STV
+
+	# Features:
+	     + Added INDI Observer pattern to enable flexible inter-driver communication.
+             + getINDI now supports BLOBs.
+	     + LX200 Drivers use client timestamp to update the telescope internal clock. The old behavior was to use to system's time.
+	     + Added a new INDI Standard Property: UTC_OFFSET.
+	     + Dropping threaded INDI server in favor of the slightly better non-threaded version due to performance considerations.
+
+	# Bugs
+	     + SBIG CCD driver was updated to fix problems with CFITSIO.
+	     + Updated TTY API to include error reporting, in addition to fixing a few bugs.
+	     + Fixed INDI Mac OSX Crash.
+
+	# Known Issues
+	     + Astrophysics Mount driver (apmount) is not working. It is currently under new development and is intented to be released in the next version as it matures.
+             + Meade LPI exposure is locked to 1 second. The Video4Linux support for timed exposures is limited. A fix should be available in the next release.
+             + The SBIG driver does not allow autoguiding. When one selects the guider CCD, any exposure on the imaging CCD is cancelled and vice-versa.
+
+From v0.3 to v0.4:
+
+	# Devices:
+
+		+ SBIG CCD
+		+ SBIG CFW
+		+ RoboFocus
+		+ FLI Precision Focuser
+		+ Orion Atlas / Sky Scan
+		
+	# Other:
+		+ Added more API documentation and revised existing documentation for accuracy and consistency.
+		+ Fixed UTC correction bug in LX200 driver.
+		+ Fixed pallete selection in V4L 2 drivers.
+		+ Fixed bug in eventloop that can cause IE timers to crash.
+		+ Added variable focus speed for Meade Autostar and GPS.
+		+ Added CFITSIO, a mature and robust FITS library.
+		+ New RS232 API for common access routines.
+
+From v0.2 to v0.3:
+
+	# Devices:
+		+ Apogee CCD (Experimental)
+		+ SkyCommander
+		+ Temma Takahashi
+		+ FLI Filter Wheel
+		+ Meade Lunar Planetary Imager (Experimental)
+		+ Astrophysics AP
+
+	# Other:
+		+ Support for Video 4 Linux 2
+		+ Multi-threaded INDI server
+		+ Binary transfer via BLOB
+		+ INDI scripting tools
+		+ Various bug fixing
+
+INDI Library v1.0 conforms to INDI wire protocol v1.6
Index: /BAORadio/libindi/v1/Doxyfile
===================================================================
--- /BAORadio/libindi/v1/Doxyfile	(revision 500)
+++ /BAORadio/libindi/v1/Doxyfile	(revision 500)
@@ -0,0 +1,255 @@
+# Doxyfile 1.4.1-KDevelop
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = "Instrument Neutral Distributed Interface INDI"
+PROJECT_NUMBER         = 0.7
+OUTPUT_DIRECTORY       = /home/jasem/Projects/doc
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+USE_WINDOWS_ENCODING   = NO
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = 
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = NO
+STRIP_FROM_PATH        = 
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+DISTRIBUTE_GROUP_DOC   = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = NO
+OPTIMIZE_OUTPUT_JAVA   = NO
+SUBGROUPING            = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+HIDE_UNDOC_MEMBERS     = YES
+HIDE_UNDOC_CLASSES     = YES
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = YES
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = YES
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = /home/jasem/Projects/trunk/libindi
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.C \
+                         *.H \
+                         *.tlh \
+                         *.diff \
+                         *.patch \
+                         *.moc \
+                         *.xpm \
+                         *.dox
+RECURSIVE              = YES
+EXCLUDE                = /home/jasem/Projects/trunk/libindi/drivers \
+                         /home/jasem/Projects/trunk/libindi/tools \
+                         /home/jasem/Projects/trunk/libindi/libs/webcam \
+                         /home/jasem/Projects/trunk/libindi/libs/base64.c \
+                         /home/jasem/Projects/trunk/libindi/libs/fq.c \
+                         /home/jasem/Projects/trunk/libindi/indidrivermain.c \
+                         /home/jasem/Projects/trunk/libindi/indiserver.c
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION    = NO
+VERBATIM_HEADERS       = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = doc
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = NO
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = 
+EXPAND_AS_DEFINED      = 
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = YES
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = NO
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = NO
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = 
+DOTFILE_DIRS           = 
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+MAX_DOT_GRAPH_DEPTH    = 1000
+DOT_TRANSPARENT        = NO
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO
Index: /BAORadio/libindi/v1/INSTALL
===================================================================
--- /BAORadio/libindi/v1/INSTALL	(revision 500)
+++ /BAORadio/libindi/v1/INSTALL	(revision 500)
@@ -0,0 +1,28 @@
+INDI Library Setup 0.6.1
+========================
+
+You must have CMake >= 2.4.7 in order to build this package.
+
+1) $ tar -xzf libindi.tar.gz
+2) $ mkdir libindi_build
+3) $ cd libindi_build
+4) $ cmake -DCMAKE_INSTALL_PREFIX=/usr . ../libindi
+5) $ su -c 'make install' or sudo make install
+   
+Refer to README for instructions on running indiserver and device drivers.
+
+Refer to README.drivers for driver-specific information.
+
+Dependencies
+============
+
++ libusb
++ libnova >= 0.12.2
++ libfli  >= 1.7
++ cfitsio >= 3.0
+
+You can download packages for the dependencies above from SUSE BuildService:
+
+http://software.opensuse.org/search
+
+The packages are available for all major distributions.
Index: /BAORadio/libindi/v1/LICENSE
===================================================================
--- /BAORadio/libindi/v1/LICENSE	(revision 500)
+++ /BAORadio/libindi/v1/LICENSE	(revision 500)
@@ -0,0 +1,513 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
Index: /BAORadio/libindi/v1/NEWS
===================================================================
--- /BAORadio/libindi/v1/NEWS	(revision 500)
+++ /BAORadio/libindi/v1/NEWS	(revision 500)
@@ -0,0 +1,6 @@
+-------------------------------------------------------------------------
+News
+-------------------------------------------------------------------------
+
+For the latest news on INDI, refer to INDI's website @ http://indi.sf.net
+
Index: /BAORadio/libindi/v1/README
===================================================================
--- /BAORadio/libindi/v1/README	(revision 500)
+++ /BAORadio/libindi/v1/README	(revision 500)
@@ -0,0 +1,103 @@
+The code here demonstrates the use of INDI, an Instrument-Neutral Device
+Interface protocol. See http://www.clearskyinstitute.com/INDI/INDI.pdf.
+
+Architecture:
+
+    Typical INDI Client / Server / Driver / Device connectivity:
+
+
+    INDI Client 1 ----|                  |---- INDI Driver A  ---- Dev X
+                      |                  |
+    INDI Client 2 ----|                  |---- INDI Driver B  ---- Dev Y
+                      |                  |                     |
+     ...              |--- indiserver ---|                     |-- Dev Z
+                      |                  |
+                      |                  |
+    INDI Client n ----|                  |---- INDI Driver C  ---- Dev T
+
+
+     Client       INET       Server       UNIX     Driver          Hardware
+     processes    sockets    process      pipes    processes       devices
+
+
+
+    Indiserver is the public network access point where one or more INDI Clients
+    may contact one or more INDI Drivers. Indiserver launches each driver
+    process and arranges for it to receive the INDI protocol from Clients on
+    its stdin and expects to find commands destined for Clients on the
+    driver's stdout. Anything arriving from a driver process' stderr is copied
+    to indiserver's stderr.
+
+    Indiserver only provides convenient port, fork and data steering services.
+    If desired, a Client may run and connect to INDI Drivers directly.
+
+Construction:
+
+    An INDI driver typically consists of one .c file, eg, mydriver.c, which
+    #includes indiapi.h to access the reference API declarations. It is
+    compiled then linked with indidrivermain.o, eventloop.o and liblilxml.a to
+    form an INDI process. These supporting files contain the implementation of
+    the INDI Driver API and need not be changed in any way. Note that
+    evenloop.[ch] provide a nice callback facility independent of INDI which
+    may be used in other projects if desired.
+    
+    The driver implementation, again in our example mydriver.c, does not
+    contain a main() but is expected to operate as an event-driver program.
+    The driver must implement each ISxxx() function but never call them. The
+    IS() functions are called by the reference implementation main() as messages
+    arrive from Clients. Within each IS function the driver performs the
+    desired tasks then may report back to the Client by calling the IDxxx()
+    functions.
+
+    The reference API provides IE() functions to allow the driver to add its
+    own callback functions if desired. The driver can arrange for functions to
+    be called when reading a file descriptor will not block; when a time
+    interval has expired; or when there is no other client traffic in progress.
+
+    The sample indiserver is a stand alone process that may be used to run one
+    or more INDI-compliant drivers. It takes the names of each driver process
+    to run in its command line args.
+
+    To build indiserver type 'make indiserver';
+    to build all the sample drivers type 'make drivers';
+    to run the sample server with all drivers type 'make run'.
+    Killing indiserver will also kill all the drivers it started.
+
+Secure remote operation:
+
+    Suppose we want to run indiserver and its clients on a remote machine, r,
+    and connect them to our favorite INDI client, XEphem, running on the
+    local machine.
+
+    From the local machine log onto the remote machine, r, by typing:
+
+	ssh2 -L 7624:s:7624 r
+
+    after logging in, run indiserver on the remote machine:
+    
+	make run
+	
+    Back on the local machine, start XEphem, then open Views -> Sky View ->
+    Telescope -> INDI panel. XEphem will connect to the remote INDI server
+    securely and automatically begin running. Sweet.
+
+Testing:
+
+    A low-level way to test the socket, forking and data steering abilities of
+    indiserver is to use the 'hose' command from the netpipes collection
+    (http://web.purplefrog.com/~thoth/netpipes/netpipes.html):
+
+    1. start indiserver using UNIX' cat program as the only INDI "device":
+
+	% indiserver cat &
+
+    2. use hose to connect to the "cat" device driver which just copies back:
+
+	% hose localhost 7624 --slave
+	hello world
+	hello world
+	more stuff
+	more stuff
+
+! For RCS Only -- Do Not Edit
+! @(#) $RCSfile$ $Date: 2004-02-03 09:34:32 +0300 (Tue, 03 Feb 2004) $ $Revision: 284704 $ $Name:  $
Index: /BAORadio/libindi/v1/README.drivers
===================================================================
--- /BAORadio/libindi/v1/README.drivers	(revision 500)
+++ /BAORadio/libindi/v1/README.drivers	(revision 500)
@@ -0,0 +1,73 @@
+=============================================
+= INDI Drivers Knowledge Base
+=============================================
+
+Introduction
+============
+
+The goal of the INDI Drivers Knowledge Base is to establish a repository that addresses driver-specific issues and problems. 
+
+You can find more up to date information on INDI drivers from the following sources:
+
+1. INDI Device Profiles: http://indi.sf.net/devices.html
+2. INDI Wiki: http://wiki.kde.org/tiki-index.php?page=indi
+
+
+Telescopes
+==========
+
+	+ Meade
+		- Slew Precision:
+			Meade scopes do not report back a successful slew (Meade claim they do, but they don't). Normally, the user hears a beep when slew is complete. However, clients and scripts need to know when the slew is over. Furthermore, you can't hear any beeps if you're controlling the telescope remotely! The solution to this is to continously monitor the target coordinates against the telescope's current coordinate during slew. When the two coordinates are 'close enough', we declare a successful slew. This 'close enough' value was hardcoded in previous versions in INDI, but they are user-adjustable now. The default value for RA and DEC is 3 arcminutes. Setting the values too low might result in endless busy state during slew. Set the values to reflect your instruments precision capabilities. The 3 arcminute value is the average value determined from experience. Please not that the Slew Precision parameter has NO EFFECT what so ever on your telescope slew accuracy or precision, it is merely used to indicate when a successful slew is completed.
+
+		- Track Precision:
+			Tracking is indentical to slewing for sidereal objects. For non-sidereal objects (e.g. planets), the telescope need to continously follow the object as it crosses the sky. For LX200 Classic telescopes, it is possible to ask the scope to track a specific solar system object. However, in all other models, such facitliy does not exist. It is therefore neccesary to manually track non-sideral objects. But continiously issuing 'slew' commands will result in jerky scope motion. To compensate for that, we set an upper limit for the difference between our target coordinates and the current telescope coordinates. If this limit is exceeded, then we tell the scope to slew. The default values for track precision are 3 arcminutes. If you set the values too low, your telescope motion will be jerky and unstable. If you set the values too high, the object might move significantly in the eye piece, if not completely out of it. 
+	+ Celestron
+	+ Meade-Compatible
+		For all Meade-Compatible telescopes, use the lx200basic driver to obtain basic control over your particular controller. It is not recommended to use other LX200* drivers as your controller might or might not support Meade's command set. 
+	+ DCS
+
+CCDs
+====
+
+	+ FLI (Finger Lakes Instruments)
+
+		- FLI driver require read and write access to your USB subsystem. There are two methods to accomplish this:
+		 1. Run fliccd driver as root or setuid your fliccd (chmod +s fliccd).
+		 2. Allow your user write privileges to the USB sub system by mounting /proc/bus/usb with the proper user and group permissions.
+
+	+ SBIG (Santa Barbara ....)
+	+ Apogee
+
+
+Focusers
+========
+
+	+ Meade LX200GPS Microfocuser
+	+ Meade 1206 Primary Mirror Focuser
+	+ JMI NGF Series
+	+ JMI MOTOFOCUS
+	+ Robo Focus
+
+
+Filter Wheels
+=============
+
+	+ FLI Filter Wheel
+	+ SBIG CWF
+	+ TruTechnology Filter Wheel
+
+Video
+=====
+
+	+ Video 4 Linux I, II
+	+ Philips Webcam
+	+ SBIG STV
+	+ Meade Lunar Planetary Imager (Experimental)
+
+		- Exposure: You need to have Kernel 2.6.16+ if you want to take long exposures (1 second or more) with the LPI. To obtain long exposures under 2.6.16+, you need to modify a module paramter for the SN9Cxxx drivers. As root, perform the following:
+
+		[root@localhost #] cd /sys/class/video4linux/video0
+        	[root@localhost #] echo 16 > frame_timeout
+
+		This will increase the timeout for the driver to up to 16 seconds. You can experiment with different values, but 16 seconds is Meade's LPI 'advertised' limit.
Index: /BAORadio/libindi/v1/README.robofocus
===================================================================
--- /BAORadio/libindi/v1/README.robofocus	(revision 500)
+++ /BAORadio/libindi/v1/README.robofocus	(revision 500)
@@ -0,0 +1,94 @@
+INDI Robofocus Driver README.robofocus
+2006-10-02, Markus Wildi
+
+
+1) Development environment:
+
+I used INDI v 0.4 and kstars 1.2. on PIII 800 MHz running Linux 2.6.16.5-default.
+
+2) Known bugs: 
+
+There no bugs known.
+
+The RoboFocus micro controller does not check if a setting is out of the interval 
+0 ... ca. 65000. After a position is out of limits it does not respond to any 
+command and must be turned off and on.
+
+3) Feedback: markus.wildi_AT_datacomm_dot_ch
+
+4) ToDo:
+
+Make it completely complying with the INDI standard properties.
+Add Temperature compensation.
+
+5) Status: 
+
+All commands listed in Appendix I of the RoboFocus manual are implemented.
+
+6) Before you start:
+
+Read at first the RoboFocus manual at least chapter 3. Operation of RoboFocus
+including the description of the RoboFocus Control Program (RFCP) and Appendix I
+Software Commands.
+
+Directions are given as positive or negative numbers.
+
+7) Recommended approach:
+
+Use the default settings for duty cycle, step delay and motor steps per tick
+(a tick is a counter increment by one). Set the back lash correction only to a
+non zero value in case you measured it.
+
+RoboFocus is a slow device and sometimes the position needs to be read out
+separately. That needs additional time. If the LED indicator became green again
+of given property the robofocus driver resumed normal operation regardless what
+happened before.
+
+
+8) Features
+
+Robofocus driver provides the following features: absolute and relative movement, 
+resetting the counter to a given position, maximum and minimum travel, 
+backlash compensation, duty cycle, step delay, number of motor steps per 
+counter increment (tick), the read out of the built in temperature sensor 
+and the four output lines used to control the remote power modules (optional 
+accessories).
+
+The settings of the RoboFocus device are polled and displayed in the corresponding
+fields.
+
+
+Connection tab
+
+Port: Set the name of the RS 232 port. The speed is fixed to 9600 baud.
+
+Power: set the four digital outputs (used for optional RoboFocus accessory)
+
+Temperature: read out of the built in temperature sensor (not a real useful
+device)
+
+Settings: the settings step delay and motor steps per tick determine how fast the 
+stepper motor turns. The duty cycle is can be set to zero for a main mirror focuser
+setup and to a decent value for a rack and pinion focuser. Read the RoboFocus manual.
+
+Motion tab
+
+Extrema: the movement of the focuser and the position setting can be limited.
+
+Maximum travel: (to me the RoboFocus documentation is unclear.)
+
+Set register Position: set the counter to the value given in the input field.
+
+Set register Backlash: define the amount of ticks. If the back lash correction and
+the absolute or relative movement have opposite signs RoboFocus will move into the 
+negative direction of the main movement at the end.
+
+Movement: set it currently to IGNORE (this is a ToDo)
+
+Position: shows the actual position.
+ 
+Speed, Timer: ignore them (this is a ToDo)
+
+Absolute goto: the focuser moves to the absolute position.
+Relative goto: the focuser moves the defined ticks (negative or positive).
+
Index: /BAORadio/libindi/v1/README.stv
===================================================================
--- /BAORadio/libindi/v1/README.stv	(revision 500)
+++ /BAORadio/libindi/v1/README.stv	(revision 500)
@@ -0,0 +1,149 @@
+INDI STV Driver README.stv
+2006-09-10, Markus Wildi
+
+1) Credits:
+
+The initial work is based on the program STVremote by Shashikiran Ganesh.
+email: gshashikiran_AT_linuxmail_dot_org. The RS 232 initialization was 
+programmed by Lukas Zimmermann and parts of the FLI CCD driver are reused
+and slightly adapted.
+
+2) Development environment:
+
+I used INDI v 0.4 and kstars 1.2. kstars versions prior to 1.2 do not work 
+with image download on PIII 800 MHz running Linux 2.6.16.5-default.
+
+3) Known bugs: 
+
+the connection hangs sometimes. At the startup of the driver
+the header or data check sum may fail. This condition is displayed in the
+client's log window and on the terminal where the INDI server has been started.
+Most of the time this is not a severe error condition. 
+
+If something (foreseeable) goes severely wrong the stv driver does an _exit(1).
+
+The STV does not swallow commands at any speed. At many places there are usleep()
+function calls in the code which fit the above mentioned hardware configuration. 
+Because they slow down the communication these settings are good for any faster
+configuration but may fail on slower/older ones. In case where the communication is 
+degraded let me know it.
+
+There are some characters used on the STV's display used in tracking mode. I need
+a more or less clear night to translate them to readable characters on the client's
+display (as far as I remember the content is still readable). 
+
+4) Feedback: markus.wildi_AT_datacomm_dot_ch
+
+6) ToDo:
+
+Image download: Set the correct window size according the information found in 
+image info (e.g. image_info->height).
+
+5) Recommended hardware set up for true remote operation:
+
+Use the STV driver together with the INDI v4ldriver and a video capture 
+card to watch the LCD screen on the local computer.
+
+6) Status: 
+
+The INDI STV driver is an experimental release. Experimental means that it may 
+hang (despite not often). The terminal where you started the INDI server 
+process will sometimes show messages (on stderr) which can only be understood 
+if one reads the source code (search for parts of the message).
+
+The current version is basically a mirror of the STV's built in functions. These 
+primitives can be used in different ways to enhance the versatility of the STV. 
+There are two examples on the tab Settings: 
+
+ 1) set current time (UTC) (time may differ, because it takes a while until it
+    is set and the seconds can only be set in steps of 15 seconds).
+ 2) set the ccd temperature
+
+E.g. The STV forgets the time and temperature settings and they must be 
+entered at each power up.
+
+A farther reaching example: imagine using the STV remotely and without video 
+capture card. The focusing process of the STV might render impossible. I 
+think an automated process together with an a INDI focuser driver should do 
+that work autonomously.
+
+These two examples are implemented in two different ways. Time set is done 
+"blindly". That means the buttons and the rotary knobs (better the software 
+equivalents) are used without any feedback from the STV. The ccd temperature 
+reads the display and stops when the desired temperature appears.
+
+7) Before you start:
+
+If you want to use the INDI STV driver, please refer to the SBIG STV manual 
+first.  The INDI STV driver is basically a remote front end to your fingers 
+with additional features.
+
+Please note that the buffers are labeled as 1 to 32. Buffer number 32 is the
+LCD screen buffer. Despite SBIG's manual says so, accessible are only buffers
+1 through 14 and 32 (at least I found no way to store images e.g. in buffer 
+20).
+
+8) Recommended approach:
+
+Put the STV hardware on your desk an connect it to the computer where the 
+INDI server and client run. 
+First do basic things like changing settings on the STV using the INDI client 
+(tab Buttons and Knobs). Compare the results on the STV display with the 
+results on the INDI client. The STV's two line display should be always 
+synchronous with the INDI client display.
+Then try to take an image which is finally displayed on the STV's LCD screen 
+and try to download it to the INDI client using the default settings on the 
+tab Image Download. 
+
+9) What is not possible:
+
+A mixed operation, that is some commands entered at the STV box and some 
+entered via the INDI STV driver, is hardly possible. There is no way how one 
+can retrieve the current status of the STV besides monitoring the display of 
+the STV.
+
+10) What is not supported:
+
+The meta data of images, e.g. offset, taken in mosaic mode are not read
+out currently.
+
+11) Features:
+
+STV's display is reproduced on each tab for convenience.
+
+Connection tab
+
+Set the device and the speed (9600, 19200, 38400, 57600 and 115200).
+Start/stop update clients display.
+
+Settings tab
+
+Set the time to UTC.
+Set the CCD temperature.
+
+Buttons and Knobs tab
+
+All STV's buttons and knobs are supported. Basically you can use the STV driver 
+as if you were sitting in front of the box.
+The names and groups are identical to what is printed on the STV's box.
+The labels of up/down left/right of the rotary knobs are replaced by Increase and
+Decrease in both cases.
+
+Warning: Do not change the STV's speed with File Ops menu. The communication 
+will stop. 
+
+Download
+
+Buffers Status: get a quick overview which buffers are used or empty.
+
+The meta information about one image or all images are available and printed in 
+the log window.
+
+The buffer on which the buttons One Image (Information and Download) operate on
+can be selected.
+
+The download of one or all images can be initiated either in un- or compressed 
+mode.
+
+An arbitrary window can be set on the original window. This speeds the download
+considerably and is e.g. useful if you want to inspect a single star image.
Index: /BAORadio/libindi/v1/TODO
===================================================================
--- /BAORadio/libindi/v1/TODO	(revision 500)
+++ /BAORadio/libindi/v1/TODO	(revision 500)
@@ -0,0 +1,9 @@
+TODO:
+
+- RTML Support
+- Multi user Scheduler daemon
+- Web interface
+- Vantage Pro/Pro2 Weather Station
+- More Devices!
+
+
Index: /BAORadio/libindi/v1/base64.c
===================================================================
--- /BAORadio/libindi/v1/base64.c	(revision 500)
+++ /BAORadio/libindi/v1/base64.c	(revision 500)
@@ -0,0 +1,248 @@
+#if 0
+    INDI
+    Copyright (C) 2003 Elwood C. Downey
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Adapted from code written by Eric S. Raymond <esr@snark.thyrsus.com>
+#endif
+
+/* Pair of functions to convert to/from base64.
+ * Also can be used to build a standalone utility and a loopback test.
+ * see http://www.faqs.org/rfcs/rfc3548.html
+ */
+
+/** \file base64.c
+    \brief Pair of functions to convert to/from base64.
+
+*/
+
+#include <ctype.h>
+#include "base64.h"
+
+static const char base64digits[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define BAD     (-1)
+static const char base64val[] = {
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
+     52, 53, 54, 55,  56, 57, 58, 59,  60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,  0,  1,  2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
+     15, 16, 17, 18,  19, 20, 21, 22,  23, 24, 25,BAD, BAD,BAD,BAD,BAD,
+    BAD, 26, 27, 28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
+     41, 42, 43, 44,  45, 46, 47, 48,  49, 50, 51,BAD, BAD,BAD,BAD,BAD
+};
+#define DECODE64(c)  (isascii(c) ? base64val[c] : BAD)
+
+/* convert inlen raw bytes at in to base64 string (NUL-terminated) at out. 
+ * out size should be at least 4*inlen/3 + 4.
+ * return length of out (sans trailing NUL).
+ */
+int
+to64frombits(unsigned char *out, const unsigned char *in, int inlen)
+{
+    unsigned char *out0 = out;
+
+    for (; inlen >= 3; inlen -= 3)
+    {
+        *out++ = base64digits[in[0] >> 2];
+        *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+        *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+        *out++ = base64digits[in[2] & 0x3f];
+        in += 3;
+    }
+    if (inlen > 0)
+    {
+        unsigned char fragment;
+    
+        *out++ = base64digits[in[0] >> 2];
+        fragment = (in[0] << 4) & 0x30;
+        if (inlen > 1)
+            fragment |= in[1] >> 4;
+        *out++ = base64digits[fragment];
+        *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
+        *out++ = '=';
+    }
+    *out = '\0';
+
+    return (out-out0);
+}
+
+/* convert base64 at in to raw bytes out, returning count or <0 on error.
+ * base64 may contain any embedded whitespace.
+ * out should be at least 3/4 the length of in.
+ */
+int
+from64tobits(char *out, const char *in)
+{
+    int len = 0;
+    register unsigned char digit1, digit2, digit3, digit4;
+
+    do {
+	do {digit1 = *in++;} while (isspace(digit1));
+        if (DECODE64(digit1) == BAD)
+            return(-1);
+	do {digit2 = *in++;} while (isspace(digit2));
+        if (DECODE64(digit2) == BAD)
+            return(-2);
+	do {digit3 = *in++;} while (isspace(digit3));
+        if (digit3 != '=' && DECODE64(digit3) == BAD)
+            return(-3); 
+	do {digit4 = *in++;} while (isspace(digit4));
+        if (digit4 != '=' && DECODE64(digit4) == BAD)
+            return(-4);
+        *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4);
+        ++len;
+        if (digit3 != '=')
+        {
+            *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2);
+            ++len;
+            if (digit4 != '=')
+            {
+                *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4);
+                ++len;
+            }
+        }
+	while (isspace(*in))
+	    in++;
+    } while (*in && digit4 != '=');
+
+    return (len);
+}
+
+#ifdef BASE64_PROGRAM
+/* standalone program that converts to/from base64.
+ * cc -o base64 -DBASE64_PROGRAM base64.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+usage (char *me)
+{
+	fprintf (stderr, "Purpose: convert stdin to/from base64 on stdout\n");
+	fprintf (stderr, "Usage: %s {-t,-f}\n", me);
+	exit (1);
+}
+
+int
+main (int ac, char *av[])
+{
+	int to64 = 1;
+
+	/* decide whether to or from base64 */
+	if (ac == 2 && strcmp (av[1], "-f") == 0)
+	    to64 = 0;
+	else if (ac != 1 && (ac != 2 || strcmp (av[1], "-t")))
+	    usage (av[0]);
+
+	if (to64) {
+	    unsigned char *rawin, *b64;
+	    int i, n, nrawin, nb64;
+
+	    /* read raw on stdin until EOF */
+	    rawin = malloc(4096);
+	    nrawin = 0;
+	    while ((n = fread (rawin+nrawin, 1, 4096, stdin)) > 0)
+		rawin = realloc (rawin, (nrawin+=n)+4096);
+
+	    /* convert to base64 */
+	    b64 = malloc (4*nrawin/3+4);
+	    nb64 = to64frombits(b64, rawin, nrawin);
+
+	    /* pretty print */
+	    for (i = 0; i < nb64; i += 72)
+		printf ("%.*s\n", 72, b64+i);
+	} else {
+	    unsigned char *raw, *b64;
+	    int n, nraw, nb64;
+
+	    /* read base64 on stdin until EOF */
+	    b64 = malloc(4096);
+	    nb64 = 0;
+	    while ((n = fread (b64+nb64, 1, 4096, stdin)) > 0)
+		b64 = realloc (b64, (nb64+=n)+4096);
+	    b64[nb64] = '\0';
+
+	    /* convert to raw */
+	    raw = malloc (3*nb64/4);
+	    nraw = from64tobits(raw, b64);
+	    if (nraw < 0) {
+		fprintf (stderr, "base64 conversion error: %d\n", nraw);
+		return (1);
+	    }
+
+	    /* write */
+	    fwrite (raw, 1, nraw, stdout);
+	}
+
+	return (0);
+}
+
+#endif
+
+#ifdef LOOPBACK_TEST
+/* standalone test that reads binary on stdin, converts to base64 and back,
+ * then compares. exit 0 if compares the same else 1
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main (int ac, char *av[])
+{
+	unsigned char *rawin, *b64, *rawback;
+	int n, nrawin, nrawback, nb64;
+
+	/* read raw on stdin until EOF */
+	rawin = malloc(4096);
+	nrawin = 0;
+	while ((n = fread (rawin+nrawin, 1, 4096, stdin)) > 0)
+	    rawin = realloc (rawin, (nrawin+=n)+4096);
+
+	/* convert to base64 */
+	b64 = malloc (4*nrawin*3 + 4);
+	nb64 = to64frombits(b64, rawin, nrawin);
+
+	/* convert back to raw */
+	rawback = malloc (3*nb64/4);
+	nrawback = from64tobits(rawback, b64);
+	if (nrawback < 0) {
+	    fprintf (stderr, "base64 error: %d\n", nrawback);
+	    return(1);
+	}
+	if (nrawback != nrawin) {
+	    fprintf (stderr, "base64 back length %d != %d\n", nrawback, nrawin);
+	    return(1);
+	}
+
+	/* compare */
+	if (memcmp (rawback, rawin, nrawin)) {
+	    fprintf (stderr, "compare error\n");
+	    return (1);
+	}
+
+	/* success */
+	return (0);
+}
+#endif
+/* For RCS Only -- Do Not Edit */
+static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile$ $Date: 2006-09-30 14:19:41 +0300 (Sat, 30 Sep 2006) $ $Revision: 590506 $ $Name:  $"};
Index: /BAORadio/libindi/v1/base64.h
===================================================================
--- /BAORadio/libindi/v1/base64.h	(revision 500)
+++ /BAORadio/libindi/v1/base64.h	(revision 500)
@@ -0,0 +1,56 @@
+#if 0
+    INDI
+    Copyright (C) 2003 Elwood C. Downey
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#ifndef BASE64_H
+#define BASE64_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \defgroup base64 Base 64 Functions: Convert from and to base64
+ */
+/*@{*/
+
+/** \brief Convert bytes array to base64. 
+    \param out output buffer in base64. The buffer size must be at least (4 * inlen / 3 + 4) bytes long.
+    \param in input binary buffer
+    \param inlen number of bytes to convert
+    \return 0 on success, -1 on failure.
+ */
+extern int to64frombits(unsigned char *out, const unsigned char *in,
+    int inlen);
+    
+/** \brief Convert base64 to bytes array.
+    \param out output buffer in bytes. The buffer size must be at least (3 * size_of_in_buffer / 4) bytes long.
+    \param in input base64 buffer
+    \return 0 on success, -1 on failure.
+ */
+
+extern int from64tobits(char *out, const char *in);
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /BAORadio/libindi/v1/cmake_modules/FindALUT.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindALUT.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindALUT.cmake	(revision 500)
@@ -0,0 +1,77 @@
+# - Locate ALUT
+# This module defines
+# ALUT_LIBRARY
+# ALUT_FOUND, if false, do not try to link to OpenAL
+# ALUT_INCLUDE_DIR, where to find the headers
+#
+# $OPENALDIR is an environment variable that would
+# correspond to the ./configure --prefix=$OPENALDIR
+# used in building OpenAL.
+#
+# Created by Bryan Donlan, based on the FindOpenAL.cmake module by Eric Wang.
+ 
+FIND_PATH(ALUT_INCLUDE_DIR alut.h
+  $ENV{OPENALDIR}/include
+  ~/Library/Frameworks/OpenAL.framework/Headers
+  /Library/Frameworks/OpenAL.framework/Headers
+  /System/Library/Frameworks/OpenAL.framework/Headers # Tiger
+  /usr/local/include/AL
+  /usr/local/include/OpenAL
+  /usr/local/include
+  /usr/include/AL
+  /usr/include/OpenAL
+  /usr/include
+  /sw/include/AL # Fink
+  /sw/include/OpenAL
+  /sw/include
+  /opt/local/include/AL # DarwinPorts
+  /opt/local/include/OpenAL
+  /opt/local/include
+  /opt/csw/include/AL # Blastwave
+  /opt/csw/include/OpenAL
+  /opt/csw/include
+  /opt/include/AL
+  /opt/include/OpenAL
+  /opt/include
+  )
+# I'm not sure if I should do a special casing for Apple. It is
+# unlikely that other Unix systems will find the framework path.
+# But if they do ([Next|Open|GNU]Step?),
+# do they want the -framework option also?
+IF(${ALUT_INCLUDE_DIR} MATCHES ".framework")
+  STRING(REGEX REPLACE "(.*)/.*\\.framework/.*" "\\1" ALUT_FRAMEWORK_PATH_TMP ${ALUT_INCLUDE_DIR})
+  IF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks"
+      OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks"
+      )
+    # String is in default search path, don't need to use -F
+    SET (ALUT_LIBRARY "-framework OpenAL" CACHE STRING "OpenAL framework for OSX")
+  ELSE("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks"
+      OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks"
+      )
+    # String is not /Library/Frameworks, need to use -F
+    SET(ALUT_LIBRARY "-F${ALUT_FRAMEWORK_PATH_TMP} -framework OpenAL" CACHE STRING "OpenAL framework for OSX")
+  ENDIF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks"
+    OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks"
+    )
+  # Clear the temp variable so nobody can see it
+  SET(ALUT_FRAMEWORK_PATH_TMP "" CACHE INTERNAL "")
+ 
+ELSE(${ALUT_INCLUDE_DIR} MATCHES ".framework")
+  FIND_LIBRARY(ALUT_LIBRARY
+    NAMES alut
+    PATHS
+    $ENV{OPENALDIR}/lib
+    $ENV{OPENALDIR}/libs
+    /usr/local/lib
+    /usr/lib
+    /sw/lib
+    /opt/local/lib
+    /opt/csw/lib
+    /opt/lib
+    )
+ENDIF(${ALUT_INCLUDE_DIR} MATCHES ".framework")
+ 
+SET(ALUT_FOUND "NO")
+IF(ALUT_LIBRARY)
+  SET(ALUT_FOUND "YES")
+ENDIF(ALUT_LIBRARY)
Index: /BAORadio/libindi/v1/cmake_modules/FindAPOGEE.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindAPOGEE.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindAPOGEE.cmake	(revision 500)
@@ -0,0 +1,60 @@
+# - Try to find Apogee Instruments Library
+# Once done this will define
+#
+#  APOGEE_FOUND - system has APOGEE
+#  APOGEE_INCLUDE_DIR - the APOGEE include directory
+#  APOGEE_LIBRARIES - Link these to use APOGEE
+
+# Copyright (c) 2008, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES)
+
+  # in cache already
+  set(APOGEE_FOUND TRUE)
+  message(STATUS "Found libapogee: ${APOGEEU_LIBRARIES}, ${APOGEEE_LIBRARIES}")
+
+else (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES)
+
+  find_path(APOGEE_INCLUDE_DIR libapogee.h
+    PATH_SUFFIXES libapogee
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  # Find Apogee Alta-U Library
+  find_library(APOGEEU_LIBRARIES NAMES apogeeu
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  # Find Apogee Alta-U Library
+  find_library(APOGEEE_LIBRARIES NAMES apogeee
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  if(APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES)
+    set(APOGEE_FOUND TRUE)
+  else (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES)
+    set(APOGEE_FOUND FALSE)
+  endif(APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES)
+
+  if (APOGEE_FOUND)
+    if (NOT APOGEE_FIND_QUIETLY)
+      message(STATUS "Found APOGEE: ${APOGEEU_LIBRARIES}, ${APOGEEE_LIBRARIES}")
+    endif (NOT APOGEE_FIND_QUIETLY)
+  else (APOGEE_FOUND)
+    if (APOGEE_FIND_REQUIRED)
+      message(FATAL_ERROR "libapogee not found. Cannot compile Apogee CCD Driver. Please install libapogee and try again. http://APOGEE.sf.net")
+    endif (APOGEE_FIND_REQUIRED)
+  endif (APOGEE_FOUND) 
+
+ mark_as_advanced(APOGEE_INCLUDE_DIR APOGEEU_LIBRARIES APOGEEE_LIBRARIES)
+
+endif (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindCFITSIO.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindCFITSIO.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindCFITSIO.cmake	(revision 500)
@@ -0,0 +1,66 @@
+# - Try to find CFITSIO
+# Once done this will define
+#
+#  CFITSIO_FOUND - system has CFITSIO
+#  CFITSIO_INCLUDE_DIR - the CFITSIO include directory
+#  CFITSIO_LIBRARIES - Link these to use CFITSIO
+#  CFITSIO_VERSION_STRING - Human readable version number of cfitsio
+#  CFITSIO_VERSION_MAJOR  - Major version number of cfitsio
+#  CFITSIO_VERSION_MINOR  - Minor version number of cfitsio
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+
+  # in cache already
+  set(CFITSIO_FOUND TRUE)
+  message(STATUS "Found CFITSIO: ${CFITSIO_LIBRARIES}")
+
+
+else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+
+  # JM: Packages from different distributions have different suffixes
+  find_path(CFITSIO_INCLUDE_DIR fitsio.h
+    PATH_SUFFIXES libcfitsio3 libcfitsio0 cfitsio
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  find_library(CFITSIO_LIBRARIES NAMES cfitsio
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  if(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+    set(CFITSIO_FOUND TRUE)
+  else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+    set(CFITSIO_FOUND FALSE)
+  endif(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+
+
+  if (CFITSIO_FOUND)
+
+    # Find the version of the cfitsio header
+    execute_process(COMMAND egrep CFITSIO_VERSION ${CFITSIO_INCLUDE_DIR}/fitsio.h
+                    OUTPUT_VARIABLE CFITSIO_VERSION_STRING)
+    STRING(REGEX REPLACE "[^0-9.]" "" CFITSIO_VERSION_STRING ${CFITSIO_VERSION_STRING})
+    STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\1" CFITSIO_VERSION_MAJOR ${CFITSIO_VERSION_STRING})
+    STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\2" CFITSIO_VERSION_MINOR ${CFITSIO_VERSION_STRING})
+
+    if (NOT CFITSIO_FIND_QUIETLY)
+      message(STATUS "Found CFITSIO ${CFITSIO_VERSION_STRING}: ${CFITSIO_LIBRARIES}")
+    endif (NOT CFITSIO_FIND_QUIETLY)
+  else (CFITSIO_FOUND)
+    if (CFITSIO_FIND_REQUIRED)
+      message(STATUS "CFITSIO not found.")
+    endif (CFITSIO_FIND_REQUIRED)
+  endif (CFITSIO_FOUND)
+
+  mark_as_advanced(CFITSIO_INCLUDE_DIR CFITSIO_LIBRARIES)
+
+endif (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindFLI.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindFLI.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindFLI.cmake	(revision 500)
@@ -0,0 +1,53 @@
+# - Try to find Finger Lakes Instruments Library
+# Once done this will define
+#
+#  FLI_FOUND - system has FLI
+#  FLI_INCLUDE_DIR - the FLI include directory
+#  FLI_LIBRARIES - Link these to use FLI
+
+# Copyright (c) 2008, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+
+  # in cache already
+  set(FLI_FOUND TRUE)
+  message(STATUS "Found libfli: ${FLI_LIBRARIES}")
+
+else (FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+
+  find_path(FLI_INCLUDE_DIR libfli.h
+    PATH_SUFFIXES fli
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  find_library(FLI_LIBRARIES NAMES fli
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  if(FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+    set(FLI_FOUND TRUE)
+  else (FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+    set(FLI_FOUND FALSE)
+  endif(FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+
+
+  if (FLI_FOUND)
+    if (NOT FLI_FIND_QUIETLY)
+      message(STATUS "Found FLI: ${FLI_LIBRARIES}")
+    endif (NOT FLI_FIND_QUIETLY)
+  else (FLI_FOUND)
+    if (FLI_FIND_REQUIRED)
+      message(FATAL_ERROR "FLI not found. Please install libfli1-devel. http://indi.sf.net")
+    endif (FLI_FIND_REQUIRED)
+  endif (FLI_FOUND)
+
+  mark_as_advanced(FLI_INCLUDE_DIR FLI_LIBRARIES)
+  
+endif (FLI_INCLUDE_DIR AND FLI_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindGPHOTO2.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindGPHOTO2.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindGPHOTO2.cmake	(revision 500)
@@ -0,0 +1,54 @@
+# - Try to find libgphoto2
+# Once done this will define
+#
+#  LIBGPHOTO2_FOUND - system has libgphoto2
+#  LIBGPHOTO2_INCLUDE_DIR - the libgphoto2 include directory
+#  LIBGPHOTO2_LIBRARIES - Link these to use libghoto2
+
+# Copyright (c) 2009, Geoffrey Hausheer
+# Based on FindINDI by Jasem Mutlaq <mutlaqja@ikarustech.com>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES)
+
+  # in cache already
+  set(LIBGPHOTO2_FOUND TRUE)
+  message(STATUS "Found libgphoto2: ${LIBGPHOTO2_LIBRARIES}")
+
+
+else (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES)
+
+  find_path(LIBGPHOTO2_INCLUDE_DIR gphoto2.h
+    PATH_SUFFIXES gphoto2
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  find_library(LIBGPHOTO2_LIBRARIES NAMES gphoto2
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  if(LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES)
+    set(LIBGPHOTO2_FOUND TRUE)
+  else (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES)
+    set(LIBGPHOTO2_FOUND FALSE)
+  endif(LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES)
+
+
+  if (LIBGPHOTO2_FOUND)
+    if (NOT LIBGPHOTO2_FIND_QUIETLY)
+      message(STATUS "Found libgphoto2: ${LIBGPHOTO2_LIBRARIES}")
+    endif (NOT LIBGPHOTO2_FIND_QUIETLY)
+  else (LIBGPHOTO2_FOUND)
+    if (GLIBPHOTO2_FIND_REQUIRED)
+      message(FATAL_ERROR "libgphoto2 not found.")
+    endif (LIBGPHOTO2_FIND_REQUIRED)
+  endif (LIBGPHOTO2_FOUND)
+
+  mark_as_advanced(LIBGPHOTO2_INCLUDE_DIR LIBGPHOTO2_LIBRARIES)
+
+endif (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindINDI.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindINDI.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindINDI.cmake	(revision 500)
@@ -0,0 +1,60 @@
+# - Try to find INDI
+# Once done this will define
+#
+#  INDI_FOUND - system has INDI
+#  INDI_INCLUDE_DIR - the INDI include directory
+#  INDI_LIBRARIES - Link these to use INDI
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (INDI_INCLUDE_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES)
+
+  # in cache already
+  set(INDI_FOUND TRUE)
+  message(STATUS "Found INDI: ${INDI_LIBRARIES}")
+
+
+else (INDI_INCLUDE_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES)
+
+  find_path(INDI_INCLUDE_DIR indidevapi.h
+    PATH_SUFFIXES libindi
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  find_library(INDI_DRIVER_LIBRARIES NAMES indidriver
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  find_library(INDI_LIBRARIES NAMES indi
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  if(INDI_INCLUDE_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES)
+    set(INDI_FOUND TRUE)
+  else (INDI_INCLUDE_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES)
+    set(INDI_FOUND FALSE)
+  endif(INDI_INCLUDE_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES)
+
+
+  if (INDI_FOUND)
+    if (NOT INDI_FIND_QUIETLY)
+      message(STATUS "Found INDI: ${INDI_LIBRARIES}, ${INDI_DRIVER_LIBRARIES}")
+    endif (NOT INDI_FIND_QUIETLY)
+  else (INDI_FOUND)
+    if (INDI_FIND_REQUIRED)
+      message(FATAL_ERROR "indi-devel not found. Cannot compile INDI drivers. Please install indi-devel and try again. http://indi.sf.net")
+    endif (INDI_FIND_REQUIRED)
+  endif (INDI_FOUND)
+
+  mark_as_advanced(INDI_INCLUDE_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES)
+
+endif (INDI_INCLUDE_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindMEADE.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindMEADE.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindMEADE.cmake	(revision 500)
@@ -0,0 +1,47 @@
+# - Try to find Meade DSI Library.
+# Once done this will define
+#
+#  MEADEDSI_FOUND - system has Meade DSI
+#  MEADEDSI_LIBRARIES - Link these to use Meade DSI
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (MEADEDSI_LIBRARIES)
+
+  # in cache already
+  set(MEADEDSI_FOUND TRUE)
+  message(STATUS "Found MEADEDSI: ${MEADEDSI_LIBRARIES}")
+
+else (MEADEDSI_LIBRARIES)
+
+  find_library(MEADEDSI_LIBRARIES NAMES dsi
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+ set(CMAKE_REQUIRED_LIBRARIES ${MEADEDSI_LIBRARIES})
+
+   if(MEADEDSI_LIBRARIES)
+    set(MEADEDSI_FOUND TRUE)
+  else (MEADEDSI_LIBRARIES)
+    set(MEADEDSI_FOUND FALSE)
+  endif(MEADEDSI_LIBRARIES)
+
+  if (MEADEDSI_FOUND)
+    if (NOT MEADEDSI_FIND_QUIETLY)
+      message(STATUS "Found Meade DSI: ${MEADEDSI_LIBRARIES}")
+    endif (NOT MEADEDSI_FIND_QUIETLY)
+  else (MEADEDSI_FOUND)
+    if (MEADEDSI_FIND_REQUIRED)
+      message(FATAL_ERROR "Meade DSI not found. Please install Meade DSI library. http://linuxdsi.sourceforge.net")
+    endif (MEADEDSI_FIND_REQUIRED)
+  endif (MEADEDSI_FOUND)
+
+  mark_as_advanced(MEADEDSI_LIBRARIES)
+
+endif (MEADEDSI_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindMODBUS.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindMODBUS.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindMODBUS.cmake	(revision 500)
@@ -0,0 +1,56 @@
+# - Try to find libmodbus
+# Once done this will define
+#
+#  MODBUS_FOUND - system has MODBUS
+#  MODBUS_INCLUDE_DIR - the MODBUS include directory
+#  MODBUS_LIBRARIES - Link these to use MODBUS
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+
+  # in cache already
+  set(MODBUS_FOUND TRUE)
+  message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}")
+
+else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+
+  find_path(MODBUS_INCLUDE_DIR modbus.h
+    PATH_SUFFIXES modbus
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  find_library(MODBUS_LIBRARIES NAMES modbus
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+ set(CMAKE_REQUIRED_INCLUDES ${MODBUS_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${MODBUS_LIBRARIES})
+
+   if(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+    set(MODBUS_FOUND TRUE)
+  else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+    set(MODBUS_FOUND FALSE)
+  endif(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+
+  if (MODBUS_FOUND)
+    if (NOT MODBUS_FIND_QUIETLY)
+      message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}")
+    endif (NOT MODBUS_FIND_QUIETLY)
+  else (MODBUS_FOUND)
+    if (MODBUS_FIND_REQUIRED)
+      message(FATAL_ERROR "libmodbus not found. Please install libmodbus-devel. https://launchpad.net/libmodbus/")
+    endif (MODBUS_FIND_REQUIRED)
+  endif (MODBUS_FOUND)
+
+  mark_as_advanced(MODBUS_INCLUDE_DIR MODBUS_LIBRARIES)
+  
+endif (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+
Index: /BAORadio/libindi/v1/cmake_modules/FindNova.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindNova.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindNova.cmake	(revision 500)
@@ -0,0 +1,57 @@
+# - Try to find NOVA
+# Once done this will define
+#
+#  NOVA_FOUND - system has NOVA
+#  NOVA_INCLUDE_DIR - the NOVA include directory
+#  NOVA_LIBRARIES - Link these to use NOVA
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE)
+
+  # in cache already
+  set(NOVA_FOUND TRUE)
+  message(STATUS "Found libnova: ${NOVA_LIBRARIES}")
+
+else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES)
+
+  find_path(NOVA_INCLUDE_DIR libnova.h
+    PATH_SUFFIXES libnova
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  find_library(NOVA_LIBRARIES NAMES nova
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+ set(CMAKE_REQUIRED_INCLUDES ${NOVA_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${NOVA_LIBRARIES})
+ check_cxx_source_compiles("#include <libnova.h> 
+ int main() { ln_get_date_from_tm(NULL, NULL); return 0; }" NOVA_FUNCTION_COMPILE)
+
+   if(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE)
+    set(NOVA_FOUND TRUE)
+  else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE)
+    set(NOVA_FOUND FALSE)
+  endif(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE)
+
+  if (NOVA_FOUND)
+    if (NOT Nova_FIND_QUIETLY)
+      message(STATUS "Found NOVA: ${NOVA_LIBRARIES}")
+    endif (NOT Nova_FIND_QUIETLY)
+  else (NOVA_FOUND)
+    if (Nova_FIND_REQUIRED)
+      message(FATAL_ERROR "libnova not found. Please install libnova0-devel. http://indi.sf.net")
+    endif (Nova_FIND_REQUIRED)
+  endif (NOVA_FOUND)
+
+  mark_as_advanced(NOVA_INCLUDE_DIR NOVA_LIBRARIES)
+  
+endif (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE)
Index: /BAORadio/libindi/v1/cmake_modules/FindQSI.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindQSI.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindQSI.cmake	(revision 500)
@@ -0,0 +1,50 @@
+# - Try to find Quantum Scientific Imaging Library
+# Once done this will define
+#
+#  QSI_FOUND - system has QSI
+#  QSI_INCLUDE_DIR - the QSI include directory
+#  QSI_LIBRARIES - Link these to use QSI
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+
+  # in cache already
+  set(QSI_FOUND TRUE)
+  message(STATUS "Found libqsiapi: ${QSI_LIBRARIES}")
+
+else (QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+
+  find_path(QSI_INCLUDE_DIR qsiapi.h
+    PATH_SUFFIXES qsiapi
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  find_library(QSI_LIBRARIES NAMES qsiapi
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  if(QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+    set(QSI_FOUND TRUE)
+  else (QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+    set(QSI_FOUND FALSE)
+  endif(QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+
+
+  if (QSI_FOUND)
+    if (NOT QSI_FIND_QUIETLY)
+      message(STATUS "Found QSI: ${QSI_LIBRARIES}")
+    endif (NOT QSI_FIND_QUIETLY)
+  else (QSI_FOUND)
+    if (QSI_FIND_REQUIRED)
+      message(FATAL_ERROR "QSI not found. Please install qsiapi http://indi.sf.net")
+    endif (QSI_FIND_REQUIRED)
+  endif (QSI_FOUND)
+
+  mark_as_advanced(QSI_INCLUDE_DIR QSI_LIBRARIES)
+  
+endif (QSI_INCLUDE_DIR AND QSI_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindSBIG.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindSBIG.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindSBIG.cmake	(revision 500)
@@ -0,0 +1,47 @@
+# - Try to find SBIG (Santa Barbara Instruments Group Library for CCDs & Filter Wheels).
+# Once done this will define
+#
+#  SBIG_FOUND - system has SBIG
+#  SBIG_LIBRARIES - Link these to use SBIG
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (SBIG_LIBRARIES)
+
+  # in cache already
+  set(SBIG_FOUND TRUE)
+  message(STATUS "Found SBIG: ${SBIG_LIBRARIES}")
+
+else (SBIG_LIBRARIES)
+
+  find_library(SBIG_LIBRARIES NAMES sbigudrv
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+ set(CMAKE_REQUIRED_LIBRARIES ${SBIG_LIBRARIES})
+
+   if(SBIG_LIBRARIES)
+    set(SBIG_FOUND TRUE)
+  else (SBIG_LIBRARIES)
+    set(SBIG_FOUND FALSE)
+  endif(SBIG_LIBRARIES)
+
+  if (SBIG_FOUND)
+    if (NOT SBIG_FIND_QUIETLY)
+      message(STATUS "Found SBIG: ${SBIG_LIBRARIES}")
+    endif (NOT SBIG_FIND_QUIETLY)
+  else (SBIG_FOUND)
+    if (SBIG_FIND_REQUIRED)
+      message(FATAL_ERROR "SBIG not found. Please install SBIG library. http://indi.sf.net")
+    endif (SBIG_FIND_REQUIRED)
+  endif (SBIG_FOUND)
+
+  mark_as_advanced(SBIG_LIBRARIES)
+  
+endif (SBIG_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindUSB.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindUSB.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindUSB.cmake	(revision 500)
@@ -0,0 +1,53 @@
+# - Try to find LIBUSB
+# Once done this will define
+#
+#  LIBUSB_FOUND - system has LIBUSB
+#  LIBUSB_INCLUDE_DIR - the LIBUSB include directory
+#  LIBUSB_LIBRARIES - Link these to use LIBUSB
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
+
+  # in cache already
+  set(LIBUSB_FOUND TRUE)
+  message(STATUS "Found LIBUSB: ${LIBUSB_LIBRARIES}")
+
+
+else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
+
+  find_path(LIBUSB_INCLUDE_DIR usb.h
+    ${_obIncDir}
+    ${GNUWIN32_DIR}/include
+  )
+
+  find_library(LIBUSB_LIBRARIES NAMES usb
+    PATHS
+    ${_obLinkDir}
+    ${GNUWIN32_DIR}/lib
+  )
+
+  if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
+    set(LIBUSB_FOUND TRUE)
+  else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
+    set(LIBUSB_FOUND FALSE)
+  endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
+
+
+  if (LIBUSB_FOUND)
+    if (NOT USB_FIND_QUIETLY)
+      message(STATUS "Found LIBUSB: ${LIBUSB_LIBRARIES}")
+    endif (NOT USB_FIND_QUIETLY)
+  else (LIBUSB_FOUND)
+    if (USB_FIND_REQUIRED)
+      message(FATAL_ERROR "LIBUSB not found. Please install libusb-devel and try again.")
+    endif (USB_FIND_REQUIRED)
+  endif (LIBUSB_FOUND)
+   
+mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
+
+endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
Index: /BAORadio/libindi/v1/cmake_modules/FindVorbis.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/FindVorbis.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/FindVorbis.cmake	(revision 500)
@@ -0,0 +1,32 @@
+# - Find vorbis
+# Find the native vorbis includes and libraries
+#
+#  VORBIS_INCLUDE_DIR - where to find vorbis.h, etc.
+#  VORBIS_LIBRARIES   - List of libraries when using vorbis(file).
+#  VORBIS_FOUND       - True if vorbis found.
+
+if(VORBIS_INCLUDE_DIR)
+    # Already in cache, be silent
+    set(VORBIS_FIND_QUIETLY TRUE)
+endif(VORBIS_INCLUDE_DIR)
+
+find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h)
+
+find_library(OGG_LIBRARY NAMES ogg)
+find_library(VORBIS_LIBRARY NAMES vorbis)
+find_library(VORBISFILE_LIBRARY NAMES vorbisfile)
+
+# Handle the QUIETLY and REQUIRED arguments and set VORBIS_FOUND to TRUE if
+# all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(VORBIS DEFAULT_MSG
+    VORBIS_INCLUDE_DIR OGG_LIBRARY VORBIS_LIBRARY VORBIS_LIBRARY)
+
+if(VORBIS_FOUND)
+  set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY})
+else(VORBIS_FOUND)
+  set(VORBIS_LIBRARIES)
+endif(VORBIS_FOUND)
+
+mark_as_advanced(VORBIS_INCLUDE_DIR)
+mark_as_advanced(OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY)
Index: /BAORadio/libindi/v1/cmake_modules/MacroBoolTo01.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/MacroBoolTo01.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/MacroBoolTo01.cmake	(revision 500)
@@ -0,0 +1,20 @@
+# MACRO_BOOL_TO_01( VAR RESULT0 ... RESULTN )
+# This macro evaluates its first argument
+# and sets all the given vaiables either to 0 or 1
+# depending on the value of the first one
+
+# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+MACRO(MACRO_BOOL_TO_01 FOUND_VAR )
+   FOREACH (_current_VAR ${ARGN})
+      IF(${FOUND_VAR})
+         SET(${_current_VAR} 1)
+      ELSE(${FOUND_VAR})
+         SET(${_current_VAR} 0)
+      ENDIF(${FOUND_VAR})
+   ENDFOREACH(_current_VAR)
+ENDMACRO(MACRO_BOOL_TO_01)
Index: /BAORadio/libindi/v1/cmake_modules/MacroLogFeature.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/MacroLogFeature.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/MacroLogFeature.cmake	(revision 500)
@@ -0,0 +1,125 @@
+# This file defines the Feature Logging macros.
+#
+# MACRO_LOG_FEATURE(VAR FEATURE DESCRIPTION URL [REQUIRED [MIN_VERSION [COMMENTS]]])
+#   Logs the information so that it can be displayed at the end
+#   of the configure run
+#   VAR : TRUE or FALSE, indicating whether the feature is supported
+#   FEATURE: name of the feature, e.g. "libjpeg"
+#   DESCRIPTION: description what this feature provides
+#   URL: home page
+#   REQUIRED: TRUE or FALSE, indicating whether the featue is required
+#   MIN_VERSION: minimum version number. empty string if unneeded
+#   COMMENTS: More info you may want to provide.  empty string if unnecessary
+#
+# MACRO_DISPLAY_FEATURE_LOG()
+#   Call this to display the collected results.
+#   Exits CMake with a FATAL error message if a required feature is missing
+#
+# Example:
+#
+# INCLUDE(MacroLogFeature)
+#
+# FIND_PACKAGE(JPEG)
+# MACRO_LOG_FEATURE(JPEG_FOUND "libjpeg" "Support JPEG images" "http://www.ijg.org" TRUE "3.2a" "")
+# ...
+# MACRO_DISPLAY_FEATURE_LOG()
+
+# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
+# Copyright (c) 2006, Allen Winter, <winter@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+IF (NOT _macroLogFeatureAlreadyIncluded)
+   SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
+   IF (EXISTS ${_file})
+      FILE(REMOVE ${_file})
+   ENDIF (EXISTS ${_file})
+
+   SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
+   IF (EXISTS ${_file})
+      FILE(REMOVE ${_file})
+   ENDIF (EXISTS ${_file})
+
+   SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
+   IF (EXISTS ${_file})
+      FILE(REMOVE ${_file})
+  ENDIF (EXISTS ${_file})
+
+  SET(_macroLogFeatureAlreadyIncluded TRUE)
+ENDIF (NOT _macroLogFeatureAlreadyIncluded)
+
+
+MACRO(MACRO_LOG_FEATURE _var _package _description _url ) # _required _minvers _comments)
+
+   SET(_required "${ARGV4}")
+   SET(_minvers "${ARGV5}")
+   SET(_comments "${ARGV6}")
+
+   IF (${_var})
+     SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
+   ELSE (${_var})
+     IF (${_required} MATCHES "[Tt][Rr][Uu][Ee]")
+       SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
+     ELSE (${_required} MATCHES "[Tt][Rr][Uu][Ee]")
+       SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
+     ENDIF (${_required} MATCHES "[Tt][Rr][Uu][Ee]")
+   ENDIF (${_var})
+
+   SET(_logtext "+ ${_package}")
+
+   IF (NOT ${_var})
+      IF (${_minvers} MATCHES ".*")
+        SET(_logtext "${_logtext}, ${_minvers}")
+      ENDIF (${_minvers} MATCHES ".*")
+      SET(_logtext "${_logtext}: ${_description} <${_url}>")
+      IF (${_comments} MATCHES ".*")
+        SET(_logtext "${_logtext}\n${_comments}")
+      ENDIF (${_comments} MATCHES ".*")
+#      SET(_logtext "${_logtext}\n") #double-space missing features?
+   ENDIF (NOT ${_var})
+   FILE(APPEND "${_LOGFILENAME}" "${_logtext}\n")
+ 
+ENDMACRO(MACRO_LOG_FEATURE)
+
+
+MACRO(MACRO_DISPLAY_FEATURE_LOG)
+
+   SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
+   IF (EXISTS ${_file})
+      FILE(READ ${_file} _requirements)
+      MESSAGE(STATUS "\n-----------------------------------------------------------------------------\n-- The following REQUIRED packages could NOT be located on your system.\n-- Please install them before continuing this software installation.\n-----------------------------------------------------------------------------\n${_requirements}-----------------------------------------------------------------------------")
+      FILE(REMOVE ${_file})
+      MESSAGE(FATAL_ERROR "Exiting: Missing Requirements")
+   ENDIF (EXISTS ${_file})
+
+   SET(_summary "\n")
+
+   SET(_elist 0)
+   SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
+   IF (EXISTS ${_file})
+      SET(_elist 1)
+      FILE(READ ${_file} _enabled)
+      FILE(REMOVE ${_file})
+      SET(_summary "${_summary}-----------------------------------------------------------------------------\n-- The following external packages were located on your system.\n-- This installation will have the extra features provided by these packages.\n${_enabled}")
+   ENDIF (EXISTS ${_file})
+
+   SET(_dlist 0)
+   SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
+   IF (EXISTS ${_file})
+      SET(_dlist 1)
+      FILE(READ ${_file} _disabled)
+      FILE(REMOVE ${_file})
+      SET(_summary "${_summary}-----------------------------------------------------------------------------\n-- The following OPTIONAL packages could NOT be located on your system.\n-- Consider installing them to enable more features from this software.\n${_disabled}")
+   ELSE (EXISTS ${_file})
+      IF (${_elist})
+        SET(_summary "${_summary}Congratulations! All external packages have been found.\n")
+      ENDIF (${_elist})
+   ENDIF (EXISTS ${_file})
+
+   IF (${_elist} OR ${_dlist})
+      SET(_summary "${_summary}-----------------------------------------------------------------------------\n")
+   ENDIF (${_elist} OR ${_dlist})
+   MESSAGE(STATUS "${_summary}")
+
+ENDMACRO(MACRO_DISPLAY_FEATURE_LOG)
Index: /BAORadio/libindi/v1/cmake_modules/MacroOptionalFindPackage.cmake
===================================================================
--- /BAORadio/libindi/v1/cmake_modules/MacroOptionalFindPackage.cmake	(revision 500)
+++ /BAORadio/libindi/v1/cmake_modules/MacroOptionalFindPackage.cmake	(revision 500)
@@ -0,0 +1,28 @@
+# - MACRO_OPTIONAL_FIND_PACKAGE() combines FIND_PACKAGE() with an OPTION()
+# MACRO_OPTIONAL_FIND_PACKAGE( <name> [QUIT] )
+# This macro is a combination of OPTION() and FIND_PACKAGE(), it
+# works like FIND_PACKAGE(), but additionally it automatically creates
+# an option name WITH_<name>, which can be disabled via the cmake GUI.
+# or via -DWITH_<name>=OFF
+# The standard <name>_FOUND variables can be used in the same way
+# as when using the normal FIND_PACKAGE()
+
+# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+MACRO (MACRO_OPTIONAL_FIND_PACKAGE _name )
+   OPTION(WITH_${_name} "Search for ${_name} package" ON)
+   if (WITH_${_name})
+      FIND_PACKAGE(${_name} ${ARGN})
+   else (WITH_${_name})
+      set(${_name}_FOUND)
+      set(${_name}_INCLUDE_DIR)
+      set(${_name}_INCLUDES)
+      set(${_name}_LIBRARY)
+      set(${_name}_LIBRARIES)
+   endif (WITH_${_name})
+ENDMACRO (MACRO_OPTIONAL_FIND_PACKAGE)
+
Index: /BAORadio/libindi/v1/config.h.cmake
===================================================================
--- /BAORadio/libindi/v1/config.h.cmake	(revision 500)
+++ /BAORadio/libindi/v1/config.h.cmake	(revision 500)
@@ -0,0 +1,14 @@
+/* Define to 1 if you have the <linux/videodev2.h> header file. */
+#cmakedefine HAVE_LINUX_VIDEODEV2_H 1
+
+/* The symbol timezone is an int, not a function */
+#define TIMEZONE_IS_INT 1
+
+/* Define if you have termios.h */
+#cmakedefine   HAVE_TERMIOS_H 1
+
+/* Define if you have fitsio.h */
+#cmakedefine   HAVE_CFITSIO_H 1
+
+/* Define if you have libnova.h */
+#cmakedefine   HAVE_NOVA_H 1
Index: /BAORadio/libindi/v1/debian/changelog
===================================================================
--- /BAORadio/libindi/v1/debian/changelog	(revision 500)
+++ /BAORadio/libindi/v1/debian/changelog	(revision 500)
@@ -0,0 +1,5 @@
+libindi (0.6) gutsy; urgency=low
+
+  * Initial release
+
+ -- Jasem Mutlaq <mutlaqja@ikarustech.com>  Fri, 3 Oct 2008 21:00:00 +0300
Index: /BAORadio/libindi/v1/debian/compat
===================================================================
--- /BAORadio/libindi/v1/debian/compat	(revision 500)
+++ /BAORadio/libindi/v1/debian/compat	(revision 500)
@@ -0,0 +1,1 @@
+5
Index: /BAORadio/libindi/v1/debian/control
===================================================================
--- /BAORadio/libindi/v1/debian/control	(revision 500)
+++ /BAORadio/libindi/v1/debian/control	(revision 500)
@@ -0,0 +1,16 @@
+Source: libindi
+Section: Development/Libraries
+Priority: extra
+Maintainer: Jasem Mutlaq <mutlaqja@ikarustech.com>
+Build-Depends: debhelper (>= 5)
+Standards-Version: 3.7.2
+
+Package: libindi0
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: INDI is an Instrument Neutral Distributed Interface control protocol for astronomical devices, which provides a framework that decouples low level hardware drivers from high level front end clients. Clients that use the device drivers are completely unaware of the device capabilities and communicate with the device drivers and build a completely dynamic GUI based on the services provided by the device.
+
+Package: libindi0-dev
+Architecture: any
+Depends: libindi0, ${shlibs:Depends}, ${misc:Depends}
+Description: Development headers for INDI Library
Index: /BAORadio/libindi/v1/debian/copyright
===================================================================
--- /BAORadio/libindi/v1/debian/copyright	(revision 500)
+++ /BAORadio/libindi/v1/debian/copyright	(revision 500)
@@ -0,0 +1,14 @@
+This package was debianized by Jasem Mutlaq <mutlaqja@ikarustech.com> on
+Fri, 21 Dec 2007 02:44:13 +0300.
+
+Copyright: 
+
+    <Elwood Downey (C) 2008>
+    <Jasem Mutlaq (C) 2008>
+
+License:
+
+    <LGPL>
+
+The Debian packaging is (C) 2008, Jasem Mutlaq <mutlaqja@ikarustech.com> and
+is licensed under the LGPL License.
Index: /BAORadio/libindi/v1/debian/libindi0-dev.dirs
===================================================================
--- /BAORadio/libindi/v1/debian/libindi0-dev.dirs	(revision 500)
+++ /BAORadio/libindi/v1/debian/libindi0-dev.dirs	(revision 500)
@@ -0,0 +1,1 @@
+usr/include/libindi
Index: /BAORadio/libindi/v1/debian/libindi0-dev.install
===================================================================
--- /BAORadio/libindi/v1/debian/libindi0-dev.install	(revision 500)
+++ /BAORadio/libindi/v1/debian/libindi0-dev.install	(revision 500)
@@ -0,0 +1,2 @@
+usr/include/libindi/*.h
+usr/lib/libindidriver.a
Index: /BAORadio/libindi/v1/debian/libindi0-dev.links
===================================================================
--- /BAORadio/libindi/v1/debian/libindi0-dev.links	(revision 500)
+++ /BAORadio/libindi/v1/debian/libindi0-dev.links	(revision 500)
@@ -0,0 +1,1 @@
+usr/lib/libindi.so.0 usr/lib/libindi.so
Index: /BAORadio/libindi/v1/debian/libindi0.dirs
===================================================================
--- /BAORadio/libindi/v1/debian/libindi0.dirs	(revision 500)
+++ /BAORadio/libindi/v1/debian/libindi0.dirs	(revision 500)
@@ -0,0 +1,3 @@
+usr/lib
+usr/bin
+usr/share/indi
Index: /BAORadio/libindi/v1/debian/libindi0.install
===================================================================
--- /BAORadio/libindi/v1/debian/libindi0.install	(revision 500)
+++ /BAORadio/libindi/v1/debian/libindi0.install	(revision 500)
@@ -0,0 +1,3 @@
+usr/lib/libindi.so.0.6
+usr/share/indi/drivers.xml
+usr/bin/indi*
Index: /BAORadio/libindi/v1/debian/libindi0.links
===================================================================
--- /BAORadio/libindi/v1/debian/libindi0.links	(revision 500)
+++ /BAORadio/libindi/v1/debian/libindi0.links	(revision 500)
@@ -0,0 +1,5 @@
+usr/bin/indi_lx200generic usr/bin/indi_lx200classic
+usr/bin/indi_lx200generic usr/bin/indi_lx200autostar
+usr/bin/indi_lx200generic usr/bin/indi_lx200_16
+usr/bin/indi_lx200generic usr/bin/indi_lx200gps
+usr/bin/indi_lx200generic usr/bin/indi_lx200ap
Index: /BAORadio/libindi/v1/debian/postinst.ex
===================================================================
--- /BAORadio/libindi/v1/debian/postinst.ex	(revision 500)
+++ /BAORadio/libindi/v1/debian/postinst.ex	(revision 500)
@@ -0,0 +1,41 @@
+#!/bin/sh
+# postinst script for apogee
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    configure)
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
+
+
Index: /BAORadio/libindi/v1/debian/rules
===================================================================
--- /BAORadio/libindi/v1/debian/rules	(revision 500)
+++ /BAORadio/libindi/v1/debian/rules	(revision 500)
@@ -0,0 +1,49 @@
+#!/usr/bin/make -f
+clean::
+	dh_testdir
+	dh_clean
+	rm -rf debian/tmp 
+
+d:=debian/tmp
+version:=0.6
+DEB_HOST_ARCH=$(shell /usr/bin/dpkg-architecture -qDEB_HOST_ARCH)
+
+build: 
+	mkdir -p $(d)
+	cmake -DCMAKE_INSTALL_PREFIX=$(d)/usr .
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k 
+	dh_installdirs
+	make install
+	ln -sf /usr/bin/indi_lx200generic $(d)/usr/bin/indi_lx200classic
+	ln -sf /usr/bin/indi_lx200generic $(d)/usr/bin/indi_lx200autostar
+	ln -sf /usr/bin/indi_lx200generic $(d)/usr/bin/indi_lx200_16
+	ln -sf /usr/bin/indi_lx200generic $(d)/usr/bin/indi_lx200gps
+	ln -sf /usr/bin/indi_lx200generic $(d)/usr/bin/indi_lx200ap
+
+binary-indep:
+	# nothing to do
+
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installdocs
+	dh_installchangelogs
+	dh_install -s --sourcedir=debian/tmp
+	dh_link -s
+	dh_compress
+	dh_fixperms
+	dh_makeshlibs
+	dh_installdeb
+	dh_gencontrol
+	dh_installdeb -s
+	dh_shlibdeps -s
+	dh_gencontrol -s
+	dh_md5sums -s
+	dh_builddeb -s
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary
Index: /BAORadio/libindi/v1/drivers.xml
===================================================================
--- /BAORadio/libindi/v1/drivers.xml	(revision 500)
+++ /BAORadio/libindi/v1/drivers.xml	(revision 500)
@@ -0,0 +1,138 @@
+<devGroup group="Telescopes">
+	<device label="LX200 Basic" focal_length="" aperture="">
+		<driver name="LX200 Basic">indi_lx200basic</driver>
+		<version>1.0</version>
+	</device>
+	<device label="BAO" focal_length="" aperture="">
+		<driver name="BAO">indi_BAO</driver>
+		<version>1.0</version>
+	</device>
+	<device label="LX200 Autostar" focal_length="" aperture="">
+		<driver name="LX200 Autostar">indi_lx200autostar</driver>
+		<version>2.0</version>
+	</device>
+	<device label="LX200 Classic" focal_length="" aperture="">
+		<driver name="LX200 Classic">indi_lx200classic</driver>
+		<version>1.0</version>
+	</device>
+	<device label="LX200 GPS" focal_length="" aperture="">
+		<driver name="LX200 GPS">indi_lx200gps</driver>
+		<version>2.0</version>
+	</device>
+	<device label="LX200 16" focal_length="4064" aperture="406.4">
+		<driver name="LX200 16">indi_lx200_16</driver>
+		<version>2.0</version>
+	</device>
+	<device label="LX90" focal_length="2000" aperture="203.2">
+		<driver name="LX200 Autostar">indi_lx200autostar</driver>
+		<version>2.0</version>
+	</device>
+	<device label="ETX125" focal_length="1900" aperture="127">
+		<driver name="LX200 Autostar">indi_lx200autostar</driver>
+		<version>2.0</version>
+	</device>
+	<device label="ETX105" focal_length="1470" aperture="105">
+		<driver name="LX200 Autostar">indi_lx200autostar</driver>
+		<version>2.0</version>
+	</device>
+	<device label="ETX90"  focal_length="1250" aperture="88.9">
+		<driver name="LX200 Autostar">indi_lx200autostar</driver>
+		<version>2.0</version>
+	</device>
+	<device label="LX200 Astro-Physics">
+		<driver name="LX200 Astro-Physics">indi_lx200ap</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Celestron GPS" focal_length="" aperture="">
+		<driver name="Celestron GPS">indi_celestron_gps</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Celestron NexStar" focal_length="" aperture="">
+		<driver name="Celestron GPS">indi_celestron_gps</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Astro-Electronic FS-2" focal_length="" aperture="">
+		<driver name="LX200 Basic">indi_lx200basic</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Orion Atlas" focal_length="" aperture="">
+		<driver name="Orion Atlas">indi_orion_atlas</driver>
+		<version>0.1</version>
+	</device>
+	<device label="Sky Scan" focal_length="" aperture="">
+		<driver name="Orion Atlas">indi_orion_atlas</driver>
+		<version>0.1</version>
+	</device>
+	<device label="Losmandy Gemini" focal_length="" aperture="">
+		<driver name="LX200 Basic">indi_lx200basic</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Mel Bartels" focal_length="" aperture="">
+		<driver name="LX200 Basic">indi_lx200basic</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Temma Takahashi" focal_length="" aperture="">
+		<driver name="Temma">indi_temma</driver>
+	  	<version>0.1</version>
+	</device>
+	<device label="Sky Commander" focal_length="" aperture="">
+		<driver name="Sky Commander">indi_skycommander</driver>
+		<version>0.1</version>
+	</device>
+	<device label="Argo Navis" focal_length="" aperture="">
+		<driver name="LX200 Basic">indi_lx200basic</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Intelliscope" focal_length="" aperture="">
+		<driver name="Intelliscope">indi_intelliscope</driver>
+		<version>0.2</version>
+	</device>
+	<device label="SkyWizard" focal_length="" aperture="">
+		<driver name="Intelliscope">indi_intelliscope</driver>
+		<version>0.2</version>
+	</device>
+</devGroup>
+<devGroup group="CCDs">
+	<device label="FLI CCD">
+		<driver name="FLI CCD">indi_fli_ccd</driver>
+		<version>1.0</version>
+	</device>
+</devGroup>
+<devGroup group="Focusers">
+	<device label="FLI PDF">
+		<driver name="FLI PDF">indi_fli_pdf</driver>
+		<version>0.1</version>
+	</device>
+	<device label="Robo Focus">
+		<driver name="Robofocus">indi_robofocus</driver>
+		<version>0.1</version>
+	</device>
+</devGroup>
+<devGroup group="Filter Wheels">
+  	<device label="FLI Wheel">
+		<driver name="FLI Wheel">indi_fli_wheel</driver>
+    		<version>0.9</version>
+    	</device>
+	<device label="TruTech Wheel">
+		<driver name="TruTech Wheel">indi_trutech_wheel</driver>
+		<version>0.1</version>
+    	</device>
+</devGroup>
+<devGroup group="Video">
+	<device label="Generic Video4Linux">
+		<driver name="Video4Linux Generic Device">indi_v4l_generic</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Philips Webcam">
+		<driver name="Video4Linux Generic Device">indi_v4l_philips</driver>
+		<version>1.0</version>
+	</device>
+	<device label="Meade LPI">
+		<driver name="Meade LPI">indi_meade_lpi</driver>
+		<version>0.1</version>
+	</device>
+	<device label="SBIG STV">
+		<driver name="STV Guider">indi_sbig_stv</driver>
+		<version>0.1</version>
+	</device>
+</devGroup>
Index: /BAORadio/libindi/v1/drivers/ccd/fli_ccd.c
===================================================================
--- /BAORadio/libindi/v1/drivers/ccd/fli_ccd.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/ccd/fli_ccd.c	(revision 500)
@@ -0,0 +1,1379 @@
+#if 0
+    FLI CCD
+    INDI Interface for Finger Lakes Instruments CCDs
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <zlib.h>
+
+#include <fitsio.h>
+
+#include <libfli.h>
+#include "indidevapi.h"
+#include "eventloop.h"
+#include "indicom.h"
+
+void ISInit(void);
+void getBasicData(void);
+void ISPoll(void *);
+void handleExposure(void *);
+void connectCCD(void);
+void getBasicData(void);
+void uploadFile(const char* filename);
+int  writeFITS(const char* filename, char errmsg[]);
+int  findcam(flidomain_t domain);
+int  setImageArea(char errmsg[]);
+int  manageDefaults(char errmsg[]);
+int  grabImage(void);
+int  checkPowerS(ISwitchVectorProperty *sp);
+int  checkPowerN(INumberVectorProperty *np);
+int  checkPowerT(ITextVectorProperty *tp);
+int  getOnSwitch(ISwitchVectorProperty *sp);
+int  isCCDConnected(void);
+void addFITSKeywords(fitsfile *fptr);
+
+double min(void);
+double max(void);
+
+extern char* me;
+extern int errno;
+
+#define mydev           "FLI CCD"
+
+#define COMM_GROUP	"Communication"
+#define EXPOSE_GROUP	"Expose"
+#define IMAGE_GROUP	"Image Settings"
+#define DATA_GROUP      "Data Channel"
+
+#define MAX_CCD_TEMP	45		/* Max CCD temperature */
+#define MIN_CCD_TEMP	-55		/* Min CCD temperature */
+#define MAX_X_BIN	16.		/* Max Horizontal binning */
+#define MAX_Y_BIN	16.		/* Max Vertical binning */
+#define MAX_PIXELS	4096		/* Max number of pixels in one dimension */
+#define POLLMS		1000		/* Polling time (ms) */
+#define TEMP_THRESHOLD  .25		/* Differential temperature threshold (C)*/
+#define NFLUSHES	1		/* Number of times a CCD array is flushed before an exposure */
+
+#define FILENAMESIZ	2048
+#define LIBVERSIZ 	1024
+#define PREFIXSIZ	64
+#define PIPEBUFSIZ	8192
+#define FRAME_ILEN	64
+#define TEMPFILE_LEN	16
+
+enum FLIFrames { LIGHT_FRAME = 0, BIAS_FRAME, DARK_FRAME, FLAT_FRAME };
+
+
+typedef struct {
+  flidomain_t domain;
+  char *dname;
+  char *name;
+  char *model;
+  long HWRevision;
+  long FWRevision;
+  double x_pixel_size;
+  double y_pixel_size;
+  long Array_Area[4];
+  long Visible_Area[4];
+  int width, height;
+  double temperature;
+} cam_t;
+
+typedef struct {
+int  width;
+int  height;
+int  frameType;
+int  expose;
+unsigned short  *img;
+} img_t;
+
+/*static int streamTimerID;		 Stream ID */
+
+static flidev_t fli_dev;
+static cam_t *FLICam;
+static img_t *FLIImg;
+static int portSwitchIndex;
+
+long int Domains[] = { FLIDOMAIN_USB, FLIDOMAIN_SERIAL, FLIDOMAIN_PARALLEL_PORT,  FLIDOMAIN_INET };
+
+/*INDI controls */
+
+/* Connect/Disconnect */
+static ISwitch ConnectS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty ConnectSP	= { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0};
+
+/* Types of Ports */
+static ISwitch PortS[]           	= {{"USB", "", ISS_ON, 0, 0}, {"Serial", "", ISS_OFF, 0, 0}, {"Parallel", "", ISS_OFF, 0, 0}, {"INet", "", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty PortSP	= { mydev, "Port Type", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PortS, NARRAY(PortS), "", 0};
+
+/* Types of Frames */
+static ISwitch FrameTypeS[]		= { {"FRAME_LIGHT", "Light", ISS_ON, 0, 0}, {"FRAME_BIAS", "Bias", ISS_OFF, 0, 0}, {"FRAME_DARK", "Dark", ISS_OFF, 0, 0}, {"FRAME_FLAT", "Flat Field", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty FrameTypeSP = { mydev, "CCD_FRAME_TYPE", "Frame Type", EXPOSE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FrameTypeS, NARRAY(FrameTypeS), "", 0};
+
+/* Frame coordinates. Full frame is default */
+static INumber FrameN[]          	= {
+ { "X", "X", "%.0f", 0.,     MAX_PIXELS, 1., 0., 0, 0, 0},
+ { "Y", "Y", "%.0f", 0.,     MAX_PIXELS, 1., 0., 0, 0, 0},
+ { "WIDTH", "Width", "%.0f", 0., MAX_PIXELS, 1., 0., 0, 0, 0},
+ { "HEIGHT", "Height", "%.0f",0., MAX_PIXELS, 1., 0., 0, 0, 0}};
+ static INumberVectorProperty FrameNP = { mydev, "CCD_FRAME", "Frame", IMAGE_GROUP, IP_RW, 60, IPS_IDLE, FrameN, NARRAY(FrameN), "", 0};
+ 
+ /* Binning */ 
+ static INumber BinningN[]       = {
+ { "HOR_BIN", "X", "%0.f", 1., MAX_X_BIN, 1., 1., 0, 0, 0},
+ { "VER_BIN", "Y", "%0.f", 1., MAX_Y_BIN, 1., 1., 0, 0, 0}};
+ static INumberVectorProperty BinningNP = { mydev, "CCD_BINNING", "Binning", IMAGE_GROUP, IP_RW, 60, IPS_IDLE, BinningN, NARRAY(BinningN), "", 0};
+ 
+ /* Exposure time */
+  static INumber ExposeTimeWN[]    = {{ "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., .5, 1., 0, 0, 0}};
+  static INumberVectorProperty ExposeTimeWNP = { mydev, "CCD_EXPOSURE_REQUEST", "Expose", EXPOSE_GROUP, IP_WO, 36000, IPS_IDLE, ExposeTimeWN, NARRAY(ExposeTimeWN), "", 0};
+
+  static INumber ExposeTimeRN[]    = {{ "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., .5, 1., 0, 0, 0}};
+  static INumberVectorProperty ExposeTimeRNP = { mydev, "CCD_EXPOSURE", "Expose", EXPOSE_GROUP, IP_RO, 36000, IPS_IDLE, ExposeTimeRN, NARRAY(ExposeTimeRN), "", 0};
+ 
+  /* Temperature control */
+ static INumber TemperatureN[]	  = { {"CCD_TEMPERATURE_VALUE", "Temperature", "%+06.2f", MIN_CCD_TEMP, MAX_CCD_TEMP, .2, 0., 0, 0, 0}};
+ static INumberVectorProperty TemperatureNP = { mydev, "CCD_TEMPERATURE", "Temperature (C)", EXPOSE_GROUP, IP_RW, 60, IPS_IDLE, TemperatureN, NARRAY(TemperatureN), "", 0};
+ 
+  /* Pixel size (Âµm) */
+static INumber PixelSizeN[] 	= {
+	{ "Width", "", "%.0f", 0. , 0., 0., 0., 0, 0, 0},
+	{ "Height", "", "%.0f", 0. , 0., 0., 0., 0, 0, 0}};
+static INumberVectorProperty PixelSizeNP = { mydev, "Pixel Size (Âµm)", "", DATA_GROUP, IP_RO, 0, IPS_IDLE, PixelSizeN, NARRAY(PixelSizeN), "", 0};
+
+/* BLOB for sending image */
+static IBLOB imageB = {"FITS_BLOB", "FITS", "", 0, 0, 0, 0, 0, 0, 0};
+static IBLOBVectorProperty imageBP = {mydev, "CCD_FITS_BLOB", "BLOB", COMM_GROUP,
+  IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0};
+
+/* send client definitions of all properties */
+void ISInit()
+{
+  static int isInit=0;
+
+ if (isInit)
+  return;
+ 
+ /* USB by default {USB, SERIAL, PARALLEL, INET} */
+ portSwitchIndex = 0;
+ 
+ FLIImg = malloc (sizeof(img_t));
+ 
+ if (FLIImg == NULL)
+ {
+   IDMessage(mydev, "Error: unable to initialize driver. Low memory.");
+   IDLog("Error: unable to initialize driver. Low memory.");
+   return;
+ }
+ 
+ IEAddTimer (POLLMS, ISPoll, NULL);
+
+ isInit = 1;
+ 
+}
+
+void ISGetProperties (const char *dev)
+{ 
+
+   ISInit();
+  
+  if (dev && strcmp (mydev, dev))
+    return;
+
+  /* COMM_GROUP */
+  IDDefSwitch(&ConnectSP, NULL);
+  IDDefSwitch(&PortSP, NULL);
+  IDDefBLOB(&imageBP, NULL);
+  
+  /* Expose */
+  IDDefSwitch(&FrameTypeSP, NULL);  
+  IDDefNumber(&ExposeTimeWNP, NULL);
+  IDDefNumber(&ExposeTimeRNP, NULL);
+  IDDefNumber(&TemperatureNP, NULL);
+  
+  /* Image Group */
+  IDDefNumber(&FrameNP, NULL);
+  IDDefNumber(&BinningNP, NULL);
+  
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
+void ISSnoopDevice (XMLEle *root) {}
+  
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	long err;
+	int i;
+	ISwitch *sp;
+	
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+	    
+	ISInit();
+
+	/* Port type */
+	if (!strcmp (name, PortSP.name))
+	{
+   	  PortSP.s = IPS_IDLE; 
+	  IUResetSwitch(&PortSP);
+	  IUUpdateSwitch(&PortSP, states, names, n);
+	  portSwitchIndex = getOnSwitch(&PortSP);
+	  
+	  PortSP.s = IPS_OK; 
+	  IDSetSwitch(&PortSP, NULL);
+	  return;
+	}
+	
+	/* Connection */
+	if (!strcmp (name, ConnectSP.name))
+	{
+	  if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0)
+		return;
+   	  connectCCD();
+	  return;
+	}
+	
+     /* Frame Type */
+     if (!strcmp(FrameTypeSP.name, name))
+     {
+       if (checkPowerS(&FrameTypeSP))
+         return;
+	 
+       for (i = 0; i < n ; i++)
+       {
+         sp = IUFindSwitch(&FrameTypeSP, names[i]);
+	 
+	 if (!sp)
+	 {
+	      FrameTypeSP.s = IPS_ALERT;
+	      IDSetSwitch(&FrameTypeSP, "Unknown error. %s is not a member of %s property.", names[0], name);
+	      return;
+	 }
+	 
+	 /* NORMAL, BIAS, or FLAT */
+	 if ( (sp == &FrameTypeS[LIGHT_FRAME] || sp == &FrameTypeS[FLAT_FRAME]) && states[i] == ISS_ON)
+	 {
+	   if (sp == &FrameTypeS[LIGHT_FRAME])
+	     FLIImg->frameType = LIGHT_FRAME;
+  	   else
+	     FLIImg->frameType = FLAT_FRAME;
+	   
+	   if ((err = FLISetFrameType(fli_dev, FLI_FRAME_TYPE_NORMAL) ))
+  	   {
+	    IUResetSwitch(&FrameTypeSP);
+	    FrameTypeS[LIGHT_FRAME].s = ISS_ON;
+	    FrameTypeSP.s = IPS_ALERT;
+            IDSetSwitch(&FrameTypeSP, "FLISetFrameType() failed. %s.\n", strerror((int)-err));
+	    IDLog("FLISetFrameType() failed. %s.\n", strerror((int)-err));
+	    return;
+	   }
+	  
+	   IUResetSwitch(&FrameTypeSP);
+	   sp->s = ISS_ON; 
+	   FrameTypeSP.s = IPS_OK;
+	   IDSetSwitch(&FrameTypeSP, NULL);
+	   break;
+	 }
+	 /* DARK AND BIAS */
+	 else if ( (sp == &FrameTypeS[DARK_FRAME] || sp == &FrameTypeS[BIAS_FRAME]) && states[i] == ISS_ON)
+	 {
+	   
+	  if (sp == &FrameTypeS[DARK_FRAME])
+	     FLIImg->frameType = DARK_FRAME;
+	  else
+	     FLIImg->frameType = BIAS_FRAME;
+	   
+	   if ((err = FLISetFrameType(fli_dev, FLI_FRAME_TYPE_DARK) ))
+  	   {
+	    IUResetSwitch(&FrameTypeSP);
+	    FrameTypeS[LIGHT_FRAME].s = ISS_ON;
+	    FrameTypeSP.s = IPS_ALERT;
+            IDSetSwitch(&FrameTypeSP, "FLISetFrameType() failed. %s.\n", strerror((int)-err));
+	    IDLog("FLISetFrameType() failed. %s.\n", strerror((int)-err));
+	    return;
+	   }
+	   
+	   IUResetSwitch(&FrameTypeSP);
+	   sp->s = ISS_ON;
+	   FrameTypeSP.s = IPS_OK;
+	   IDSetSwitch(&FrameTypeSP, NULL);
+	   break;
+	 }
+	   
+  	} /* For loop */
+	
+	return;
+     }
+     
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	ISInit();
+ 
+       /* ignore if not ours */ 
+       if (dev && strcmp (mydev, dev))
+         return;
+
+	/* suppress warning */
+	n=n; dev=dev; name=name; names=names; texts=texts;
+	
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+      long err;
+      int i;
+      INumber *np;
+      char errmsg[ERRMSG_SIZE];
+
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+	    
+	ISInit();
+	
+    /* Exposure time */
+    if (!strcmp (ExposeTimeWNP.name, name))
+    {
+       if (checkPowerN(&ExposeTimeWNP))
+         return;
+
+       if (ExposeTimeWNP.s == IPS_BUSY)
+       {
+          if ( (err = FLICancelExposure(fli_dev)))
+	  {
+	    	ExposeTimeWNP.s = IPS_ALERT;
+	    	IDSetNumber(&ExposeTimeWNP, "FLICancelExposure() failed. %s.", strerror((int)-err));
+	    	IDLog("FLICancelExposure() failed. %s.\n", strerror((int)-err));
+	    	return;
+	  }
+	
+	  ExposeTimeWNP.s = IPS_IDLE;
+	  ExposeTimeRNP.s = IPS_IDLE;
+	  ExposeTimeRN[0].value = 0;
+
+	  IDSetNumber(&ExposeTimeWNP, "Exposure cancelled.");
+	  IDSetNumber(&ExposeTimeRNP, NULL);
+	  IDLog("Exposure Cancelled.\n");
+	  return;
+        }
+    
+       np = IUFindNumber(&ExposeTimeWNP, names[0]);
+	 
+       if (!np)
+       {
+	   ExposeTimeWNP.s = IPS_ALERT;
+	   IDSetNumber(&ExposeTimeWNP, "Error: %s is not a member of %s property.", names[0], name);
+	   return;
+       }
+	 
+        np->value = values[0];
+	FLIImg->expose = (int) (values[0] * 1000.);
+	
+      /* Set duration */  
+     if ( (err = FLISetExposureTime(fli_dev, np->value * 1000.) ))
+     {
+       ExposeTimeWNP.s = IPS_ALERT;
+       IDSetNumber(&ExposeTimeWNP, "FLISetExposureTime() failed. %s.\n", strerror((int)-err));
+       IDLog("FLISetExposureTime() failed. %s.\n", strerror((int)-err));
+       return;
+     }
+      
+      IDLog("Exposure Time (ms) is: %g\n", np->value * 1000.);
+      
+      handleExposure(NULL);
+      return;
+    } 
+    
+    
+  if (!strcmp(TemperatureNP.name, name))
+  {
+    if (checkPowerN(&TemperatureNP))
+      return;
+      
+    TemperatureNP.s = IPS_IDLE;
+    
+    np = IUFindNumber(&TemperatureNP, names[0]);
+    
+    if (!np)
+    {
+    IDSetNumber(&TemperatureNP, "Unknown error. %s is not a member of %s property.", names[0], name);
+    return;
+    }
+    
+    if (values[0] < MIN_CCD_TEMP || values[0] > MAX_CCD_TEMP)
+    {
+      IDSetNumber(&TemperatureNP, "Error: valid range of temperature is from %d to %d", MIN_CCD_TEMP, MAX_CCD_TEMP);
+      return;
+    }
+    
+    if ( (err = FLISetTemperature(fli_dev, values[0])))
+    {
+      IDSetNumber(&TemperatureNP, "FLISetTemperature() failed. %s.", strerror((int)-err));
+      IDLog("FLISetTemperature() failed. %s.", strerror((int)-err));
+      return;
+    }
+    
+    FLICam->temperature = values[0];
+    TemperatureNP.s = IPS_BUSY;
+    
+    IDSetNumber(&TemperatureNP, "Setting CCD temperature to %+06.2f C", values[0]);
+    IDLog("Setting CCD temperature to %+06.2f C\n", values[0]);
+    return;
+   }
+   
+   if (!strcmp(FrameNP.name, name))
+   {
+     int nset=0;
+     
+     if (checkPowerN(&FrameNP))
+      return;
+      
+     FrameNP.s = IPS_IDLE;
+     
+     for (i=0; i < n ; i++)
+     {
+       np = IUFindNumber(&FrameNP, names[i]);
+       
+      if (!np)
+      {
+       IDSetNumber(&FrameNP, "Unknown error. %s is not a member of %s property.", names[0], name);
+       return;
+      }
+      
+      /* X or Width */
+      if (np == &FrameN[0] || np==&FrameN[2])
+      {
+        if (values[i] < 0 || values[i] > FLICam->width)
+	 break;
+	 
+	nset++;
+	np->value = values[i];
+      }
+      /* Y or height */
+      else if (np == &FrameN[1] || np==&FrameN[3])
+      {
+       if (values[i] < 0 || values[i] > FLICam->height)
+	 break;
+	 
+	nset++;
+	np->value = values[i];
+      }
+     }
+      
+      if (nset < 4)
+      {
+        IDSetNumber(&FrameNP, "Invalid range. Valid range is (0,0) - (%0d,%0d)", FLICam->width, FLICam->height);
+	IDLog("Invalid range. Valid range is (0,0) - (%0d,%0d)", FLICam->width, FLICam->height);
+	return; 
+      }
+      
+      if (setImageArea(errmsg))
+      {
+        IDSetNumber(&FrameNP, "%s", errmsg);
+	return;
+      }
+      	    
+      FrameNP.s = IPS_OK;
+      
+      /* Adjusting image width and height */ 
+      FLIImg->width  = FrameN[2].value;
+      FLIImg->height = FrameN[3].value;
+      
+      IDSetNumber(&FrameNP, NULL);
+      
+   } /* end FrameNP */
+      
+    
+   if (!strcmp(BinningNP.name, name))
+   {
+     if (checkPowerN(&BinningNP))
+       return;
+       
+     BinningNP.s = IPS_IDLE;
+     
+     for (i=0 ; i < n ; i++)
+     {
+       np = IUFindNumber(&BinningNP, names[i]);
+       
+      if (!np)
+      {
+       IDSetNumber(&BinningNP, "Unknown error. %s is not a member of %s property.", names[0], name);
+       return;
+      }
+      
+      /* X binning */
+      if (np == &BinningN[0])
+      {
+        if (values[i] < 1 || values[i] > MAX_X_BIN)
+	{
+	  IDSetNumber(&BinningNP, "Error: Valid X bin values are from 1 to %g", MAX_X_BIN);
+	  IDLog("Error: Valid X bin values are from 1 to %g", MAX_X_BIN);
+	  return;
+	}
+	
+	if ( (err = FLISetHBin(fli_dev, values[i])))
+	{
+	  IDSetNumber(&BinningNP, "FLISetHBin() failed. %s.", strerror((int)-err));
+	  IDLog("FLISetHBin() failed. %s.", strerror((int)-err));
+	  return;
+	}
+	
+	np->value = values[i];
+      }
+      else if (np == &BinningN[1])
+      {
+        if (values[i] < 1 || values[i] > MAX_Y_BIN)
+	{
+	  IDSetNumber(&BinningNP, "Error: Valid Y bin values are from 1 to %g", MAX_Y_BIN);
+	  IDLog("Error: Valid X bin values are from 1 to %g", MAX_Y_BIN);
+	  return;
+	}
+	
+	if ( (err = FLISetVBin(fli_dev, values[i])))
+	{
+	  IDSetNumber(&BinningNP, "FLISetVBin() failed. %s.", strerror((int)-err));
+	  IDLog("FLISetVBin() failed. %s.", strerror((int)-err));
+	  return;
+	}
+	
+	np->value = values[i];
+      }
+     } /* end for */
+     
+     if (setImageArea(errmsg))
+     {
+       IDSetNumber(&BinningNP, errmsg, NULL);
+       IDLog("%s", errmsg);
+       return;
+     }
+     
+     BinningNP.s = IPS_OK;
+     
+     IDLog("Binning is: %.0f x %.0f\n", BinningN[0].value, BinningN[1].value);
+     
+     IDSetNumber(&BinningNP, NULL);
+     return;
+   }
+	
+}
+
+
+void ISPoll(void *p)
+{
+	long err;
+	long timeleft;
+	double ccdTemp;
+	
+	if (!isCCDConnected())
+	{
+	 IEAddTimer (POLLMS, ISPoll, NULL);
+	 return;
+	}
+	 
+        /*IDLog("In Poll.\n");*/
+	
+	switch (ExposeTimeWNP.s)
+	{
+	  case IPS_IDLE:
+	    break;
+	    
+	  case IPS_OK:
+	    break;
+	    
+	  case IPS_BUSY:
+	    if ( (err = FLIGetExposureStatus(fli_dev, &timeleft)))
+	    { 
+	      ExposeTimeWNP.s = IPS_ALERT; 
+	      ExposeTimeRN[0].value = 0;
+	      
+	      IDSetNumber(&ExposeTimeWNP, "FLIGetExposureStatus() failed. %s.", strerror((int)-err));
+	      IDSetNumber(&ExposeTimeRNP, NULL);
+	      IDLog("FLIGetExposureStatus() failed. %s.\n", strerror((int)-err));
+	      break;
+	    }
+	    
+	    if (timeleft > 0)
+	    {
+	      ExposeTimeRN[0].value = timeleft / 1000.;
+	      IDSetNumber(&ExposeTimeRNP, NULL); 
+	      break;
+	    }
+
+	    /* We're done exposing */
+	    /*ExposeTimeWNP.s = IPS_OK;*/
+	    ExposeTimeRNP.s = IPS_OK;  
+	    ExposeTimeRN[0].value = 0;
+	    IDSetNumber(&ExposeTimeWNP, "Exposure done, downloading image...");
+	    IDSetNumber(&ExposeTimeRNP, NULL);
+	    IDLog("Exposure done, downloading image...\n");
+
+	    /* grab and save image */
+	     grabImage();
+
+	    break;
+	    
+	  case IPS_ALERT:
+	    break;
+	 }
+	 
+	 switch (TemperatureNP.s)
+	 {
+	   case IPS_IDLE:
+	   case IPS_OK:
+	     if ( (err = FLIGetTemperature(fli_dev, &ccdTemp)))
+	     {
+	       TemperatureNP.s = IPS_IDLE;
+	       IDSetNumber(&TemperatureNP, "FLIGetTemperature() failed. %s.", strerror((int)-err));
+	       IDLog("FLIGetTemperature() failed. %s.", strerror((int)-err));
+	       return;
+	     }
+	     
+	     if (fabs(TemperatureN[0].value - ccdTemp) >= TEMP_THRESHOLD)
+	     {
+	       TemperatureN[0].value = ccdTemp;
+	       IDSetNumber(&TemperatureNP, NULL);
+	     }
+	     break;
+	     
+	   case IPS_BUSY:
+	   if ((err = FLIGetTemperature(fli_dev, &ccdTemp)))
+	     {
+	       TemperatureNP.s = IPS_ALERT;
+	       IDSetNumber(&TemperatureNP, "FLIGetTemperature() failed. %s.", strerror((int)-err));
+	       IDLog("FLIGetTemperature() failed. %s.", strerror((int)-err));
+	       return;
+	     }
+	     
+	     if (fabs(FLICam->temperature - ccdTemp) <= TEMP_THRESHOLD)
+	       TemperatureNP.s = IPS_OK;
+	     	       
+              TemperatureN[0].value = ccdTemp;
+	      IDSetNumber(&TemperatureNP, NULL);
+	      break;
+	      
+	    case IPS_ALERT:
+	     break;
+	  }
+  	 
+	 p=p; 
+ 	
+	 IEAddTimer (POLLMS, ISPoll, NULL);
+}
+
+/* Sets the Image area that the CCD will scan and download.
+   We compensate for binning. */
+int setImageArea(char errmsg[])
+{
+  
+   long x_1, y_1, x_2, y_2;
+   long err;
+   
+   /* Add the X and Y offsets */
+   x_1 = FrameN[0].value + FLICam->Visible_Area[0];
+   y_1 = FrameN[1].value + FLICam->Visible_Area[1];
+   
+   x_2 = x_1 + (FrameN[2].value / BinningN[0].value);
+   y_2 = y_1 + (FrameN[3].value / BinningN[1].value);
+   
+   if (x_2 > FLICam->Visible_Area[2])
+     x_2 = FLICam->Visible_Area[2];
+   
+   if (y_2 > FLICam->Visible_Area[3])
+     y_2 = FLICam->Visible_Area[3];
+     
+   IDLog("The Final image area is (%ld, %ld), (%ld, %ld)\n", x_1, y_1, x_2, y_2);
+   
+   FLIImg->width  = x_2 - x_1;
+   FLIImg->height = y_2 - y_1;
+   
+   if ( (err = FLISetImageArea(fli_dev, x_1, y_1, x_2, y_2) ))
+   {
+     snprintf(errmsg, ERRMSG_SIZE, "FLISetImageArea() failed. %s.\n", strerror((int)-err));
+     IDLog("%s", errmsg);
+     return -1;
+   }
+   
+   return 0;
+}
+
+/* Downloads the image from the CCD row by row and store them
+   in a raw file.
+ N.B. No processing is done on the image */
+int grabImage()
+{
+	long err;
+	int img_size,i, fd;
+	char errmsg[ERRMSG_SIZE];
+	char filename[TEMPFILE_LEN] = "/tmp/fitsXXXXXX";
+  
+	if ((fd = mkstemp(filename)) < 0)
+	{ 
+		IDMessage(mydev, "Error making temporary filename.");
+		IDLog("Error making temporary filename.\n");
+		return -1;
+	}
+	close(fd);
+     
+	img_size = FLIImg->width * FLIImg->height * sizeof(unsigned short);
+	
+	FLIImg->img = malloc (img_size);
+  
+	if (FLIImg->img == NULL)
+	{
+		IDMessage(mydev, "Not enough memory to store image.");
+		IDLog("Not enough memory to store image.\n");
+		return -1;
+	}
+  
+	for (i=0; i < FLIImg->height ; i++)
+	{
+		if ( (err = FLIGrabRow(fli_dev, &FLIImg->img[i * FLIImg->width], FLIImg->width)))
+		{
+			free(FLIImg->img);
+			IDMessage(mydev, "FLIGrabRow() failed at row %d. %s.", i, strerror((int)-err));
+			IDLog("FLIGrabRow() failed at row %d. %s.\n", i, strerror((int)-err));
+			return -1;
+		}
+	}
+  
+	IDMessage(mydev, "Download complete.\n");
+	
+	/*err = (ImageFormatS[0].s == ISS_ON) ? writeFITS(FileNameT[0].text, errmsg) : writeRAW(FileNameT[0].text, errmsg);*/
+	err = writeFITS(filename, errmsg);
+   
+	if (err)
+	{
+		free(FLIImg->img);
+		IDMessage(mydev, errmsg, NULL);
+		return -1;
+	}
+
+	free(FLIImg->img);
+	return 0;
+ 
+}
+
+int writeFITS(const char* filename, char errmsg[])
+{
+  fitsfile *fptr;       /* pointer to the FITS file; defined in fitsio.h */
+  int status;
+  long  fpixel = 1, naxis = 2, nelements;
+  long naxes[2];
+  char filename_rw[TEMPFILE_LEN+1];
+
+  naxes[0] = FLIImg->width;
+  naxes[1] = FLIImg->height;
+
+  /* Append ! to file name to over write it.*/
+  snprintf(filename_rw, TEMPFILE_LEN+1, "!%s", filename);
+
+  status = 0;         /* initialize status before calling fitsio routines */
+  fits_create_file(&fptr, filename_rw, &status);   /* create new file */
+
+  /* Create the primary array image (16-bit short integer pixels */
+  fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status);
+
+  addFITSKeywords(fptr);
+
+  nelements = naxes[0] * naxes[1];          /* number of pixels to write */
+
+  /* Write the array of integers to the image */
+  fits_write_img(fptr, TUSHORT, fpixel, nelements, FLIImg->img, &status);
+
+  fits_close_file(fptr, &status);            /* close the file */
+
+  fits_report_error(stderr, status);  /* print out any error messages */
+
+  /* Success */
+  ExposeTimeWNP.s = IPS_OK;
+  IDSetNumber(&ExposeTimeWNP, NULL);
+  uploadFile(filename);
+  unlink(filename);
+ 
+  return status;
+}
+
+void addFITSKeywords(fitsfile *fptr)
+{
+  int status=0; 
+  char binning_s[32];
+  char frame_s[32];
+  double min_val, max_val;
+  
+  /*pixel_size = (float) PixelSizeN[0].value;
+  min_val = min();
+  max_val = max();
+  temp    = (float) TemperatureN[0].value;
+  expose  = (float) FLIImg->expose;*/
+
+  snprintf(binning_s, 32, "(%g x %g)", BinningN[0].value, BinningN[1].value);
+
+  switch (FLIImg->frameType)
+  {
+    case LIGHT_FRAME:
+      	strcpy(frame_s, "Light");
+	break;
+    case BIAS_FRAME:
+        strcpy(frame_s, "Bias");
+	break;
+    case FLAT_FRAME:
+        strcpy(frame_s, "Flat Field");
+	break;
+    case DARK_FRAME:
+        strcpy(frame_s, "Dark");
+	break;
+  }
+
+  fits_update_key(fptr, TDOUBLE, "CCD-TEMP", &(TemperatureN[0].value), "CCD Temperature (Celcius)", &status);
+  fits_update_key(fptr, TDOUBLE, "EXPOSURE", &(FLIImg->expose), "Total Exposure Time (ms)", &status); 
+  fits_update_key(fptr, TDOUBLE, "PIX-SIZ", &(PixelSizeN[0].value), "Pixel Size (microns)", &status);
+  fits_update_key(fptr, TSTRING, "BINNING", binning_s, "Binning HOR x VER", &status);
+  fits_update_key(fptr, TSTRING, "FRAME", frame_s, "Frame Type", &status);
+  fits_update_key(fptr, TDOUBLE, "DATAMIN", &min_val, "Minimum value", &status);
+  fits_update_key(fptr, TDOUBLE, "DATAMAX", &max_val, "Maximum value", &status);
+  fits_update_key(fptr, TSTRING, "INSTRUME", "Finger Lakes Instruments", "CCD Name", &status);
+  fits_write_date(fptr, &status);
+
+}
+
+void uploadFile(const char* filename)
+{
+   FILE * fitsFile;
+   unsigned char *fitsData, *compressedData;
+   int r=0;
+   unsigned int i =0, nr = 0;
+   uLongf compressedBytes=0;
+   uLong  totalBytes;
+   struct stat stat_p; 
+ 
+   if ( -1 ==  stat (filename, &stat_p))
+   { 
+     IDLog(" Error occurred attempting to stat file.\n"); 
+     return; 
+   }
+   
+   totalBytes     = stat_p.st_size;
+   fitsData       = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes);
+   compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
+   
+   if (fitsData == NULL || compressedData == NULL)
+   {
+     if (fitsData) free(fitsData);
+     if (compressedData) free(compressedData);
+     IDLog("Error! low memory. Unable to initialize fits buffers.\n");
+     return;
+   }
+   
+   fitsFile = fopen(filename, "r");
+   
+   if (fitsFile == NULL)
+    return;
+   
+   /* #1 Read file from disk */ 
+   for (i=0; i < totalBytes; i+= nr)
+   {
+      nr = fread(fitsData + i, 1, totalBytes - i, fitsFile);
+     
+     if (nr <= 0)
+     {
+        IDLog("Error reading temporary FITS file.\n");
+        return;
+     }
+   }
+   fclose(fitsFile);
+   
+   compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
+    
+   /* #2 Compress it */ 
+   r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9);
+   if (r != Z_OK)
+   {
+ 	/* this should NEVER happen */
+ 	IDLog("internal error - compression failed: %d\n", r);
+	return;
+   }
+   
+   /* #3 Send it */
+   imageB.blob = compressedData;
+   imageB.bloblen = compressedBytes;
+   imageB.size = totalBytes;
+   strcpy(imageB.format, ".fits.z");
+   imageBP.s = IPS_OK;
+   IDSetBLOB (&imageBP, NULL);
+   
+   free (fitsData);   
+   free (compressedData);
+   
+}
+
+/* Initiates the exposure procedure */
+void handleExposure(void *p)
+{
+  long err;
+  
+  /* no warning */
+  p=p;
+  
+  /* BIAS frame is the same as DARK but with minimum period. i.e. readout from camera electronics.
+  */
+  if (FLIImg->frameType == BIAS_FRAME)
+  {
+     if ((err = FLISetExposureTime(fli_dev, 50)))
+     {
+       ExposeTimeWNP.s = IPS_ALERT;
+       IDSetNumber(&ExposeTimeWNP, "FLISetExposureTime() failed. %s.\n", strerror((int)-err));
+       IDLog("FLISetExposureTime() failed. %s.\n", strerror((int)-err));
+       return;
+     }
+   }
+    
+  if ((err = FLIExposeFrame(fli_dev)))
+  {
+    	ExposeTimeWNP.s = IPS_ALERT;
+    	IDSetNumber(&ExposeTimeWNP, "FLIExposeFrame() failed. %s.", strerror((int)-err));
+    	IDLog("FLIExposeFrame() failed. %s.\n", strerror((int)-err));
+    	return;
+  }
+ 
+   ExposeTimeWNP.s = IPS_BUSY;
+		  
+   IDSetNumber(&ExposeTimeWNP, "Taking a %g seconds frame...", FLIImg->expose / 1000.);
+   
+   IDLog("Taking a frame...\n");
+}
+
+/* Retrieves basic data from the CCD upon connection like temperature, array size, firmware..etc */
+void getBasicData()
+{
+
+  char buff[2048];
+  long err;
+
+  IDLog("In getBasicData()\n");
+  
+  if ((err = FLIGetModel (fli_dev, buff, 2048)))
+  {
+    IDMessage(mydev, "FLIGetModel() failed. %s.", strerror((int)-err));
+    IDLog("FLIGetModel() failed. %s.\n", strerror((int)-err));
+    return;
+  }
+  else
+  {
+    if ( (FLICam->model = malloc (sizeof(char) * 2048)) == NULL)
+    {
+      IDMessage(mydev, "malloc() failed.");
+      IDLog("malloc() failed.");
+      return;
+    }
+    
+    strcpy(FLICam->model, buff);
+  }
+  
+  if (( err = FLIGetHWRevision(fli_dev, &FLICam->HWRevision)))
+  {
+    IDMessage(mydev, "FLIGetHWRevision() failed. %s.", strerror((int)-err));
+    IDLog("FLIGetHWRevision() failed. %s.\n", strerror((int)-err));
+    
+    return;
+  }
+  
+  if (( err = FLIGetFWRevision(fli_dev, &FLICam->FWRevision)))
+  {
+    IDMessage(mydev, "FLIGetFWRevision() failed. %s.", strerror((int)-err));
+    IDLog("FLIGetFWRevision() failed. %s.\n", strerror((int)-err));
+    return;
+  }
+
+  if (( err = FLIGetPixelSize(fli_dev, &FLICam->x_pixel_size, &FLICam->y_pixel_size)))
+  {
+    IDMessage(mydev, "FLIGetPixelSize() failed. %s.", strerror((int)-err));
+    IDLog("FLIGetPixelSize() failed. %s.\n", strerror((int)-err));
+    return;
+  }
+  
+  FLICam->x_pixel_size *= 1e6;
+  FLICam->y_pixel_size *= 1e6; 
+  
+  if (( err = FLIGetArrayArea(fli_dev, &FLICam->Array_Area[0], &FLICam->Array_Area[1], &FLICam->Array_Area[2], &FLICam->Array_Area[3])))
+  {
+    IDMessage(mydev, "FLIGetArrayArea() failed. %s.", strerror((int)-err));
+    IDLog("FLIGetArrayArea() failed. %s.\n", strerror((int)-err));
+    return;
+  }
+  
+  if (( err = FLIGetVisibleArea( fli_dev, &FLICam->Visible_Area[0], &FLICam->Visible_Area[1], &FLICam->Visible_Area[2], &FLICam->Visible_Area[3])))
+  {
+    IDMessage(mydev, "FLIGetVisibleArea() failed. %s.", strerror((int)-err));
+    IDLog("FLIGetVisibleArea() failed. %s.\n", strerror((int)-err));
+  }
+  
+  if (( err = FLIGetTemperature(fli_dev, &FLICam->temperature)))
+  {
+    IDMessage(mydev, "FLIGetTemperature() failed. %s.", strerror((int)-err));
+    IDLog("FLIGetTemperature() failed. %s.\n", strerror((int)-err));
+    return;
+  }
+  
+  IDLog("The CCD Temperature is %f.\n", FLICam->temperature);
+  
+  PixelSizeN[0].value  = FLICam->x_pixel_size;				/* Pixel width (um) */
+  PixelSizeN[1].value  = FLICam->y_pixel_size;				/* Pixel height (um) */
+  TemperatureN[0].value = FLICam->temperature;				/* CCD chip temperatre (degrees C) */
+  FrameN[0].value = 0;							/* X */
+  FrameN[1].value = 0;							/* Y */
+  FrameN[2].value = FLICam->Visible_Area[2] - FLICam->Visible_Area[0];	/* Frame Width */
+  FrameN[3].value = FLICam->Visible_Area[3] - FLICam->Visible_Area[1];	/* Frame Height */
+  
+  FLICam->width  = FLIImg->width = FrameN[2].value;
+  FLICam->height = FLIImg->width = FrameN[3].value;
+  
+  BinningN[0].value = BinningN[1].value = 1;
+  
+  IDLog("The Camera Width is %d ---- %d\n", (int) FLICam->width, (int) FrameN[2].value);
+  IDLog("The Camera Height is %d ---- %d\n", (int) FLICam->height, (int) FrameN[3].value);
+  
+  IDSetNumber(&PixelSizeNP, NULL);
+  IDSetNumber(&TemperatureNP, NULL);
+  IDSetNumber(&FrameNP, NULL);
+  IDSetNumber(&BinningNP, NULL);
+  
+  IDLog("Exiting getBasicData()\n");
+  
+}
+
+int manageDefaults(char errmsg[])
+{
+  long err;
+  /*int exposeTimeMS;
+  
+  exposeTimeMS = (int) (ExposeTimeWN[0].value * 1000.);
+  
+  IDLog("Setting default exposure time of %d ms.\n", exposeTimeMS);
+  if ( (err = FLISetExposureTime(fli_dev, exposeTimeMS) ))
+  {
+    snprintf(errmsg, ERRMSG_SIZE, "FLISetExposureTime() failed. %s.\n", strerror((int)-err));
+    IDLog(errmsg, NULL);
+    return -1;
+  }*/
+  
+  /* Default frame type is NORMAL */
+  if ( (err = FLISetFrameType(fli_dev, FLI_FRAME_TYPE_NORMAL) ))
+  {
+    snprintf(errmsg, ERRMSG_SIZE, "FLISetFrameType() failed. %s.\n", strerror((int)-err));
+    IDLog(errmsg, NULL);
+    return -1;
+  }
+  
+  /* X horizontal binning */
+  if ( (err = FLISetHBin(fli_dev, BinningN[0].value) ))
+  {
+    snprintf(errmsg, ERRMSG_SIZE, "FLISetBin() failed. %s.\n", strerror((int)-err));
+    IDLog(errmsg, NULL);
+    return -1;
+  }
+  
+  /* Y vertical binning */
+  if ( (err = FLISetVBin(fli_dev, BinningN[1].value) ))
+  {
+    snprintf(errmsg, ERRMSG_SIZE, "FLISetVBin() failed. %s.\n", strerror((int)-err));
+    IDLog(errmsg, NULL);
+    return -1;
+  }
+  
+  IDLog("Setting default binning %f x %f.\n", BinningN[0].value, BinningN[1].value);
+  
+  FLISetNFlushes(fli_dev, NFLUSHES);
+  
+  /* Set image area */
+  if (setImageArea(errmsg))
+    return -1;
+  
+  /* Success */
+  return 0;
+    
+}
+
+int getOnSwitch(ISwitchVectorProperty *sp)
+{
+  int i=0;
+ for (i=0; i < sp->nsp ; i++)
+ {
+   /*IDLog("Switch %s is %s\n", sp->sp[i].name, sp->sp[i].s == ISS_ON ? "On" : "Off");*/
+     if (sp->sp[i].s == ISS_ON)
+      return i;
+ }
+
+ return -1;
+}
+
+int checkPowerS(ISwitchVectorProperty *sp)
+{
+  if (ConnectSP.s != IPS_OK)
+  {
+    if (!strcmp(sp->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the CCD is offline.", sp->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the CCD is offline.", sp->label);
+	
+    sp->s = IPS_IDLE;
+    IDSetSwitch(sp, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int checkPowerN(INumberVectorProperty *np)
+{
+  if (ConnectSP.s != IPS_OK)
+  {
+     if (!strcmp(np->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the CCD is offline.", np->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the CCD is offline.", np->label);
+    
+    np->s = IPS_IDLE;
+    IDSetNumber(np, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int checkPowerT(ITextVectorProperty *tp)
+{
+
+  if (ConnectSP.s != IPS_OK)
+  {
+    if (!strcmp(tp->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the CCD is offline.", tp->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the CCD is offline.", tp->label);
+	
+    tp->s = IPS_IDLE;
+    IDSetText(tp, NULL);
+    return -1;
+  }
+
+  return 0;
+
+}
+
+void connectCCD()
+{
+	long err;
+	char errmsg[ERRMSG_SIZE];
+	
+	IDLog ("In ConnectCCD\n");
+   
+  /* USB by default {USB, SERIAL, PARALLEL, INET} */
+	switch (ConnectS[0].s)
+	{
+		case ISS_ON:
+		IDLog("Current portSwitch is %d\n", portSwitchIndex);
+		IDLog("Attempting to find the camera in domain %ld\n", Domains[portSwitchIndex]);
+		if (findcam(Domains[portSwitchIndex])) {
+			ConnectSP.s = IPS_IDLE;
+			ConnectS[0].s = ISS_OFF;
+			ConnectS[1].s = ISS_ON;
+			IDSetSwitch(&ConnectSP, "Error: no cameras were detected.");
+			IDLog("Error: no cameras were detected.\n");
+			return;
+		}
+
+		if ((err = FLIOpen(&fli_dev, FLICam->name, FLIDEVICE_CAMERA | FLICam->domain)))
+		{
+			ConnectSP.s = IPS_IDLE;
+			ConnectS[0].s = ISS_OFF;
+			ConnectS[1].s = ISS_ON;
+			IDSetSwitch(&ConnectSP, "Error: FLIOpen() failed. %s.", strerror( (int) -err));
+			IDLog("Error: FLIOpen() failed. %s.\n", strerror( (int) -err));
+			return;
+		}
+      
+		/* Sucess! */
+		ConnectS[0].s = ISS_ON;
+		ConnectS[1].s = ISS_OFF;
+		ConnectSP.s = IPS_OK;
+		IDSetSwitch(&ConnectSP, "CCD is online. Retrieving basic data.");
+		IDLog("CCD is online. Retrieving basic data.\n");
+		getBasicData();
+		if (manageDefaults(errmsg))
+		{
+			IDMessage(mydev, errmsg, NULL);
+			IDLog("%s", errmsg);
+			return;
+		}
+
+		break;
+      
+		case ISS_OFF:
+			ConnectS[0].s = ISS_OFF;
+			ConnectS[1].s = ISS_ON;
+			ConnectSP.s = IPS_IDLE;
+			if ((err = FLIClose(fli_dev))) {
+				ConnectSP.s = IPS_IDLE;
+				ConnectS[0].s = ISS_OFF;
+				ConnectS[1].s = ISS_ON;
+				IDSetSwitch(&ConnectSP, "Error: FLIClose() failed. %s.", strerror( (int) -err));
+				IDLog("Error: FLIClose() failed. %s.\n", strerror( (int) -err));
+				return;
+			}
+			IDSetSwitch(&ConnectSP, "CCD is offline.");
+			break;
+     }
+}
+
+/* isCCDConnected: return 1 if we have a connection, 0 otherwise */
+int isCCDConnected(void)
+{
+  return ((ConnectS[0].s == ISS_ON) ? 1 : 0);
+}
+
+int findcam(flidomain_t domain)
+{
+  char **tmplist;
+  long err;
+  
+  IDLog("In find Camera, the domain is %ld\n", domain);
+
+  if (( err = FLIList(domain | FLIDEVICE_CAMERA, &tmplist)))
+  {
+    IDLog("FLIList() failed. %s\n", strerror((int)-err));
+    return -1;
+  }
+  
+  if (tmplist != NULL && tmplist[0] != NULL)
+  {
+    int i;
+
+    IDLog("Trying to allocate memory to FLICam\n");
+    if ((FLICam = malloc (sizeof (cam_t))) == NULL)
+    {
+        IDLog("malloc() failed.\n");
+	return -1;
+    }
+
+    for (i = 0; tmplist[i] != NULL; i++)
+    {
+      int j;
+
+      for (j = 0; tmplist[i][j] != '\0'; j++)
+	if (tmplist[i][j] == ';')
+	{
+	  tmplist[i][j] = '\0';
+	  break;
+	}
+    }
+    
+     FLICam->domain = domain;
+     
+	switch (domain)
+	{
+		case FLIDOMAIN_PARALLEL_PORT:
+			FLICam->dname = strdup("parallel port");
+			break;
+
+		case FLIDOMAIN_USB:
+			FLICam->dname = strdup("USB");
+			break;
+
+		case FLIDOMAIN_SERIAL:
+			FLICam->dname = strdup("serial");
+			break;
+
+		case FLIDOMAIN_INET:
+			FLICam->dname = strdup("inet");
+			break;
+
+		default:
+			FLICam->dname = strdup("Unknown domain");
+	}
+      
+      FLICam->name = strdup(tmplist[0]);
+      
+     if ((err = FLIFreeList(tmplist)))
+     {
+       IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err));
+       return -1;
+     }
+      
+   } /* end if */
+   else
+   {
+     if ((err = FLIFreeList(tmplist)))
+     {
+       IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err));
+       return -1;
+     }
+     
+     return -1;
+   }
+
+  IDLog("Findcam() finished successfully.\n");
+  return 0;
+}
+
+double min()
+{
+  double lmin = FLIImg->img[0];
+  int ind=0, i, j;
+  
+  for (i= 0; i < FLIImg->height ; i++)
+    for (j= 0; j < FLIImg->width; j++)
+    {
+       ind = (i * FLIImg->width) + j;
+       if (FLIImg->img[ind] < lmin) lmin = FLIImg->img[ind];
+    }
+    
+    return lmin;
+}
+
+double max()
+{
+  double lmax = FLIImg->img[0];
+  int ind=0, i, j;
+  
+   for (i= 0; i < FLIImg->height ; i++)
+    for (j= 0; j < FLIImg->width; j++)
+    {
+      ind = (i * FLIImg->width) + j;
+       if (FLIImg->img[ind] > lmax) lmax = FLIImg->img[ind];
+    }
+    
+    return lmax;
+}
Index: /BAORadio/libindi/v1/drivers/filter_wheel/fli_wheel.c
===================================================================
--- /BAORadio/libindi/v1/drivers/filter_wheel/fli_wheel.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/filter_wheel/fli_wheel.c	(revision 500)
@@ -0,0 +1,710 @@
+#if 0
+    FLI WHEEL
+    INDI Interface for Finger Lakes Instruments Filter Wheels
+    Copyright (C) 2005 Gaetano Vocca (yagvoc-web AT yahoo DOT it)
+	Based on fli_ccd by Jasem Mutlaq (mutlaqja AT ikarustech DOT com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "libfli.h"
+#include "indidevapi.h"
+#include "eventloop.h"
+#include "indicom.h"
+
+void ISInit(void);
+void getBasicData(void);
+void ISPoll(void *);
+void handleExposure(void *);
+void connectFilter(void);
+int  findwheel(flidomain_t domain);
+int  manageDefaults(char errmsg[]);
+int  checkPowerS(ISwitchVectorProperty *sp);
+int  checkPowerN(INumberVectorProperty *np);
+int  checkPowerT(ITextVectorProperty *tp);
+int  getOnSwitch(ISwitchVectorProperty *sp);
+int  isFilterConnected(void);
+
+double min(void);
+double max(void);
+
+extern char* me;
+extern int errno;
+
+#define mydev           "FLI Wheel"
+
+#define MAIN_GROUP	"Main Control"
+
+#define LAST_FILTER  14		/* Max slot index */
+#define FIRST_FILTER 0		/* Min slot index */
+
+#define currentFilter	FilterN[0].value
+
+#define POLLMS		1000
+#define LIBVERSIZ 	1024
+#define PREFIXSIZ	64
+#define PIPEBUFSIZ	8192
+#define FRAME_ILEN	64
+
+typedef struct {
+  flidomain_t domain;
+  char *dname;
+  char *name;
+  char *model;
+  long HWRevision;
+  long FWRevision;
+  long current_filter;
+  long filter_count;
+  long home;
+} cam_t;
+
+
+static flidev_t fli_dev;
+static cam_t *FLIWheel;
+static int portSwitchIndex;
+static int simulation;
+static int targetFilter;
+
+long int Domains[] = { FLIDOMAIN_USB, FLIDOMAIN_SERIAL, FLIDOMAIN_PARALLEL_PORT,  FLIDOMAIN_INET };
+
+/*INDI controls */
+
+/* Connect/Disconnect */
+static ISwitch PowerS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty PowerSP	= { mydev, "CONNECTION" , "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+
+/* Types of Ports */
+static ISwitch PortS[]           	= {{"USB", "", ISS_ON, 0, 0}, {"Serial", "", ISS_OFF, 0, 0}, {"Parallel", "", ISS_OFF, 0, 0}, {"INet", "", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty PortSP	= { mydev, "Port Type", "", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PortS, NARRAY(PortS), "", 0};
+ 
+/* Filter control */
+static INumber FilterN[]	  = { {"FILTER_SLOT_VALUE", "Active Filter", "%2.0f", FIRST_FILTER, LAST_FILTER, 1, 0, 0, 0, 0}};
+static INumberVectorProperty FilterNP = { mydev, "FILTER_SLOT", "Filter", MAIN_GROUP, IP_RW, 0, IPS_IDLE, FilterN, NARRAY(FilterN), "", 0};
+  
+/* send client definitions of all properties */
+void ISInit()
+{
+	static int isInit=0;
+	
+	if (isInit)
+		return;
+	
+	/* USB by default {USB, SERIAL, PARALLEL, INET} */
+	portSwitchIndex = 0;
+
+	targetFilter = 0;
+
+        /* No Simulation by default */
+	simulation = 0;
+
+        /* Enable the following for simulation mode */
+        /*simulation = 1;
+        IDLog("WARNING: Simulation is on\n");*/
+        
+        IEAddTimer (POLLMS, ISPoll, NULL);
+	
+	isInit = 1; 
+}
+
+void ISGetProperties (const char *dev)
+{ 
+
+	ISInit();
+	
+	if (dev && strcmp (mydev, dev))
+		return;
+	
+	/* Main Control */
+	IDDefSwitch(&PowerSP, NULL);
+	IDDefSwitch(&PortSP, NULL);
+	IDDefNumber(&FilterNP, NULL);
+	
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+		return;
+	    
+	ISInit();
+	    
+	/* Port type */
+	if (!strcmp (name, PortSP.name))
+	{
+		PortSP.s = IPS_IDLE; 
+		IUResetSwitch(&PortSP);
+		IUUpdateSwitch(&PortSP, states, names, n);
+		portSwitchIndex = getOnSwitch(&PortSP);
+		
+		PortSP.s = IPS_OK; 
+		IDSetSwitch(&PortSP, NULL);
+		return;
+	}
+	
+	/* Connection */
+	if (!strcmp (name, PowerSP.name))
+	{
+		IUResetSwitch(&PowerSP);
+		IUUpdateSwitch(&PowerSP, states, names, n);
+		connectFilter();
+		return;
+	}
+	
+     
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	ISInit();
+	
+	/* ignore if not ours */ 
+	if (dev && strcmp (mydev, dev))
+		return;
+
+	/* suppress warning */
+	n=n; dev=dev; name=name; names=names; texts=texts;
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+	long err;
+	INumber *np;
+	long newFilter;
+
+	n = n;
+	
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+	    
+	ISInit();
+	
+	
+if (!strcmp(FilterNP.name, name)) {
+		if (simulation) {
+			targetFilter = values[0];
+			FilterNP.s = IPS_BUSY;
+			IDSetNumber(&FilterNP, "Setting current filter to slot %d", targetFilter);
+			IDLog("Setting current filter to slot %d\n", targetFilter);
+			return;
+ 		}
+
+
+		if (!isFilterConnected()) {
+			IDMessage(mydev, "Device not connected.");
+			FilterNP.s = IPS_IDLE;
+			IDSetNumber(&FilterNP, NULL);
+			return;
+		}
+		
+		targetFilter = values[0];
+		
+		np = IUFindNumber(&FilterNP, names[0]);
+		
+		if (!np)
+		{
+                        FilterNP.s = IPS_ALERT;
+			IDSetNumber(&FilterNP, "Unknown error. %s is not a member of %s property.", names[0], name);
+			return;
+		}
+		
+		if (targetFilter < FIRST_FILTER || targetFilter > FLIWheel->filter_count - 1)
+		{
+			FilterNP.s = IPS_ALERT;
+			IDSetNumber(&FilterNP, "Error: valid range of filter is from %d to %d", FIRST_FILTER, LAST_FILTER);
+			return;
+		}
+
+		FilterNP.s = IPS_BUSY;
+		IDSetNumber(&FilterNP, "Setting current filter to slot %d", targetFilter);
+		IDLog("Setting current filter to slot %d\n", targetFilter);
+		
+		if ( (err = FLISetFilterPos(fli_dev, targetFilter)))
+		{
+			FilterNP.s = IPS_ALERT;
+			IDSetNumber(&FilterNP, "FLISetFilterPos() failed. %s.", strerror((int)-err));
+			IDLog("FLISetFilterPos() failed. %s.", strerror((int)-err));
+			return;
+		}
+		
+		/* Check current filter position */
+		if (( err = FLIGetFilterPos(fli_dev, &newFilter))) {
+			FilterNP.s = IPS_ALERT;
+			IDSetNumber(&FilterNP, "FLIGetFilterPos() failed. %s.", strerror((int)-err));
+			IDLog("FLIGetFilterPos() failed. %s.\n", strerror((int)-err));
+			return;
+		}
+		
+		if (newFilter == targetFilter) {
+			FLIWheel->current_filter = targetFilter;
+			FilterN[0].value = FLIWheel->current_filter;
+			FilterNP.s = IPS_OK;
+			IDSetNumber(&FilterNP, "Filter set to slot #%d", targetFilter);
+			return;
+		}
+
+		return;
+	}
+}
+
+
+/* Retrieves basic data from the Wheel upon connection like temperature, array size, firmware..etc */
+void getBasicData()
+{
+
+	char buff[2048];
+	long err;
+	
+	if ((err = FLIGetModel (fli_dev, buff, 2048)))
+	{
+		IDMessage(mydev, "FLIGetModel() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetModel() failed. %s.\n", strerror((int)-err));
+		return;
+	}
+	else
+	{
+		if ( (FLIWheel->model = malloc (sizeof(char) * 2048)) == NULL)
+		{
+		IDMessage(mydev, "malloc() failed.");
+		IDLog("malloc() failed.");
+		return;
+		}
+		
+		strcpy(FLIWheel->model, buff);
+	}
+  
+	if (( err = FLIGetHWRevision(fli_dev, &FLIWheel->HWRevision)))
+	{
+		IDMessage(mydev, "FLIGetHWRevision() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetHWRevision() failed. %s.\n", strerror((int)-err));
+		
+		return;
+	}
+	
+	if (( err = FLIGetFWRevision(fli_dev, &FLIWheel->FWRevision)))
+	{
+		IDMessage(mydev, "FLIGetFWRevision() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetFWRevision() failed. %s.\n", strerror((int)-err));
+		return;
+	}
+	
+	if (( err = FLIGetFilterCount(fli_dev, &FLIWheel->filter_count)))
+	{
+		IDMessage(mydev, "FLIGetFilterCount() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetFilterCount() failed. %s.\n", strerror((int)-err));
+		return;
+	}
+  
+	IDLog("The filter count is %ld\n", FLIWheel->filter_count);
+	
+	FilterN[0].max = FLIWheel->filter_count - 1;
+	FilterNP.s = IPS_OK;
+	
+	IUUpdateMinMax(&FilterNP);
+	IDSetNumber(&FilterNP, "Setting basic data");
+	
+	IDLog("Exiting getBasicData()\n");
+  
+}
+
+int manageDefaults(char errmsg[])
+{
+	long err;
+	
+	/*IDLog("Resetting filter wheel to slot %d\n", 0);
+	FLIWheel->home = 0;
+	if (( err = FLISetFilterPos(fli_dev, 0)))
+	{
+		IDMessage(mydev, "FLISetFilterPos() failed. %s.", strerror((int)-err));
+		IDLog("FLISetFilterPos() failed. %s.\n", strerror((int)-err));
+		return (int)-err;
+	}*/
+
+	
+	if (( err = FLIGetFilterPos(fli_dev, &FLIWheel->current_filter)))
+	{
+		IDMessage(mydev, "FLIGetFilterPos() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetFilterPos() failed. %s.\n", strerror((int)-err));
+		return (int)-err;
+	}
+  
+	IDLog("The current filter is %ld\n", FLIWheel->current_filter);
+
+	FilterN[0].value = FLIWheel->current_filter;
+	IDSetNumber(&FilterNP, "Storing defaults");
+	
+	/* Success */
+	return 0;
+    
+}
+
+void ISPoll(void *p)
+{
+  static int simMTC = 5;
+
+  if (!isFilterConnected())
+  {
+      IEAddTimer (POLLMS, ISPoll, NULL);
+      return;
+  }
+
+
+  switch (FilterNP.s)
+  {
+    case IPS_IDLE:
+    case IPS_OK:
+       break;
+  
+   
+   case IPS_BUSY:
+    /* Simulate that it takes 5 seconds to change slot */
+    if (simulation)
+    {
+        simMTC--;
+        if (simMTC == 0)
+        {
+           simMTC = 5;
+           currentFilter = targetFilter;
+           FilterNP.s = IPS_OK;
+	   IDSetNumber(&FilterNP, "Filter set to slot #%2.0f", currentFilter);
+           break;
+        }
+        IDSetNumber(&FilterNP, NULL);
+        break;
+    }
+
+
+    /*if (( err = FLIGetFilterPos(fli_dev, &currentFilter)))
+	{
+                FilterNP.s = IPS_ALERT;
+		IDSetNumber(&FilterNP, "FLIGetFilterPos() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetFilterPos() failed. %s.\n", strerror((int)-err));
+		return;
+	}
+
+        if (targetFilter == currentFilter)
+        {
+		FLIWheel->current_filter = currentFilter;
+		FilterNP.s = IPS_OK;
+		IDSetNumber(&FilterNP, "Filter set to slot #%2.0f", currentFilter);
+                return;
+        }
+       
+        IDSetNumber(&FilterNP, NULL);*/
+	break;
+
+   case IPS_ALERT:
+    break;
+ }
+
+   IEAddTimer (POLLMS, ISPoll, NULL);
+
+}
+
+
+
+int getOnSwitch(ISwitchVectorProperty *sp)
+{
+  int i=0;
+ for (i=0; i < sp->nsp ; i++)
+ {
+   /*IDLog("Switch %s is %s\n", sp->sp[i].name, sp->sp[i].s == ISS_ON ? "On" : "Off");*/
+     if (sp->sp[i].s == ISS_ON)
+      return i;
+ }
+
+ return -1;
+}
+
+int checkPowerS(ISwitchVectorProperty *sp)
+{
+
+  if (simulation)
+   return 0;
+
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(sp->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", sp->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", sp->label);
+	
+    sp->s = IPS_IDLE;
+    IDSetSwitch(sp, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int checkPowerN(INumberVectorProperty *np)
+{
+  if (simulation)
+   return 0;
+
+  if (PowerSP.s != IPS_OK)
+  {
+     if (!strcmp(np->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", np->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", np->label);
+    
+    np->s = IPS_IDLE;
+    IDSetNumber(np, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int checkPowerT(ITextVectorProperty *tp)
+{
+   if (simulation)
+    return 0;
+
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(tp->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", tp->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", tp->label);
+	
+    tp->s = IPS_IDLE;
+    IDSetText(tp, NULL);
+    return -1;
+  }
+
+  return 0;
+
+}
+
+void connectFilter()
+{
+	long err;
+	char errmsg[ERRMSG_SIZE];
+ 
+  
+	/* USB by default {USB, SERIAL, PARALLEL, INET} */
+	switch (PowerS[0].s)
+	{
+		case ISS_ON:
+			
+			if (simulation)
+			{
+	                        /* Success! */
+				PowerS[0].s = ISS_ON;
+				PowerS[1].s = ISS_OFF;
+				PowerSP.s = IPS_OK;
+				IDSetSwitch(&PowerSP, "Simulation Wheel is online.");
+				IDLog("Simulation Wheel is online.\n");
+				return;
+			}
+
+			IDLog("Current portSwitch is %d\n", portSwitchIndex);
+			IDLog("Attempting to find the device in domain %ld\n", Domains[portSwitchIndex]);
+
+			if (findwheel(Domains[portSwitchIndex]))
+			{
+				PowerSP.s = IPS_IDLE;
+				PowerS[0].s = ISS_OFF;
+				PowerS[1].s = ISS_ON;
+				IDSetSwitch(&PowerSP, "Error: no wheels were detected.");
+				IDLog("Error: no wheels were detected.\n");
+				return;
+			}
+			
+			if ((err = FLIOpen(&fli_dev, FLIWheel->name, FLIWheel->domain | FLIDEVICE_FILTERWHEEL)))
+			{
+				PowerSP.s = IPS_IDLE;
+				PowerS[0].s = ISS_OFF;
+				PowerS[1].s = ISS_ON;
+				IDSetSwitch(&PowerSP, "Error: FLIOpen() failed. %s.", strerror( (int) -err));
+				IDLog("Error: FLIOpen() failed. %s.\n", strerror( (int) -err));
+				return;
+			}
+
+			/* Success! */
+			PowerS[0].s = ISS_ON;
+			PowerS[1].s = ISS_OFF;
+			PowerSP.s = IPS_OK;
+			IDSetSwitch(&PowerSP, "Wheel is online. Retrieving basic data.");
+			IDLog("Wheel is online. Retrieving basic data.\n");
+			getBasicData();
+			
+
+			if (manageDefaults(errmsg))
+			{
+				IDMessage(mydev, errmsg, NULL);
+				IDLog("%s", errmsg);
+				return;
+			}
+
+			break;
+		
+		case ISS_OFF:
+
+			if (simulation)
+			{
+				PowerS[0].s = ISS_OFF;
+				PowerS[1].s = ISS_ON;
+				PowerSP.s = IPS_IDLE;
+				IDSetSwitch(&PowerSP, "Wheel is offline.");
+				return;
+			}
+
+			PowerS[0].s = ISS_OFF;
+			PowerS[1].s = ISS_ON;
+			PowerSP.s = IPS_IDLE;
+			if ((err = FLIClose(fli_dev))) {
+				PowerSP.s = IPS_ALERT;
+				IDSetSwitch(&PowerSP, "Error: FLIClose() failed. %s.", strerror( (int) -err));
+				IDLog("Error: FLIClose() failed. %s.\n", strerror( (int) -err));
+				return;
+			}
+			IDSetSwitch(&PowerSP, "Wheel is offline.");
+			break;
+	}
+}
+
+/* isFilterConnected: return 1 if we have a connection, 0 otherwise */
+int isFilterConnected(void)
+{
+   if (simulation)
+     return 1;
+
+   return ((PowerS[0].s == ISS_ON) ? 1 : 0);
+}
+
+int findwheel(flidomain_t domain)
+{
+	char **devlist;
+	long err;
+	
+	IDLog("In find Camera, the domain is %ld\n", domain);
+	
+	if (( err = FLIList(domain | FLIDEVICE_FILTERWHEEL, &devlist)))
+	{
+		IDLog("FLIList() failed. %s\n", strerror((int)-err));
+		return -1;
+	}
+	
+	if (devlist != NULL && devlist[0] != NULL)
+	{
+		int i;
+
+		IDLog("Trying to allocate memory to FLIWheel\n");
+		if ((FLIWheel = malloc (sizeof (cam_t))) == NULL)
+		{
+			IDLog("malloc() failed.\n");
+			return -1;
+		}
+		
+		for (i = 0; devlist[i] != NULL; i++)
+		{
+			int j;
+	
+			for (j = 0; devlist[i][j] != '\0'; j++)
+				if (devlist[i][j] == ';')
+				{
+					devlist[i][j] = '\0';
+					break;
+				}
+		}
+
+		FLIWheel->domain = domain;
+		
+		/* Each driver handles _only_ one camera for now */
+		switch (domain)
+		{
+			case FLIDOMAIN_PARALLEL_PORT:
+				FLIWheel->dname = strdup("parallel port");
+				break;
+	
+			case FLIDOMAIN_USB:
+				FLIWheel->dname = strdup("USB");
+				break;
+	
+			case FLIDOMAIN_SERIAL:
+				FLIWheel->dname = strdup("serial");
+				break;
+	
+			case FLIDOMAIN_INET:
+				FLIWheel->dname = strdup("inet");
+				break;
+	
+			default:
+				FLIWheel->dname = strdup("Unknown domain");
+		}
+		
+		IDLog("Domain set OK\n");
+		
+		FLIWheel->name = strdup(devlist[0]);
+				
+		if ((err = FLIFreeList(devlist)))
+		{
+			IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err));
+			return -1;
+		}
+      
+	} /* end if */
+	else
+	{
+		if ((err = FLIFreeList(devlist)))
+		{
+			IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err));
+			return -1;
+		}
+		
+		return -1;
+	}
+
+	IDLog("Findcam() finished successfully.\n");
+	return 0;
+}
Index: /BAORadio/libindi/v1/drivers/filter_wheel/trutech_wheel.c
===================================================================
--- /BAORadio/libindi/v1/drivers/filter_wheel/trutech_wheel.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/filter_wheel/trutech_wheel.c	(revision 500)
@@ -0,0 +1,421 @@
+#if 0
+   True Technology Filter Wheel
+    Copyright (C) 2006 Jasem Mutlaq (mutlaqja AT ikarustech DOT com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "indidevapi.h"
+#include "eventloop.h"
+#include "indicom.h"
+
+void ISInit(void);
+void getBasicData(void);
+void ISPoll(void *);
+void handleExposure(void *);
+void connectFilter(void);
+int  manageDefaults(char errmsg[]);
+int  checkPowerS(ISwitchVectorProperty *sp);
+int  checkPowerN(INumberVectorProperty *np);
+int  checkPowerT(ITextVectorProperty *tp);
+int  getOnSwitch(ISwitchVectorProperty *sp);
+int  isFilterConnected(void);
+
+static int targetFilter;
+static int fd;
+const unsigned char COMM_PRE  = 0x01;
+const unsigned char COMM_INIT = 0xA5;
+const unsigned char COMM_FILL = 0x20;
+
+#define mydev           		"TruTech Wheel"
+#define MAIN_GROUP			"Main Control"
+#define currentFilter			FilterPositionN[0].value
+#define POLLMS				3000
+#define DEFAULT_FILTER_COUNT		5
+#define MAX_FILTER_COUNT		10
+#define ERRMSG_SIZE			1024
+
+#define CMD_SIZE			5
+#define CMD_JUNK			64
+#define CMD_RESP			15
+
+#define FILTER_TIMEOUT			15					/* 15 Seconds before timeout */
+#define FIRST_FILTER			1
+
+
+/*INDI controls */
+
+/* Connect/Disconnect */
+static ISwitch PowerS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty PowerSP	= { mydev, "CONNECTION" , "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+
+/* Connection Port */
+static IText PortT[]			= {{"PORT", "Port", 0, 0, 0, 0}};
+static ITextVectorProperty PortTP		= { mydev, "DEVICE_PORT", "Ports", MAIN_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
+
+/* Home/Learn Swtich */
+static ISwitch HomeS[]          	= {{"Find" , "" , ISS_OFF, 0, 0}};
+static ISwitchVectorProperty HomeSP	= { mydev, "HOME" , "", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, HomeS, NARRAY(HomeS), "", 0};
+
+/* Filter Count */
+static INumber FilterCountN[]	  = { {"Count", "", "%2.0f",  0 , MAX_FILTER_COUNT, 1, DEFAULT_FILTER_COUNT, 0, 0, 0}};
+static INumberVectorProperty FilterCountNP = { mydev, "Filter Count", "", MAIN_GROUP, IP_RW, 0, IPS_IDLE, FilterCountN, NARRAY(FilterCountN), "", 0};
+
+/* Filter Position */
+static INumber FilterPositionN[]	  = { {"FILTER_SLOT_VALUE", "Active Filter", "%2.0f",  1 , DEFAULT_FILTER_COUNT, 1, 1, 0, 0, 0}};
+static INumberVectorProperty FilterPositionNP = { mydev, "FILTER_SLOT", "Filter", MAIN_GROUP, IP_RW, 0, IPS_IDLE, FilterPositionN, NARRAY(FilterPositionN), "", 0};
+
+/* send client definitions of all properties */
+void ISInit()
+{
+	static int isInit=0;
+	
+	if (isInit)
+		return;
+	
+
+	targetFilter = -1;
+	fd = -1;
+
+	isInit = 1; 
+}
+
+void ISGetProperties (const char *dev)
+{ 
+
+	ISInit();
+	
+	if (dev && strcmp (mydev, dev))
+		return;
+	
+	/* Main Control */
+	IDDefSwitch(&PowerSP, NULL);
+	IDDefText(&PortTP, NULL);
+	IDDefNumber(&FilterCountNP, NULL);
+	IDDefSwitch(&HomeSP, NULL);
+	IDDefNumber(&FilterPositionNP, NULL);
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	int err;
+	char error_message[ERRMSG_SIZE];
+
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+		return;
+	    
+	ISInit();
+	    
+	/* Connection */
+	if (!strcmp (name, PowerSP.name))
+	{
+		IUUpdateSwitch(&PowerSP, states, names, n);
+		connectFilter();
+		return;
+	}
+
+	/* Home Search */
+	if (!strcmp (name, HomeSP.name))
+	{
+		int nbytes=0;
+		unsigned char type = 0x03;
+		unsigned char chksum = COMM_INIT + type + COMM_FILL;
+		/*char filter_command[5] = { COMM_PRE, COMM_INIT, type, COMM_FILL, chksum };*/
+		char filter_command[CMD_SIZE];
+		snprintf(filter_command, CMD_SIZE,  "%c%c%c%c%c", COMM_PRE, COMM_INIT, type, COMM_FILL, chksum);
+
+		if (checkPowerS(&HomeSP))
+			return;
+
+		err = tty_write(fd, filter_command, CMD_SIZE, &nbytes);
+		
+		/* Send Home Command */
+		if (err != TTY_OK)
+		{
+		
+			tty_error_msg(err, error_message, ERRMSG_SIZE);
+			
+			HomeSP.s = IPS_ALERT;
+			IDSetSwitch(&HomeSP, "Sending command Home to filter failed. %s", error_message);
+			IDLog("Sending command Home to filter failed. %s\n", error_message);
+
+			return;
+		}
+
+		FilterPositionN[0].value = 1;
+		FilterPositionNP.s = IPS_OK;
+		HomeSP.s = IPS_OK;
+		IDSetSwitch(&HomeSP, "Filter set to HOME.");
+		IDSetNumber(&FilterPositionNP, NULL);
+		
+	}
+	
+     
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	ISInit();
+	
+	/* ignore if not ours */ 
+	if (dev && strcmp (mydev, dev))
+		return;
+
+	if (!strcmp(name, PortTP.name))
+	{
+		if (IUUpdateText(&PortTP, texts, names, n))
+		  return;
+
+		PortTP.s = IPS_OK;
+		IDSetText(&PortTP, NULL);
+	}
+	
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+	long err;
+	INumber *np;
+	n = n;
+	
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+	    
+	ISInit();
+	
+	if (!strcmp(FilterPositionNP.name, name)) 
+	{
+
+		if (!isFilterConnected()) 
+		{
+			IDMessage(mydev, "Filter is not connected.");
+			FilterPositionNP.s = IPS_IDLE;
+			IDSetNumber(&FilterPositionNP, NULL);
+			return;
+		}
+
+		np = IUFindNumber(&FilterPositionNP, names[0]);
+		if (np == &FilterPositionN[0])
+		{
+			
+			targetFilter = values[0];
+			int nbytes=0;
+			char type = 0x01;
+			char chksum = COMM_INIT + type + (char) targetFilter;
+			/*char filter_command[5] = { COMM_PRE, COMM_INIT, type, targetFilter, chksum };*/
+			char filter_command[CMD_SIZE];
+
+			snprintf(filter_command, CMD_SIZE,  "%c%c%c%c%c", COMM_PRE, COMM_INIT, type, COMM_FILL, chksum);
+
+			if (targetFilter < FilterPositionN[0].min || targetFilter > FilterPositionN[0].max)
+			{
+				FilterPositionNP.s = IPS_ALERT;
+				IDSetNumber(&FilterPositionNP, "Error: valid range of filter is from %d to %d", (int) FilterPositionN[0].min, (int) FilterPositionN[0].max);
+				return;
+			}
+
+			IUUpdateNumber(&FilterPositionNP, values, names, n);
+			err = tty_write(fd, filter_command, CMD_SIZE, &nbytes);
+
+			FilterPositionNP.s = IPS_OK;
+			IDSetNumber(&FilterPositionNP, "Setting current filter to slot %d", targetFilter);
+		}
+		else
+		{
+			FilterPositionNP.s = IPS_IDLE;
+			IDSetNumber(&FilterPositionNP, NULL);
+		}
+		
+		return;
+	}
+
+	if (!strcmp(FilterCountNP.name, name)) 
+	{
+
+		if (!isFilterConnected()) 
+		{
+			IDMessage(mydev, "Filter is not connected.");
+			FilterCountNP.s = IPS_IDLE;
+			IDSetNumber(&FilterCountNP, NULL);
+			return;
+		}
+
+		np = IUFindNumber(&FilterCountNP, names[0]);
+		if (np == &FilterCountN[0])
+		{
+			if (IUUpdateNumber(&FilterCountNP, values, names, n) <0)
+				return;
+
+			FilterPositionN[0].min = 1;
+			FilterPositionN[0].max = (int) FilterCountN[0].value;
+			IUUpdateMinMax(&FilterPositionNP);
+
+			FilterCountNP.s = IPS_OK;
+			IDSetNumber(&FilterCountNP, "Updated number of available filters to %d", ((int) FilterCountN[0].value));
+		}
+		else
+		{
+			FilterCountNP.s = IPS_IDLE;
+			IDSetNumber(&FilterCountNP, NULL);
+		}
+		
+		return;
+	}
+
+}
+
+int getOnSwitch(ISwitchVectorProperty *sp)
+{
+  int i=0;
+ for (i=0; i < sp->nsp ; i++)
+ {
+     if (sp->sp[i].s == ISS_ON)
+      return i;
+ }
+
+ return -1;
+
+}
+
+int checkPowerS(ISwitchVectorProperty *sp)
+{
+
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(sp->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", sp->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", sp->label);
+	
+    sp->s = IPS_IDLE;
+    IDSetSwitch(sp, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int checkPowerN(INumberVectorProperty *np)
+{
+  if (PowerSP.s != IPS_OK)
+  {
+     if (!strcmp(np->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", np->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", np->label);
+    
+    np->s = IPS_IDLE;
+    IDSetNumber(np, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int checkPowerT(ITextVectorProperty *tp)
+{
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(tp->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", tp->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the wheel is offline.", tp->label);
+	
+    tp->s = IPS_IDLE;
+    IDSetText(tp, NULL);
+    return -1;
+  }
+
+  return 0;
+
+}
+
+void connectFilter()
+{
+	int err;
+	char errmsg[ERRMSG_SIZE];
+ 
+	switch (PowerS[0].s)
+	{
+		case ISS_ON:
+			if ( (err = tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd)) != TTY_OK)
+			{
+				PowerSP.s = IPS_ALERT;
+				IDSetSwitch(&PowerSP, "Error: cannot connect to %s. Make sure the filter is connected and you have access to the port.", PortT[0].text);
+				tty_error_msg(err, errmsg, ERRMSG_SIZE);
+				IDLog("Error: %s\n", errmsg);
+				return;
+			}
+
+			PowerSP.s = IPS_OK;
+			IDSetSwitch(&PowerSP, "Filter Wheel is online. True Technology filter wheel suffers from several bugs. Please refer to http://indi.sf.net/profiles/trutech.html for more details.");
+			break;
+		
+		case ISS_OFF:
+			if ( (err = tty_disconnect(fd)) != TTY_OK)
+			{
+				PowerSP.s = IPS_ALERT;
+				IDSetSwitch(&PowerSP, "Error: cannot disconnect.");
+				tty_error_msg(err, errmsg, ERRMSG_SIZE);
+				IDLog("Error: %s\n", errmsg);
+				return;
+			}
+
+			PowerSP.s = IPS_IDLE;
+			IDSetSwitch(&PowerSP, "Filter Wheel is offline.");
+			break;
+	}
+}
+
+/* isFilterConnected: return 1 if we have a connection, 0 otherwise */
+int isFilterConnected(void)
+{
+   return ((PowerS[0].s == ISS_ON) ? 1 : 0);
+}
+
Index: /BAORadio/libindi/v1/drivers/focuser/fli_pdf.c
===================================================================
--- /BAORadio/libindi/v1/drivers/focuser/fli_pdf.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/focuser/fli_pdf.c	(revision 500)
@@ -0,0 +1,678 @@
+#if 0
+    FLI Precision Digital Focuer 
+    Copyright (C) 2005 Jasem Mutlaq (mutlaqja AT ikarustech DOT com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "libfli.h"
+#include "indidevapi.h"
+#include "eventloop.h"
+#include "indicom.h"
+
+void ISInit(void);
+void getBasicData(void);
+void ISPoll(void *);
+void handleExposure(void *);
+void connectPDF(void);
+int  findPDF(flidomain_t domain);
+int  manageDefaults(char errmsg[]);
+int  checkPowerS(ISwitchVectorProperty *sp);
+int  checkPowerN(INumberVectorProperty *np);
+int  checkPowerT(ITextVectorProperty *tp);
+int  getOnSwitch(ISwitchVectorProperty *sp);
+int  isPDFConnected(void);
+
+double min(void);
+double max(void);
+
+extern char* me;
+extern int errno;
+
+#define mydev           "FLI PDF"
+#define MAIN_GROUP	"Main Control"
+#define currentPosition	 FocuserN[0].value
+#define POLLMS		1000
+
+typedef struct {
+  flidomain_t domain;
+  char *dname;
+  char *name;
+  char *model;
+  long HWRevision;
+  long FWRevision;
+  long current_pos;
+  long home;
+} pdf_t;
+
+
+static flidev_t fli_dev;
+static pdf_t *FLIPDF;
+static int portSwitchIndex;
+static int simulation;
+static long targetPosition;
+
+long int Domains[] = { FLIDOMAIN_USB, FLIDOMAIN_SERIAL, FLIDOMAIN_PARALLEL_PORT,  FLIDOMAIN_INET };
+
+/*INDI controls */
+
+/* Connect/Disconnect */
+static ISwitch PowerS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty PowerSP	= { mydev, "CONNECTION" , "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+
+/* Types of Ports */
+static ISwitch PortS[]           	= {{"USB", "", ISS_ON, 0, 0}, {"Serial", "", ISS_OFF, 0, 0}, {"Parallel", "", ISS_OFF, 0, 0}, {"INet", "", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty PortSP	= { mydev, "Port Type", "", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PortS, NARRAY(PortS), "", 0};
+ 
+/* Focuser control */
+static INumber FocuserN[]	  = { {"Position", "", "%2.0f", -10000., 10000., 1., 0, 0, 0, 0}};
+static INumberVectorProperty FocuserNP = { mydev, "Focuser", "", MAIN_GROUP, IP_RW, 0, IPS_IDLE, FocuserN, NARRAY(FocuserN), "", 0};
+
+/* Focuser home */
+static ISwitch HomeS[]			= { {"Home", "", ISS_OFF, 0, 0} };
+static ISwitchVectorProperty HomeSP = { mydev, "Home", "", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, HomeS, NARRAY(HomeS), "", 0};
+
+/* send client definitions of all properties */
+void ISInit()
+{
+	static int isInit=0;
+	
+	if (isInit)
+		return;
+	
+	/* USB by default {USB, SERIAL, PARALLEL, INET} */
+	portSwitchIndex = 0;
+
+	targetPosition = 0;
+
+        /* No Simulation by default */
+	simulation = 0;
+
+        /* Enable the following for simulation mode */
+        /*simulation = 1;
+        IDLog("WARNING: Simulation is on\n");*/
+        
+        IEAddTimer (POLLMS, ISPoll, NULL);
+	
+	isInit = 1; 
+}
+
+void ISGetProperties (const char *dev)
+{ 
+
+	ISInit();
+	
+	if (dev && strcmp (mydev, dev))
+		return;
+	
+	/* Main Control */
+	IDDefSwitch(&PowerSP, NULL);
+	IDDefSwitch(&PortSP, NULL);
+	IDDefSwitch(&HomeSP, NULL);
+	IDDefNumber(&FocuserNP, NULL);
+	
+	
+}
+ 
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	long err=0;
+
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+		return;
+	    
+	ISInit();
+	    
+	/* Port type */
+	if (!strcmp (name, PortSP.name))
+	{
+		PortSP.s = IPS_IDLE; 
+		IUResetSwitch(&PortSP);
+		IUUpdateSwitch(&PortSP, states, names, n);
+		portSwitchIndex = getOnSwitch(&PortSP);
+		
+		PortSP.s = IPS_OK; 
+		IDSetSwitch(&PortSP, NULL);
+		return;
+	}
+	
+	/* Connection */
+	if (!strcmp (name, PowerSP.name))
+	{
+		IUResetSwitch(&PowerSP);
+		IUUpdateSwitch(&PowerSP, states, names, n);
+		connectPDF();
+		return;
+	}
+
+	if (!strcmp(name, HomeSP.name))
+	{
+		if (!isPDFConnected()) 
+		{
+			IDMessage(mydev, "Device not connected.");
+			HomeSP.s = IPS_IDLE;
+			IDSetSwitch(&HomeSP, NULL);
+			return;
+		}
+
+		
+		if ( (err = FLIHomeFocuser(fli_dev)))
+		{
+			HomeSP.s = IPS_ALERT;
+			IDSetSwitch(&HomeSP, "FLIHomeFocuser() failed. %s.", strerror((int)-err));
+			IDLog("FLIHomeFocuser() failed. %s.\n", strerror((int)-err));
+			return;
+		}
+
+		HomeSP.s = IPS_OK;
+		IDSetSwitch(&HomeSP, "Focuser at home position.");
+		IDLog("Focuser at home position.\n");
+		return;
+	}
+	
+     
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	ISInit();
+	
+	/* ignore if not ours */ 
+	if (dev && strcmp (mydev, dev))
+		return;
+
+	/* suppress warning */
+	n=n; dev=dev; name=name; names=names; texts=texts;
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+	long err;
+	long newPos;
+	names=names;
+	n = n;
+	
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+	    
+	ISInit();
+	
+	
+	if (!strcmp(FocuserNP.name, name)) {
+		if (simulation) 
+		{
+			targetPosition = values[0];
+			FocuserNP.s = IPS_BUSY;
+			IDSetNumber(&FocuserNP, "Setting focuser position to %ld", targetPosition);
+			IDLog("Setting focuser position to %ld", targetPosition);
+			return;
+ 		}
+
+
+		if (!isPDFConnected()) 
+		{
+			IDMessage(mydev, "Device not connected.");
+			FocuserNP.s = IPS_IDLE;
+			IDSetNumber(&FocuserNP, NULL);
+			return;
+		}
+		
+		targetPosition = values[0];
+		
+		FocuserNP.s = IPS_BUSY;
+		IDSetNumber(&FocuserNP, "Setting focuser position to %ld", targetPosition);
+		IDLog("Setting focuser position to %ld\n", targetPosition);
+		
+		if ( (err = FLIStepMotor(fli_dev, targetPosition)))
+		{
+			FocuserNP.s = IPS_ALERT;
+			IDSetNumber(&FocuserNP, "FLIStepMotor() failed. %s.", strerror((int)-err));
+			IDLog("FLIStepMotor() failed. %s.", strerror((int)-err));
+			return;
+		}
+		
+		/* Check current focuser position */
+		if (( err = FLIGetStepperPosition(fli_dev, &newPos))) 
+		{
+			FocuserNP.s = IPS_ALERT;
+			IDSetNumber(&FocuserNP, "FLIGetStepperPosition() failed. %s.", strerror((int)-err));
+			IDLog("FLIGetStepperPosition() failed. %s.\n", strerror((int)-err));
+			return;
+		}
+		
+		if (newPos == targetPosition) 
+		{
+			FLIPDF->current_pos = targetPosition;
+			currentPosition = FLIPDF->current_pos;
+			FocuserNP.s = IPS_OK;
+			IDSetNumber(&FocuserNP, "Focuser position %ld", targetPosition);
+			return;
+		}
+
+		return;
+	}
+}
+
+
+/* Retrieves basic data from the focuser upon connection like temperature, array size, firmware..etc */
+void getBasicData()
+{
+
+	char buff[2048];
+	long err;
+	
+	if ((err = FLIGetModel (fli_dev, buff, 2048)))
+	{
+		IDMessage(mydev, "FLIGetModel() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetModel() failed. %s.\n", strerror((int)-err));
+		return;
+	}
+	else
+	{
+		if ( (FLIPDF->model = malloc (sizeof(char) * 2048)) == NULL)
+		{
+		IDMessage(mydev, "malloc() failed.");
+		IDLog("malloc() failed.");
+		return;
+		}
+		
+		strcpy(FLIPDF->model, buff);
+	}
+  
+	if (( err = FLIGetHWRevision(fli_dev, &FLIPDF->HWRevision)))
+	{
+		IDMessage(mydev, "FLIGetHWRevision() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetHWRevision() failed. %s.\n", strerror((int)-err));
+		
+		return;
+	}
+	
+	if (( err = FLIGetFWRevision(fli_dev, &FLIPDF->FWRevision)))
+	{
+		IDMessage(mydev, "FLIGetFWRevision() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetFWRevision() failed. %s.\n", strerror((int)-err));
+		return;
+	}
+	
+	if (( err = FLIGetStepperPosition(fli_dev, &FLIPDF->current_pos)))
+	{
+		IDSetNumber(&FocuserNP, "FLIGetStepperPosition() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetStepperPosition() failed. %s.\n", strerror((int)-err));
+		return;
+	}
+  
+	currentPosition = FLIPDF->current_pos;
+
+	IDLog("Model: %s\n", FLIPDF->model);
+	IDLog("HW Revision %ld\n", FLIPDF->HWRevision);
+	IDLog("FW Revision %ld\n", FLIPDF->FWRevision);
+	IDLog("Initial focuser position %ld\n", FLIPDF->current_pos);
+	FocuserNP.s = IPS_OK;
+	IDSetNumber(&FocuserNP, NULL);
+	
+	IDLog("Exiting getBasicData()\n");
+  
+}
+
+void ISPoll(void *p)
+{
+  static int simMTC = 5;
+
+  p=p;
+  if (!isPDFConnected())
+  {
+      IEAddTimer (POLLMS, ISPoll, NULL);
+      return;
+  }
+
+
+  switch (FocuserNP.s)
+  {
+    case IPS_IDLE:
+    case IPS_OK:
+       break;
+  
+   
+   case IPS_BUSY:
+    /* Simulate that it takes 5 seconds to change positoin*/
+    if (simulation)
+    {
+        simMTC--;
+        if (simMTC == 0)
+        {
+           simMTC = 5;
+           currentPosition = targetPosition;
+           FocuserNP.s = IPS_OK;
+           IDSetNumber(&FocuserNP, "Focuser position %ld", targetPosition);
+           break;
+        }
+        IDSetNumber(&FocuserNP, NULL);
+        break;
+    }
+
+
+    /*if (( err = FLIGetFilterPos(fli_dev, &currentFilter)))
+	{
+                FocuserNP.s = IPS_ALERT;
+		IDSetNumber(&FocuserNP, "FLIGetFilterPos() failed. %s.", strerror((int)-err));
+		IDLog("FLIGetFilterPos() failed. %s.\n", strerror((int)-err));
+		return;
+	}
+
+        if (targetPosition == currentFilter)
+        {
+		FLIPDF->current_filter = currentFilter;
+		FocuserNP.s = IPS_OK;
+		IDSetNumber(&FocuserNP, "Filter set to slot #%2.0f", currentFilter);
+                return;
+        }
+       
+        IDSetNumber(&FocuserNP, NULL);*/
+	break;
+
+   case IPS_ALERT:
+    break;
+ }
+
+   IEAddTimer (POLLMS, ISPoll, NULL);
+
+}
+
+
+
+int getOnSwitch(ISwitchVectorProperty *sp)
+{
+  int i=0;
+ for (i=0; i < sp->nsp ; i++)
+ {
+   /*IDLog("Switch %s is %s\n", sp->sp[i].name, sp->sp[i].s == ISS_ON ? "On" : "Off");*/
+     if (sp->sp[i].s == ISS_ON)
+      return i;
+ }
+
+ return -1;
+}
+
+int checkPowerS(ISwitchVectorProperty *sp)
+{
+
+  if (simulation)
+   return 0;
+
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(sp->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the focuser is offline.", sp->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the focuser is offline.", sp->label);
+	
+    sp->s = IPS_IDLE;
+    IDSetSwitch(sp, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int checkPowerN(INumberVectorProperty *np)
+{
+  if (simulation)
+   return 0;
+
+  if (PowerSP.s != IPS_OK)
+  {
+     if (!strcmp(np->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the focuser is offline.", np->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the focuser is offline.", np->label);
+    
+    np->s = IPS_IDLE;
+    IDSetNumber(np, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int checkPowerT(ITextVectorProperty *tp)
+{
+   if (simulation)
+    return 0;
+
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(tp->label, ""))
+    	IDMessage (mydev, "Cannot change property %s while the focuser is offline.", tp->name);
+    else
+    	IDMessage (mydev, "Cannot change property %s while the focuser is offline.", tp->label);
+	
+    tp->s = IPS_IDLE;
+    IDSetText(tp, NULL);
+    return -1;
+  }
+
+  return 0;
+
+}
+
+void connectPDF()
+{
+	long err;
+	/* USB by default {USB, SERIAL, PARALLEL, INET} */
+	switch (PowerS[0].s)
+	{
+		case ISS_ON:
+			
+			if (simulation)
+			{
+	                        /* Success! */
+				PowerS[0].s = ISS_ON;
+				PowerS[1].s = ISS_OFF;
+				PowerSP.s = IPS_OK;
+				IDSetSwitch(&PowerSP, "Simulation PDF is online.");
+				IDLog("Simulation PDF is online.\n");
+				return;
+			}
+
+			IDLog("Current portSwitch is %d\n", portSwitchIndex);
+			IDLog("Attempting to find the device in domain %ld\n", Domains[portSwitchIndex]);
+
+			if (findPDF(Domains[portSwitchIndex]))
+			{
+				PowerSP.s = IPS_IDLE;
+				PowerS[0].s = ISS_OFF;
+				PowerS[1].s = ISS_ON;
+				IDSetSwitch(&PowerSP, "Error: no focusers were detected.");
+				IDLog("Error: no focusers were detected.\n");
+				return;
+			}
+			
+			if ((err = FLIOpen(&fli_dev, FLIPDF->name, FLIPDF->domain | FLIDEVICE_FOCUSER)))
+			{
+				PowerSP.s = IPS_IDLE;
+				PowerS[0].s = ISS_OFF;
+				PowerS[1].s = ISS_ON;
+				IDSetSwitch(&PowerSP, "Error: FLIOpen() failed. %s.", strerror( (int) -err));
+				IDLog("Error: FLIOpen() failed. %s.\n", strerror( (int) -err));
+				return;
+			}
+
+			/* Success! */
+			PowerS[0].s = ISS_ON;
+			PowerS[1].s = ISS_OFF;
+			PowerSP.s = IPS_OK;
+			IDSetSwitch(&PowerSP, "Focuser is online. Retrieving basic data.");
+			IDLog("Focuser is online. Retrieving basic data.\n");
+			getBasicData();
+
+			break;
+		
+		case ISS_OFF:
+
+			if (simulation)
+			{
+				PowerS[0].s = ISS_OFF;
+				PowerS[1].s = ISS_ON;
+				PowerSP.s = IPS_IDLE;
+				IDSetSwitch(&PowerSP, "Focuser is offline.");
+				return;
+			}
+
+			PowerS[0].s = ISS_OFF;
+			PowerS[1].s = ISS_ON;
+			PowerSP.s = IPS_IDLE;
+			if ((err = FLIClose(fli_dev))) 
+			{
+				PowerSP.s = IPS_ALERT;
+				IDSetSwitch(&PowerSP, "Error: FLIClose() failed. %s.", strerror( (int) -err));
+				IDLog("Error: FLIClose() failed. %s.\n", strerror( (int) -err));
+				return;
+			}
+			IDSetSwitch(&PowerSP, "Focuser is offline.");
+			break;
+	}
+}
+
+/* isPDFConnected: return 1 if we have a connection, 0 otherwise */
+int isPDFConnected(void)
+{
+   if (simulation)
+     return 1;
+
+   return ((PowerS[0].s == ISS_ON) ? 1 : 0);
+}
+
+int findPDF(flidomain_t domain)
+{
+	char **devlist;
+	long err;
+	
+	IDLog("In findPDF, the domain is %ld\n", domain);
+	
+	if (( err = FLIList(domain | FLIDEVICE_FOCUSER, &devlist)))
+	{
+		IDLog("FLIList() failed. %s\n", strerror((int)-err));
+		return -1;
+	}
+	
+	if (devlist != NULL && devlist[0] != NULL)
+	{
+		int i;
+
+		IDLog("Trying to allocate memory to FLIPDF\n");
+		if ((FLIPDF = malloc (sizeof (pdf_t))) == NULL)
+		{
+			IDLog("malloc() failed.\n");
+			return -1;
+		}
+		
+		for (i = 0; devlist[i] != NULL; i++)
+		{
+			int j;
+	
+			for (j = 0; devlist[i][j] != '\0'; j++)
+				if (devlist[i][j] == ';')
+				{
+					devlist[i][j] = '\0';
+					break;
+				}
+		}
+
+		FLIPDF->domain = domain;
+		
+		/* Each driver handles _only_ one camera for now */
+		switch (domain)
+		{
+			case FLIDOMAIN_PARALLEL_PORT:
+				FLIPDF->dname = strdup("parallel port");
+				break;
+	
+			case FLIDOMAIN_USB:
+				FLIPDF->dname = strdup("USB");
+				break;
+	
+			case FLIDOMAIN_SERIAL:
+				FLIPDF->dname = strdup("serial");
+				break;
+	
+			case FLIDOMAIN_INET:
+				FLIPDF->dname = strdup("inet");
+				break;
+	
+			default:
+				FLIPDF->dname = strdup("Unknown domain");
+		}
+		
+		IDLog("Domain set OK\n");
+		
+		FLIPDF->name = strdup(devlist[0]);
+				
+		if ((err = FLIFreeList(devlist)))
+		{
+			IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err));
+			return -1;
+		}
+      
+	} /* end if */
+	else
+	{
+		if ((err = FLIFreeList(devlist)))
+		{
+			IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err));
+			return -1;
+		}
+		
+		return -1;
+	}
+
+	IDLog("FindPDF() finished successfully.\n");
+	return 0;
+}
Index: /BAORadio/libindi/v1/drivers/focuser/robofocus.c
===================================================================
--- /BAORadio/libindi/v1/drivers/focuser/robofocus.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/focuser/robofocus.c	(revision 500)
@@ -0,0 +1,1307 @@
+ #if 0
+    Robofocus driver
+    Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+/* Standard headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* INDI Core headers */
+/* indidevapi.h contains API declerations */
+#include "indidevapi.h"
+
+/* INDI Eventloop mechanism */
+#include "eventloop.h"
+
+/* INDI Common Routines/RS232 */
+#include "indicom.h"
+
+#include "robofocusdriver.h"
+
+/* Definitions */
+
+#define mydev	           "Robofocus"     /* Device name */
+#define CONNECTION_GROUP   "Connection"  /* Group name */
+#define MOTION_GROUP       "Motion"
+ 
+#define currentSpeed            SpeedN[0].value
+#define currentPosition         PositionN[0].value
+#define currentTemperature      TemperatureN[0].value
+#define currentBacklash         SetBacklashN[0].value
+#define currentDuty             SettingsN[0].value
+#define currentDelay            SettingsN[1].value
+#define currentTicks            SettingsN[2].value
+#define currentRelativeMovement RelMovementN[0].value
+#define currentAbsoluteMovement AbsMovementN[0].value
+#define currentSetBacklash      SetBacklashN[0].value
+#define currentMinPosition      MinMaxPositionN[0].value
+#define currentMaxPosition      MinMaxPositionN[1].value
+#define currentMaxTravel        MaxTravelN[0].value
+
+int fd; /* Rs 232 file handle */
+int wp ;  /* Work proc ID */
+
+
+/* Function protptypes */
+
+void connectRobofocus(void);
+
+static void ISInit() ;
+void ISWorkProc (void) ;
+int updateRFPosition(int fd, double *value) ;
+int updateRFTemperature(int fd, double *value) ;
+int updateRFBacklash(int fd, double *value) ;
+int updateRFFirmware(int fd, char *rf_cmd) ;
+int updateRFMotorSettings(int fd, double *duty, double *delay, double *ticks) ;
+int updateRFPositionRelativeInward(int fd, double *value) ;
+int updateRFPositionRelativeOutward(int fd, double *value) ;
+int updateRFPositionAbsolute(int fd, double *value) ;
+int updateRFPowerSwitches(int fd, int s, int  i, int *cur_s1LL, int *cur_s2LR, int *cur_s3RL, int *cur_s4RR) ;
+int updateRFMaxPosition(int fd, double *value) ;
+int updateRFSetPosition(int fd, double *value) ;
+
+/* operational info */
+
+
+/* RS 232 Connection */
+
+static ISwitch PowerS[] = {
+  {"CONNECT", "Connect", ISS_OFF, 0, 0},                         
+  {"DISCONNECT", "Disconnect", ISS_OFF, 0, 0},
+};
+
+static ISwitchVectorProperty PowerSP    = { 
+  mydev			/* Device name */
+  , "CONNECTION"  	/* Property name */
+  , "Connection"	/* Property label */
+  , CONNECTION_GROUP	/* Property group */
+  , IP_RW		/* Property premission, it's both read and write */
+  , ISR_1OFMANY	        /* Switch behavior. Only 1 of many switches are allowed to be on at the same time */
+  , 0			/* Timeout, 0 seconds */
+  , IPS_IDLE		/* Initial state is idle */
+  , PowerS		/* Switches comprimising this vector that we defined above */
+  , NARRAY(PowerS)	/* Number of Switches. NARRAY is defined in indiapi.h */
+  , ""			/* Timestamp, set to 0 */
+  , 0};			/* auxiluary, set to 0 for now */
+
+/* Serial */
+
+static IText PortT[]= {{"PORT", "Port", 0, 0, 0, 0}}; /* Attention malloc */
+
+static ITextVectorProperty PortTP= { 
+  mydev, 
+  "DEVICE_PORT", 
+  "Ports", 
+  CONNECTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  PortT, 
+  NARRAY(PortT), 
+  "", 
+  0
+} ;
+
+/* Focuser temperature */
+
+static INumber TemperatureN[] = {
+
+  { "TEMPERATURE", "Celsius", "%6.2f", 0, 65000., 0., 10000., 0, 0, 0},				
+} ;
+
+static INumberVectorProperty TemperatureNP = { 
+  mydev, 
+  "FOCUS_TEMPERATURE", 
+  "Temperature", 
+  CONNECTION_GROUP, 
+  IP_RO, 
+  0, 
+  IPS_IDLE, 
+  TemperatureN, 
+  NARRAY(TemperatureN), 
+  "", 
+  0
+} ;
+
+/* Settings of the Robofocus */
+
+static INumber SettingsN[] = {
+
+  { "Duty cycle", "Duty cycle", "%6.0f", 0., 255., 0., 1., 0, 0, 0},
+  { "Step delay", "Step delay", "%6.0f", 0., 255., 0., 1., 0, 0, 0},
+  { "Motor Steps", "Motor steps per tick", "%6.0f", 0, 255., 0., 1., 0, 0, 0},
+};
+
+static INumberVectorProperty SettingsNP = { 
+  mydev, 
+  "FOCUS_SETTINGS", 
+  "Settings", 
+  CONNECTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  SettingsN, 
+  NARRAY(SettingsN), 
+  "", 
+  0
+} ;
+
+/* Power Switches of the Robofocus */
+static ISwitch PowerSwitchesS[]= {
+
+  {"1", "Switch 1", ISS_OFF, 0, 0}, 
+  {"2", "Switch 2", ISS_OFF, 0, 0}, 
+  {"3", "Switch 3", ISS_OFF, 0, 0}, 
+  {"4", "Switch 4", ISS_ON , 0, 0}
+};
+
+static ISwitchVectorProperty PowerSwitchesSP      = { 
+  mydev, 
+  "SWITCHES", 
+  "Power", 
+  CONNECTION_GROUP, 
+  IP_RW,
+  ISR_1OFMANY, 
+  0, 
+  IPS_IDLE, 
+  PowerSwitchesS, 
+  NARRAY(PowerSwitchesS), 
+  "", 
+  0 
+} ;
+
+/* Direction of the focuser movement - or IGNORE */
+
+static ISwitch DirectionS[] = {
+
+  {"FOCUSIN", "inward", ISS_OFF, 0, 0},	
+  {"FOCUSOUT", "outward", ISS_OFF, 0, 0},	
+  {"FOCUSIGNORE", "IGNORE", ISS_ON, 0, 0},
+} ;
+
+static ISwitchVectorProperty DirectionSP    = { 
+ 
+  mydev, 
+  "DIRECTION", 
+  "Movement",
+  MOTION_GROUP,	   
+  IP_RW,	
+  ISR_ATMOST1,
+  0,
+  IPS_IDLE,
+  DirectionS,
+  NARRAY(DirectionS),
+  "",	
+  0
+} ;	
+
+/* Robofocus should stay within these limits */
+
+static INumber MinMaxPositionN[] = {
+
+  { "MINPOS", "Minimum Tick", "%6.0f", 1., 65000., 0., 100., 0, 0, 0},
+  { "MAXPOS", "Maximum Tick", "%6.0f", 1., 65000., 0., 55000., 0, 0, 0},
+};
+
+static INumberVectorProperty MinMaxPositionNP = { 
+  mydev, 
+  "FOCUS_MINMXPOSITION", 
+  "Extrema", 
+  MOTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  MinMaxPositionN, 
+  NARRAY(MinMaxPositionN), 
+  "", 
+  0
+};
+
+static INumber MaxTravelN[] = {
+
+  { "MAXTRAVEL", "Maximum travel", "%6.0f", 1., 64000., 0., 10000., 0, 0, 0},
+};
+
+static INumberVectorProperty MaxTravelNP = { 
+  mydev, 
+  "FOCUS_MAXTRAVEL", 
+  "Max. travel", 
+  MOTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  MaxTravelN, 
+  NARRAY(MaxTravelN), 
+  "", 
+  0
+};
+
+/* Set Robofocus position register to the this position */
+
+static INumber SetRegisterPositionN[] = {
+
+  /* 64000: see Robofocus manual */
+  { "SETPOS", "Position", "%6.0f", 0, 64000., 0., 0., 0, 0, 0},	
+};
+
+static INumberVectorProperty SetRegisterPositionNP = { 
+  mydev, 
+  "FOCUS_REGISTERPOSITION", 
+  "Set register", 
+  MOTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  SetRegisterPositionN, 
+  NARRAY(SetRegisterPositionN), 
+  "", 
+  0
+};
+/* Set Robofocus' backlash behaviour */
+
+static INumber SetBacklashN[] = {
+
+  { "SETBACKLASH", "Backlash", "%6.0f", -255., 255., 0., 0., 0, 0, 0},
+};
+
+static INumberVectorProperty SetBacklashNP = { 
+  mydev, 
+  "FOCUS_Backlash", 
+  "Set register", 
+  MOTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  SetBacklashN, 
+  NARRAY(SetBacklashN), 
+  "", 
+  0
+};
+
+/* Speed */
+static INumber SpeedN[] = {
+
+  {"SPEED", "Ticks/sec", "%6.0f",0., 999., 0., 50., 0, 0, 0},
+} ;
+
+static INumberVectorProperty SpeedNP = { 
+  mydev, 
+  "FOCUS_SPEED", 
+  "Speed", 
+  MOTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  SpeedN, 
+  NARRAY(SpeedN), 
+  "", 
+  0
+} ;
+
+
+/*  Timer */
+static INumber TimerN[] = {
+
+  {"TIMER","sec", "%6.0f",0., 999., 0., 0., 0, 0, 0},
+} ;
+
+static INumberVectorProperty TimerNP = { 
+
+  mydev, 
+  "FOCUS_TIMER", 
+  "Timer", 
+  MOTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  TimerN, 
+  NARRAY(TimerN), 
+  "", 
+  0
+} ;
+
+/* Robofocus` position (RO) */
+
+static INumber PositionN[] = {
+
+  { "POSITION", "Tick", "%6.0f", 0, 65000., 0., 10000., 0, 0, 0},				
+} ;
+
+static INumberVectorProperty PositionNP = { 
+  mydev, 
+  "FOCUS_POSITION", 
+  "Position", 
+  MOTION_GROUP, 
+  IP_RO, 
+  0, 
+  IPS_IDLE, 
+  PositionN, 
+  NARRAY(PositionN), 
+  "", 
+  0
+} ;
+
+/* Relative and absolute movement */
+static INumber RelMovementN[] = {
+
+  { "RELMOVEMENT", "Ticks", "%6.0f", -65000., 65000., 0., 100., 0, 0, 0},
+				
+};
+
+static INumberVectorProperty RelMovementNP = { 
+
+  mydev, 
+  "FOCUS_RELMOVEMENT", 
+  "Relative goto", 
+  MOTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  RelMovementN, 
+  NARRAY(RelMovementN), 
+  "", 
+  0
+} ;
+
+
+static INumber AbsMovementN[] = {
+
+  { "ABSMOVEMENT", "Tick", "%6.0f", 0, 65000., 0., 10000., 0, 0, 0},				
+} ;
+
+static INumberVectorProperty AbsMovementNP = { 
+  mydev, 
+  "FOCUS_ABSMOVEMENT", 
+  "Absolute goto", 
+  MOTION_GROUP, 
+  IP_RW, 
+  0, 
+  IPS_IDLE, 
+  AbsMovementN, 
+  NARRAY(AbsMovementN), 
+  "", 
+  0
+} ;
+
+
+/* Initlization routine */
+static void ISInit() {
+
+  static int isInit=0;		/* set once mountInit is called */
+  /*fprintf(stderr, "ISInit\n") ;*/
+
+  if (isInit)
+    return;
+
+  /* stolen from temmadriver.c :-)*/
+
+  PortT[0].text = malloc( 13);
+  if (!PortT[0].text ){
+    fprintf(stderr,"Memory allocation error");
+    return;
+  }
+  IUSaveText( &PortT[0],  "/dev/ttyUSB0");
+
+  /* fprintf(stderr, "PORT:%s<\n", PortT->text) ; */
+  IDSetText( &PortTP, NULL) ;
+
+  fd=-1;
+  isInit = 1;
+}
+
+
+void ISWorkProc () {
+
+  char firmeware[]="FV0000000" ;
+  int ret = -1 ;
+  int cur_s1LL=0 ;
+  int cur_s2LR=0 ;
+  int cur_s3RL=0 ;
+  int cur_s4RR=0 ;
+
+  /* fprintf(stderr, "ISWorkProc\n") ; */
+
+  if (PowerS[0].s == ISS_ON) {
+    switch (PowerSP.s) {
+
+    case IPS_IDLE:
+    case IPS_OK:
+
+      if((ret= updateRFFirmware(fd, firmeware)) < 0) {
+        /* This would be the end*/
+	IDMessage( mydev, "Unknown error while reading Robofocus firmware\n");
+	break;
+      }
+      PowerSP.s = IPS_OK;
+      IDSetSwitch(&PowerSP, NULL);
+
+
+      if((ret= updateRFPosition(fd, &currentPosition)) < 0) {
+ 	PositionNP.s = IPS_ALERT;
+	IDSetNumber(&PositionNP, "Unknown error while reading  Robofocus position: %d", ret);
+	break;
+      }
+      PositionNP.s = IPS_OK;
+      IDSetNumber(&PositionNP, NULL); 
+
+      if(( ret= updateRFTemperature(fd, &currentTemperature)) < 0) {
+	TemperatureNP.s = IPS_ALERT;
+	IDSetNumber(&TemperatureNP, "Unknown error while reading  Robofocus temperature");
+	break;
+      }
+      TemperatureNP.s = IPS_OK;
+      IDSetNumber(&TemperatureNP, NULL);
+
+
+      currentBacklash= BACKLASH_READOUT ;
+      if(( ret= updateRFBacklash(fd, &currentBacklash)) < 0) {
+	SetBacklashNP.s = IPS_ALERT;
+	IDSetNumber(&SetBacklashNP, "Unknown error while reading  Robofocus backlash");
+	break;
+      }
+      SetBacklashNP.s = IPS_OK;
+      IDSetNumber(&SetBacklashNP, NULL);
+
+      currentDuty= currentDelay= currentTicks=0 ;
+
+      if(( ret= updateRFMotorSettings(fd, &currentDuty, &currentDelay, &currentTicks )) < 0) {
+	SettingsNP.s = IPS_ALERT;
+	IDSetNumber(&SettingsNP, "Unknown error while reading  Robofocus motor settings");
+	break;
+      }
+      SettingsNP.s = IPS_OK;
+      IDSetNumber(&SettingsNP, NULL);
+
+      if(( ret= updateRFPowerSwitches(fd,  -1, -1,  &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0) {
+	PowerSwitchesSP.s = IPS_ALERT;
+	IDSetSwitch(&PowerSwitchesSP, "Unknown error while reading  Robofocus power swicht settings");
+	break;
+      }
+
+      PowerSwitchesS[0].s= PowerSwitchesS[1].s= PowerSwitchesS[2].s= PowerSwitchesS[3].s= ISS_OFF ;
+
+      if(cur_s1LL== ISS_ON) {
+
+	PowerSwitchesS[0].s= ISS_ON ;
+      } 
+      if(cur_s2LR== ISS_ON) {
+  
+	PowerSwitchesS[1].s= ISS_ON ;
+      }
+      if(cur_s3RL== ISS_ON) {
+
+	PowerSwitchesS[2].s= ISS_ON ;
+      } 
+      if(cur_s4RR== ISS_ON) {
+
+	PowerSwitchesS[3].s= ISS_ON ;
+      }
+      PowerSwitchesSP.s = IPS_OK ;  
+      IDSetSwitch(&PowerSwitchesSP, NULL);	
+
+
+      currentMaxTravel= MAXTRAVEL_READOUT ;
+      if(( ret= updateRFMaxPosition(fd, &currentMaxTravel)) < 0) {
+	MaxTravelNP.s = IPS_ALERT;
+	IDSetNumber(&MaxTravelNP, "Unknown error while reading  Robofocus maximum travel");
+	break;
+      }
+      MaxTravelNP.s = IPS_OK;
+      IDSetNumber(&MaxTravelNP, NULL);
+
+    case IPS_BUSY:
+
+      break;
+	        
+    case IPS_ALERT:
+      break;
+    }
+  }	
+}
+
+/* void ISGetProperties (const char *dev)
+*  INDI will call this function when the client inquires about the device properties.
+*  Here we will use IDxxx functions to define new properties to the client */
+void ISGetProperties (const char *dev)
+{ 
+  /* fprintf(stderr, "ISGetProperties\n") ; */
+
+   /* #1 Let's make sure everything has been initialized properly */
+   ISInit();
+  
+  /* #2 Let's make sure that the client is asking for the properties of our device, otherwise ignore */
+  if (dev && strcmp (mydev, dev))
+    return;
+    
+  /* #3 Tell the client to create a new Switch property PowerSP */
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefText(&PortTP, NULL);
+  IDDefSwitch(&PowerSwitchesSP, NULL);
+  IDDefNumber(&TemperatureNP, NULL);
+  IDDefNumber(&SettingsNP, NULL);
+
+  IDDefNumber(&MinMaxPositionNP, NULL);
+  IDDefNumber(&MaxTravelNP, NULL);
+  IDDefNumber(&SetRegisterPositionNP, NULL);
+  IDDefNumber(&SetBacklashNP, NULL);
+  IDDefSwitch(&DirectionSP, NULL);
+
+  IDDefNumber(&PositionNP, NULL);
+  IDDefNumber(&SpeedNP, NULL);
+  IDDefNumber(&TimerNP, NULL);
+  IDDefNumber(&AbsMovementNP, NULL);
+  IDDefNumber(&RelMovementNP, NULL);
+}
+  
+/* void ISNewSwitch(...)
+ * INDI will call this function when the client wants to set a new state of existing switches 
+ ** Parameters **
+ * dev: the device name
+ * name: the property name the client wants to update
+ * states: an array of states of members switches (ISS_ON and ISS_OFF)
+ * names: names of the switches. The names are parallel to the states. That is, member names[0] has a state states[0], and so on...
+ * n: number of switches to update, which is also the dimension of *states and names[]
+*/
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) {
+
+  /* fprintf(stderr, "ISNewSwitch\n") ; */
+
+  /* #1 Let's make sure everything has been initialized properly */
+  ISInit();
+	
+  /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */
+  if (dev && strcmp (dev, mydev))
+    return;
+	    
+  /* #3 Now let's check if the property the client wants to change is the PowerSP (name: CONNECTION) property*/
+  if (!strcmp (name, PowerSP.name)) {
+
+
+    /* If the clients wants to update this property, let's perform the following */
+	  
+    /* A. We reset all switches (in this case CONNECT and DISCONNECT) to ISS_OFF */
+    IUResetSwitch(&PowerSP);
+
+    /* B. We update the switches by sending their names and updated states IUUpdateSwitch function */
+    IUUpdateSwitch(&PowerSP, states, names, n);
+	  
+    /* C. We try to establish a connection to our device */
+    connectRobofocus();
+    return ;
+  }
+
+  if (!strcmp (name, PowerSwitchesSP.name)) {
+    int ret= -1 ;
+    int nset= 0 ;
+    int i= 0 ;
+    int new_s= -1 ;
+    int new_sn= -1 ;
+    int cur_s1LL=0 ;
+    int cur_s2LR=0 ;
+    int cur_s3RL=0 ;
+    int cur_s4RR=0 ;
+
+    ISwitch *sp ;
+
+    PowerSwitchesSP.s = IPS_BUSY ;
+    IDSetSwitch(&PowerSwitchesSP, NULL) ;
+
+
+    for( nset = i = 0; i < n; i++) {
+      /* Find numbers with the passed names in the SettingsNP property */
+      sp = IUFindSwitch (&PowerSwitchesSP, names[i]) ;
+      
+      /* If the state found is  (PowerSwitchesS[0]) then process it */
+
+      if( sp == &PowerSwitchesS[0]){
+	      
+
+	new_s = (states[i]) ;
+	new_sn= 0; 
+	nset++ ;
+      } else if( sp == &PowerSwitchesS[1]){
+
+ 	new_s = (states[i]) ;
+	new_sn= 1; 
+	nset++ ;
+      } else if( sp == &PowerSwitchesS[2]){
+
+ 	new_s = (states[i]) ;
+	new_sn= 2; 
+	nset++ ;
+      } else if( sp == &PowerSwitchesS[3]){
+
+ 	new_s = (states[i]) ;
+	new_sn= 3; 
+	nset++ ;
+      }
+    }
+    if (nset == 1) {
+      cur_s1LL= cur_s2LR= cur_s3RL= cur_s4RR= 0 ;
+
+      if(( ret= updateRFPowerSwitches(fd, new_s, new_sn, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0) {
+
+	PowerSwitchesSP.s = IPS_ALERT;
+	IDSetSwitch(&PowerSwitchesSP, "Unknown error while reading  Robofocus power swicht settings");
+	return ;
+      }
+    } else {
+      /* Set property state to idle */
+      PowerSwitchesSP.s = IPS_IDLE ;
+		
+      IDSetNumber(&SettingsNP, "Power switch settings absent or bogus.");
+      return ;
+    }
+
+   
+    PowerSwitchesS[0].s= PowerSwitchesS[1].s= PowerSwitchesS[2].s= PowerSwitchesS[3].s= ISS_OFF ;
+ 
+    if(cur_s1LL== ISS_ON) {
+
+
+      PowerSwitchesS[0].s= ISS_ON ;
+    } 
+    if(cur_s2LR== ISS_ON) {
+
+      PowerSwitchesS[1].s= ISS_ON ;
+    }
+    if(cur_s3RL== ISS_ON) {
+
+      PowerSwitchesS[2].s= ISS_ON ;
+    } 
+    if(cur_s4RR== ISS_ON) {
+
+      PowerSwitchesS[3].s= ISS_ON ;
+    }
+    PowerSwitchesSP.s = IPS_OK ;  
+    IDSetSwitch(&PowerSwitchesSP, "Setting power switches");
+
+   
+  }
+}
+
+
+/* void ISNewText(...)
+ * INDI will call this function when the client wants to update an existing text.
+ ** Parameters **
+ 
+ * dev: the device name
+ * name: the property name the client wants to update
+ * texts: an array of texts.
+ * names: names of the members. The names are parallel to the texts.
+ * n: number of texts to update, which is also the dimension of *texts and names[]
+*/
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) {
+
+  /* fprintf(stderr, "ISNewText\n") ; */
+
+  /* #1 Let's make sure everything has been initialized properly */
+  ISInit();
+
+  /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */
+  if (dev && strcmp (dev, mydev))
+    return;
+ 
+
+  dev=dev; names=names; n=n;
+
+  if (!strcmp(name, PortTP.name)) {
+    IUSaveText(&PortT[0], texts[0]);
+    PortTP.s = IPS_OK;
+    IDSetText(&PortTP, NULL);
+    return;
+  }
+
+  return;	
+}
+
+/* void ISNewNumber(...)
+ * INDI will call this function when the client wants to update an existing number.
+ ** Parameters **
+ 
+ * dev: the device name
+ * name: the property name the client wants to update
+ * values: an array of values.
+ * names: names of the members. The names are parallel to the values.
+ * n: number of numbers to update, which is the dimension of *numbers and names[]
+*/
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) {
+  
+  int i, nset;
+ 
+  /* fprintf(stderr, "ISNewNumber\n") ; */
+
+  /* Make sure to initialize */
+  ISInit();
+
+  /* ignore if not ours */
+  if (strcmp (dev, mydev))
+    return;
+
+
+  if (!strcmp (name, SettingsNP.name)) {
+    /* new speed */
+    double new_duty = 0 ;
+    double new_delay = 0 ;
+    double new_ticks = 0 ;
+    int ret = -1 ;
+	    
+    /* Check power, if it is off, then return */
+    if (PowerS[0].s != ISS_ON){
+      SettingsNP.s = IPS_IDLE;
+      IDSetNumber(&SettingsNP, "Power is off");
+      return;
+    }
+	    
+    for (nset = i = 0; i < n; i++){
+      /* Find numbers with the passed names in the SettingsNP property */
+      INumber *eqp = IUFindNumber (&SettingsNP, names[i]);
+      
+      /* If the number found is  (SettingsN[0]) then process it */
+      if (eqp == &SettingsN[0]){
+	      
+	new_duty = (values[i]);
+	nset += new_duty >= 0 && new_duty <= 255;
+      } else if  (eqp == &SettingsN[1]){
+
+ 	new_delay = (values[i]);
+	nset += new_delay >= 0 && new_delay <= 255;
+      } else if  (eqp == &SettingsN[2]){
+
+	new_ticks = (values[i]);
+	nset += new_ticks >= 0 && new_ticks <= 255;
+      }
+    }
+	    
+    /* Did we process the three numbers? */
+    if (nset == 3) {
+		
+      /* Set the robofocus state to BUSY */
+      SettingsNP.s = IPS_BUSY;
+		
+		
+      IDSetNumber(&SettingsNP, NULL);
+
+      if(( ret= updateRFMotorSettings(fd,  &new_duty, &new_delay, &new_ticks))< 0) {
+	
+	IDSetNumber(&SettingsNP, "Changing to new settings failed");
+	return ;
+      } ; 
+
+      currentDuty = new_duty ;
+      currentDelay= new_delay ;
+      currentTicks= new_ticks ;
+
+      SettingsNP.s = IPS_OK;
+      IDSetNumber(&SettingsNP, "Motor settings are now  %3.0f %3.0f %3.0f", currentDuty, currentDelay, currentTicks);
+
+    } else {
+      /* Set property state to idle */
+      SettingsNP.s = IPS_IDLE;
+		
+      IDSetNumber(&SettingsNP, "Settings absent or bogus.");
+      return ;
+    }
+  }
+
+  if (!strcmp (name, RelMovementNP.name)) {
+
+    double cur_rpos=0 ;
+    double new_rpos = 0 ;
+    int nset = 0;
+    int ret= -1 ;
+
+    if (PowerS[0].s != ISS_ON){
+      RelMovementNP.s = IPS_IDLE;
+      IDSetNumber(&RelMovementNP, "Power is off");
+      return;
+    }
+    for (nset = i = 0; i < n; i++) {
+      /* Find numbers with the passed names in the RelMovementNP property */
+      INumber *eqp = IUFindNumber (&RelMovementNP, names[i]);
+		
+      /* If the number found is RelMovement (RelMovementN[0]) then process it */
+      if (eqp == &RelMovementN[0]){
+	      
+	cur_rpos= new_rpos = (values[i]);
+        
+        /* CHECK 2006-01-26, limmits are relative to the actual position */
+	nset += new_rpos >= -0xffff && new_rpos <= 0xffff;
+      }
+
+      if (nset == 1) {
+
+	/* Set the robofocus state to BUSY */
+	RelMovementNP.s = IPS_BUSY;
+	IDSetNumber(&RelMovementNP, NULL);
+
+	if((currentPosition + new_rpos < currentMinPosition) || (currentPosition + new_rpos > currentMaxPosition)) {
+
+	  RelMovementNP.s = IPS_ALERT ;
+	  IDSetNumber(&RelMovementNP, "Value out of limits %5.0f", currentPosition +  new_rpos);
+	  return ;
+	}
+
+	if( new_rpos > 0) {
+
+	  ret= updateRFPositionRelativeOutward(fd, &new_rpos) ;
+
+	} else {
+
+          new_rpos= -new_rpos ;
+	  ret= updateRFPositionRelativeInward(fd, &new_rpos) ;
+	}
+	
+	if( ret < 0) {
+
+	  RelMovementNP.s = IPS_IDLE;
+	  IDSetNumber(&RelMovementNP, "Read out of the relative movement failed, trying to recover position.");
+	  if((ret= updateRFPosition(fd, &currentPosition)) < 0) {
+	 
+
+	    PositionNP.s = IPS_ALERT;
+	    IDSetNumber(&PositionNP, "Unknown error while reading  Robofocus position: %d", ret);
+	    return ;
+	  }
+	  PositionNP.s = IPS_ALERT;
+	  IDSetNumber(&PositionNP, "Robofocus position recovered %5.0f", currentPosition); 
+
+	  IDMessage( mydev, "Robofocus position recovered resuming normal operation");
+
+          /* We have to leave here, because new_rpos is not set */
+          return ;
+	}
+
+	RelMovementNP.s = IPS_OK;
+        currentRelativeMovement= cur_rpos ;
+	IDSetNumber(&RelMovementNP, NULL) ;
+
+	AbsMovementNP.s = IPS_OK;
+        currentAbsoluteMovement=  new_rpos - cur_rpos ;
+	IDSetNumber(&AbsMovementNP, NULL) ;
+
+	PositionNP.s = IPS_OK;
+        currentPosition= new_rpos ;
+	IDSetNumber(&PositionNP,  "Last position was %5.0f", currentAbsoluteMovement);
+
+     } else {
+
+	RelMovementNP.s = IPS_IDLE;
+	IDSetNumber(&RelMovementNP, "Need exactly one parameter.");
+
+	return ;
+      }
+    }
+  }
+
+  if (!strcmp (name, AbsMovementNP.name)) {
+
+    double new_apos = 0 ;
+    int nset = 0;
+    int ret= -1 ;
+
+    if (PowerS[0].s != ISS_ON){
+      AbsMovementNP.s = IPS_IDLE;
+      IDSetNumber(&AbsMovementNP, "Power is off");
+      return;
+    }
+    for (nset = i = 0; i < n; i++) {
+      /* Find numbers with the passed names in the AbsMovementNP property */
+      INumber *eqp = IUFindNumber (&AbsMovementNP, names[i]);
+      
+      /* If the number found is AbsMovement (AbsMovementN[0]) then process it */
+      if (eqp == &AbsMovementN[0]){
+	
+	new_apos = (values[i]);
+	
+        /* limits are absolute to the actual position */
+	nset += new_apos >= 0 && new_apos <= 0xffff;
+      }
+
+      if (nset == 1) {
+
+	/* Set the robofocus state to BUSY */
+	AbsMovementNP.s = IPS_BUSY;
+	IDSetNumber(&AbsMovementNP, NULL);
+
+	if((new_apos < currentMinPosition) || (new_apos > currentMaxPosition)) {
+
+	  AbsMovementNP.s = IPS_ALERT ;
+	  IDSetNumber(&AbsMovementNP, "Value out of limits  %5.0f", new_apos);
+	  return ;
+	}
+	
+	if(( ret= updateRFPositionAbsolute(fd, &new_apos)) < 0) {
+
+	  AbsMovementNP.s = IPS_IDLE;
+	  IDSetNumber(&AbsMovementNP, "Read out of the absolute movement failed %3d, trying to recover position.", ret);
+
+	  if((ret= updateRFPosition(fd, &currentPosition)) < 0) {
+ 
+	    PositionNP.s = IPS_ALERT;
+	    IDSetNumber(&PositionNP, "Unknown error while reading  Robofocus position: %d.", ret);
+
+	    return ;
+	  }
+
+	  PositionNP.s = IPS_OK;
+	  IDSetNumber(&PositionNP, "Robofocus position recovered %5.0f", currentPosition); 
+	  IDMessage( mydev, "Robofocus position recovered resuming normal operation");
+          /* We have to leave here, because new_apos is not set */
+          return ;
+	}
+
+        currentAbsoluteMovement=  currentPosition ;
+	AbsMovementNP.s = IPS_OK;
+	IDSetNumber(&AbsMovementNP, NULL) ;
+
+	PositionNP.s = IPS_OK;
+        currentPosition= new_apos ;
+	IDSetNumber(&PositionNP,  "Absolute position was  %5.0f", currentAbsoluteMovement);
+
+      } else {
+	
+	AbsMovementNP.s = IPS_IDLE;
+	IDSetNumber(&RelMovementNP, "Need exactly one parameter.");
+ 
+	return ;
+      }
+    }
+  }
+
+  if (!strcmp (name, SetBacklashNP.name)) {
+
+    double new_back = 0 ;
+    int nset = 0;
+    int ret= -1 ;
+
+    if (PowerS[0].s != ISS_ON){
+      SetBacklashNP.s = IPS_IDLE;
+      IDSetNumber(&SetBacklashNP, "Power is off");
+      return;
+    }
+    for (nset = i = 0; i < n; i++) {
+      /* Find numbers with the passed names in the SetBacklashNP property */
+      INumber *eqp = IUFindNumber (&SetBacklashNP, names[i]);
+      
+      /* If the number found is SetBacklash (SetBacklashN[0]) then process it */
+      if (eqp == &SetBacklashN[0]){
+	
+	new_back = (values[i]);
+	
+        /* limits */
+	nset += new_back >= -0xff && new_back <= 0xff;
+      }
+
+      if (nset == 1) {
+
+	/* Set the robofocus state to BUSY */
+	SetBacklashNP.s = IPS_BUSY;
+	IDSetNumber(&SetBacklashNP, NULL);
+	
+	if(( ret= updateRFBacklash(fd, &new_back)) < 0) {
+
+	  SetBacklashNP.s = IPS_IDLE;
+	  IDSetNumber(&SetBacklashNP, "Setting new backlash failed.");
+	 
+	  return ;
+	} 
+	
+        currentSetBacklash=  new_back ;
+	SetBacklashNP.s = IPS_OK;
+	IDSetNumber(&SetBacklashNP, "Backlash is now  %3.0f", currentSetBacklash) ;
+      } else {
+	
+	SetBacklashNP.s = IPS_IDLE;
+	IDSetNumber(&SetBacklashNP, "Need exactly one parameter.");
+
+	return ;
+      }
+    }
+  }
+  
+  if (!strcmp (name, MinMaxPositionNP.name)) {
+    /* new positions */
+    double new_min = 0 ;
+    double new_max = 0 ;
+  
+	    
+    /* Check power, if it is off, then return */
+    if (PowerS[0].s != ISS_ON){
+      MinMaxPositionNP.s = IPS_IDLE;
+      IDSetNumber(&MinMaxPositionNP, "Power is off");
+      return;
+    }
+	    
+    for (nset = i = 0; i < n; i++){
+      /* Find numbers with the passed names in the MinMaxPositionNP property */
+      INumber *mmpp = IUFindNumber (&MinMaxPositionNP, names[i]);
+      
+      /* If the number found is  (MinMaxPositionN[0]) then process it */
+      if (mmpp == &MinMaxPositionN[0]){
+	      
+	new_min = (values[i]);
+	nset += new_min >= 1 && new_min <= 65000;
+      } else if  (mmpp == &MinMaxPositionN[1]){
+
+ 	new_max = (values[i]);
+	nset += new_max >= 1 && new_max <= 65000;
+      }
+    }
+	    
+    /* Did we process the two numbers? */
+    if (nset == 2) {
+		
+      /* Set the robofocus state to BUSY */
+      MinMaxPositionNP.s = IPS_BUSY;
+
+      currentMinPosition = new_min ;
+      currentMaxPosition= new_max ;
+  
+
+      MinMaxPositionNP.s = IPS_OK;
+      IDSetNumber(&MinMaxPositionNP, "Minimum and Maximum settings are now  %3.0f %3.0f", currentMinPosition, currentMaxPosition);
+
+    } else {
+      /* Set property state to idle */
+      MinMaxPositionNP.s = IPS_IDLE;
+		
+      IDSetNumber(&MinMaxPositionNP, "Minimum and maximum limits absent or bogus.");
+      
+      return ;
+    }
+  }
+
+  if (!strcmp (name, MaxTravelNP.name)) {
+
+    double new_maxt = 0 ;
+    int ret = -1 ;
+
+    /* Check power, if it is off, then return */
+    if (PowerS[0].s != ISS_ON){
+      MaxTravelNP.s = IPS_IDLE;
+      IDSetNumber(&MaxTravelNP, "Power is off");
+      return;
+    }
+    for (nset = i = 0; i < n; i++){
+      /* Find numbers with the passed names in the MinMaxPositionNP property */
+      INumber *mmpp = IUFindNumber (&MaxTravelNP, names[i]);
+      
+      /* If the number found is  (MaxTravelN[0]) then process it */
+      if (mmpp == &MaxTravelN[0]){
+	      
+	new_maxt = (values[i]);
+	nset += new_maxt >= 1 && new_maxt <= 64000;
+      }
+    }
+    /* Did we process the one number? */
+    if (nset == 1) {
+
+      IDSetNumber(&MinMaxPositionNP, NULL);
+
+      if(( ret= updateRFMaxPosition(fd,  &new_maxt))< 0 ) {
+	MaxTravelNP.s = IPS_IDLE;
+	IDSetNumber(&MaxTravelNP, "Changing to new maximum travel failed");
+	return ;
+      } ; 
+
+      currentMaxTravel=  new_maxt ;
+      MaxTravelNP.s = IPS_OK;
+      IDSetNumber(&MaxTravelNP, "Maximum travel is now  %3.0f", currentMaxTravel) ;
+
+    } else {
+      /* Set property state to idle */
+
+      MaxTravelNP.s = IPS_IDLE;
+      IDSetNumber(&MaxTravelNP, "Maximum travel absent or bogus.");
+      
+      return ;
+    }
+  }
+
+  if (!strcmp (name, SetRegisterPositionNP.name)) {
+
+    double new_apos = 0 ;
+    int nset = 0;
+    int ret= -1 ;
+
+    if (PowerS[0].s != ISS_ON){
+      SetRegisterPositionNP.s = IPS_IDLE;
+      IDSetNumber(&SetRegisterPositionNP, "Power is off");
+      return;
+    }
+    for (nset = i = 0; i < n; i++)  {
+      /* Find numbers with the passed names in the SetRegisterPositionNP property */
+      INumber *srpp = IUFindNumber (&SetRegisterPositionNP, names[i]);
+      
+      /* If the number found is SetRegisterPosition (SetRegisterPositionN[0]) then process it */
+      if (srpp == &SetRegisterPositionN[0]){
+	
+	new_apos = (values[i]);
+	
+        /* limits are absolute */
+	nset += new_apos >= 0 && new_apos <= 64000;
+      }
+
+      if (nset == 1) {
+
+	if((new_apos < currentMinPosition) || (new_apos > currentMaxPosition)) {
+
+	  SetRegisterPositionNP.s = IPS_ALERT ;
+	  IDSetNumber(&SetRegisterPositionNP, "Value out of limits  %5.0f", new_apos);
+	  return ;
+	}
+
+	/* Set the robofocus state to BUSY */
+	SetRegisterPositionNP.s = IPS_BUSY;
+	IDSetNumber(&SetRegisterPositionNP, NULL);
+	
+	if(( ret= updateRFSetPosition(fd, &new_apos)) < 0) {
+
+	  SetRegisterPositionNP.s = IPS_OK;
+	  IDSetNumber(&SetRegisterPositionNP, "Read out of the set position to %3d failed. Trying to recover the position", ret);
+
+	  if((ret= updateRFPosition(fd, &currentPosition)) < 0) {
+ 
+	    PositionNP.s = IPS_ALERT;
+	    IDSetNumber(&PositionNP, "Unknown error while reading  Robofocus position: %d", ret);
+
+	    SetRegisterPositionNP.s = IPS_IDLE;
+	    IDSetNumber(&SetRegisterPositionNP, "Relative movement failed.");
+	  }
+
+	  SetRegisterPositionNP.s = IPS_OK;
+	  IDSetNumber(&SetRegisterPositionNP, NULL); 
+
+
+	  PositionNP.s = IPS_OK;
+	  IDSetNumber(&PositionNP, "Robofocus position recovered %5.0f", currentPosition); 
+	  IDMessage( mydev, "Robofocus position recovered resuming normal operation");
+          /* We have to leave here, because new_apos is not set */
+          return ;
+	}
+	currentPosition= new_apos ;
+	SetRegisterPositionNP.s = IPS_OK;
+	IDSetNumber(&SetRegisterPositionNP, "Robofocus register set to %5.0f", currentPosition); 
+
+	PositionNP.s = IPS_OK;
+	IDSetNumber(&PositionNP, "Robofocus position is now %5.0f", currentPosition); 
+
+	return ;
+
+      } else {
+	
+	SetRegisterPositionNP.s = IPS_IDLE;
+	IDSetNumber(&SetRegisterPositionNP, "Need exactly one parameter.");
+ 	
+	return ;
+      }
+      if((ret= updateRFPosition(fd, &currentPosition)) < 0) {
+ 
+	PositionNP.s = IPS_ALERT;
+	IDSetNumber(&PositionNP, "Unknown error while reading  Robofocus position: %d", ret);
+
+	return ;
+      }
+      SetRegisterPositionNP.s = IPS_OK;
+      IDSetNumber(&SetRegisterPositionNP, "Robofocus has accepted new register setting" ) ; 
+
+      PositionNP.s = IPS_OK;
+      IDSetNumber(&PositionNP, "Robofocus new position %5.0f", currentPosition); 
+    }
+  }  
+  return;
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+/* void connectRobofocus(void)
+ * This function is called when the state of PowerSP is changed in the ISNewSwitch() function.
+ * We check the state of CONNECT and DISCONNECT switches, and connect or disconnect our fake device accordingly */
+
+void connectRobofocus(void) {
+
+  /* fprintf(stderr, "connectRobofocus\n") ; */
+
+  switch (PowerS[0].s) {
+  case ISS_ON:
+    
+   if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
+   {
+
+      PowerSP.s = IPS_ALERT;
+      IUResetSwitch(&PowerSP);
+      IDSetSwitch(&PowerSP, "Error connecting to port >%s<", PortT[0].text);
+      return;
+    }
+
+    PowerSP.s = IPS_OK;
+    IDSetSwitch(&PowerSP, "Robofocus is online.");
+    wp= IEAddWorkProc( (IE_WPF *)ISWorkProc, NULL) ;
+    break;
+
+  case ISS_OFF:
+
+    IERmWorkProc ( wp) ;
+    tty_disconnect(fd);
+    IUResetSwitch(&PowerSP);    
+    IUResetSwitch(&PowerSwitchesSP);
+    IUResetSwitch(&DirectionSP);
+    AbsMovementNP.s= RelMovementNP.s= TimerNP.s= SpeedNP.s= SetBacklashNP.s= SetRegisterPositionNP.s= MinMaxPositionNP.s= DirectionSP.s= PowerSwitchesSP.s= SettingsNP.s= TemperatureNP.s= PositionNP.s = PortTP.s = PowerSP.s = IPS_IDLE;
+
+    IDSetSwitch(&PowerSP, "Robofocus is offline.");
+
+    IDSetText(&PortTP, NULL);
+    
+    IDSetSwitch(&DirectionSP, NULL);
+    IDSetSwitch(&PowerSwitchesSP, NULL);
+
+    /* Write the last status */
+
+    IDSetNumber(&PositionNP, NULL);
+    IDSetNumber(&AbsMovementNP, NULL);
+    IDSetNumber(&RelMovementNP, NULL);
+    IDSetNumber(&TimerNP, NULL);
+    IDSetNumber(&SpeedNP, NULL);
+    IDSetNumber(&SetBacklashNP, NULL);
+    IDSetNumber(&SetRegisterPositionNP, NULL);
+    IDSetNumber(&MinMaxPositionNP, NULL);
+    IDSetNumber(&MaxTravelNP, NULL);
+    IDSetNumber(&SettingsNP, NULL);
+    IDSetNumber(&TemperatureNP, NULL);
+
+    break;
+  }
+}
+
Index: /BAORadio/libindi/v1/drivers/focuser/robofocusdriver.c
===================================================================
--- /BAORadio/libindi/v1/drivers/focuser/robofocusdriver.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/focuser/robofocusdriver.c	(revision 500)
@@ -0,0 +1,561 @@
+#if 0
+    Robofocus Driver
+    Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "indicom.h"
+#include "indidevapi.h"
+#include "indiapi.h"
+#include "robofocusdriver.h"
+
+/**********************************************************************
+* Communication
+**********************************************************************/
+
+
+int portRFRead(int fd, char *buf, int nbytes, int timeout)
+{
+
+  int bytesRead = 0;
+  int totalBytesRead = 0;
+  int err;
+  char *tbuf= buf ; 
+ 
+ 
+  while (nbytes > 0)
+    {
+      if ( (err = tty_timeout(fd, timeout)) < 0 )
+	return err;
+
+      bytesRead = read(fd, tbuf, nbytes);
+
+      if (bytesRead < 0 )
+	return -1;
+
+      
+      if((  tbuf[0]== 'I')||  (  tbuf[0]== 'O')){
+
+	/*fprintf(stderr, "Moving\n") ;*/
+	tbuf[0]=0 ;
+         usleep(100000) ; 
+      } else {
+	tbuf += bytesRead;
+	totalBytesRead++;
+	nbytes -= bytesRead;
+      }
+    }
+
+/*   fprintf(stderr, "READ : (%s,%d), %d\n", buf, 9, totalBytesRead) ; */
+/*   fprintf(stderr, "READ : ") ; */
+/*   for(i=0; i < 9; i++) { */
+
+/*     fprintf(stderr, "0x%2x ", (unsigned char)buf[i]) ; */
+/*   } */
+/*   fprintf(stderr, "\n") ; */
+  return 9;
+}
+
+
+int portRFWrite(int fd, const char * buf) {
+  int nbytes=9 ;
+  int totalBytesWritten=0 ;
+  int bytesWritten = 0;   
+
+  while (nbytes > 0)
+  {
+    
+    bytesWritten = write(fd, buf, nbytes);
+
+    if (bytesWritten < 0)
+     return -1;
+
+    buf += bytesWritten;
+    nbytes -= bytesWritten;
+  }
+
+  /* Returns the # of bytes written */
+  return (totalBytesWritten);
+}
+
+
+unsigned char calsum(char *rf_cmd) {
+
+  unsigned char val= 0 ;
+  int i=0 ;
+
+  for(i=0; i < 8; i++) {
+
+    val = val + (unsigned char) rf_cmd[i] ;
+  }
+
+  return val % 256 ;
+}
+
+
+unsigned char chksum(char *rf_cmd) {
+
+  char substr[255] ;
+  unsigned char val= 0 ;
+  int i= 0 ;
+  
+  for(i=0; i < 8; i++) {
+
+    substr[i]=rf_cmd[i] ;
+  }
+
+  val = calsum( substr) ;
+  if( val==  (unsigned char) rf_cmd[8]) {
+
+  } else {
+
+    fprintf(stderr,  "Wrong (%s,%d), %x != %x\n",  rf_cmd, strlen(rf_cmd), val, (unsigned char) rf_cmd[8]) ;
+  }
+
+  return val ;
+}
+
+/**********************************************************************
+* Commands
+**********************************************************************/
+
+
+int commRF(int fd, char *rf_cmd) {
+
+  int read_ret=0, check_ret=0;
+  char rf_cmd_cks[32] ;
+
+  unsigned char val= 0 ;
+
+  int nbytes= 9 ;
+  int i ;
+
+  val = calsum( rf_cmd ) ;
+  for(i=0; i < 8; i++) {
+      
+    rf_cmd_cks[i]= rf_cmd[i] ;
+  }
+
+  rf_cmd_cks[8]=  val ;
+  rf_cmd_cks[9]= 0 ;
+
+/*   fprintf(stderr, "WRITE: ") ; */
+/*   for(i=0; i < 9; i++) { */
+      
+/*     fprintf(stderr, "0x%2x ", rf_cmd_cks[i]) ; */
+/*   } */
+/*   fprintf(stderr, "\n") ; */
+
+  if(portRFWrite(fd, rf_cmd_cks) < 0)
+    return -1;
+
+  read_ret= portRFRead(fd, rf_cmd, nbytes, RF_TIMEOUT) ;
+
+  if (read_ret < 1)
+    return read_ret;
+
+  check_ret= chksum(rf_cmd) ;
+   
+  rf_cmd[ read_ret- 1] = 0 ;
+  return 0;
+}
+
+int updateRFPosition(int fd, double *value) {
+
+  float temp ;
+  char rf_cmd[32] ;
+  int ret_read_tmp ;
+
+  strcpy(rf_cmd, "FG000000" ) ;
+
+  if ((ret_read_tmp= commRF(fd,  rf_cmd)) < 0){
+
+    return ret_read_tmp;
+  }
+   if (sscanf(rf_cmd, "FD%6f", &temp) < 1){
+
+    return -1;
+  }
+
+  *value = (double) temp;
+
+  return 0;
+
+}
+
+int updateRFTemperature(int fd, double *value) {
+
+  float temp ;
+  char rf_cmd[32] ;
+  int ret_read_tmp ;
+
+  strcpy(rf_cmd, "FT000000" ) ;
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+    
+
+  if (sscanf(rf_cmd, "FT%6f", &temp) < 1)
+    return -1;
+   
+  *value = (double) temp/2.- 273.15;
+
+  return 0;
+}
+
+int updateRFBacklash(int fd, double *value) {
+
+  float temp ;
+  char rf_cmd[32] ;
+  char vl_tmp[4] ;
+  int ret_read_tmp ;
+  int sign= 0 ;
+
+  if(*value== BACKLASH_READOUT) {
+ 
+    strcpy(rf_cmd, "FB000000" ) ;
+
+  } else {
+
+    rf_cmd[0]=  'F' ;
+    rf_cmd[1]=  'B' ;
+    
+    if( *value > 0) {
+
+      rf_cmd[2]= '3' ;
+
+    } else {
+      *value= - *value ;
+      rf_cmd[2]= '2' ;
+    }
+    rf_cmd[3]= '0' ;
+    rf_cmd[4]= '0' ;
+
+    if(*value > 99) {
+      sprintf( vl_tmp, "%3d", (int) *value) ;
+
+    } else if(*value > 9) {
+      sprintf( vl_tmp, "0%2d", (int) *value) ;
+    } else {
+      sprintf( vl_tmp, "00%1d", (int) *value) ;
+    }
+    rf_cmd[5]= vl_tmp[0] ;
+    rf_cmd[6]= vl_tmp[1] ; 
+    rf_cmd[7]= vl_tmp[2] ;
+  }
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+    
+
+  if (sscanf(rf_cmd, "FB%1d%5f", &sign, &temp) < 1)
+    return -1;
+
+  *value = (double) temp  ;
+
+  if(( sign== 2) && ( *value > 0)) {
+    *value = - (*value) ;
+  }
+  return 0;
+}
+
+int updateRFFirmware(int fd, char *rf_cmd) {
+
+  int ret_read_tmp ;
+
+  strcpy(rf_cmd, "FV000000" ) ;
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+
+  return 0;
+}
+
+int updateRFMotorSettings(int fd, double *duty, double *delay, double *ticks) {
+
+  char rf_cmd[32] ; 
+  int ret_read_tmp ;
+
+  if(( *duty== 0 ) && (*delay== 0) && (*ticks== 0) ){
+
+    strcpy(rf_cmd, "FC000000" ) ;
+
+  } else {
+
+    rf_cmd[0]=  'F' ;
+    rf_cmd[1]=  'C' ;
+    rf_cmd[2]= (char) *duty ;
+    rf_cmd[3]= (char) *delay ;
+    rf_cmd[4]= (char) *ticks ;
+    rf_cmd[5]= '0' ;
+    rf_cmd[6]= '0' ;
+    rf_cmd[7]= '0' ;
+    rf_cmd[8]=  0 ;
+
+  }
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+ 
+  *duty=  (float) rf_cmd[2] ;
+  *delay= (float) rf_cmd[3] ;
+  *ticks= (float) rf_cmd[4] ;
+  
+  return 0;
+}
+
+int updateRFPositionRelativeInward(int fd, double *value) {
+
+  char rf_cmd[32] ;
+  int ret_read_tmp ;
+  float temp ;
+  rf_cmd[0]= 0 ;
+
+  if(*value > 9999) {
+    sprintf( rf_cmd, "FI0%5d", (int) *value) ;
+  } else if(*value > 999) {
+    sprintf( rf_cmd, "FI00%4d", (int) *value) ;
+  } else if(*value > 99) {
+    sprintf( rf_cmd, "FI000%3d", (int) *value) ;
+  } else if(*value > 9) {
+    sprintf( rf_cmd, "FI0000%2d", (int) *value) ;
+  } else {
+    sprintf( rf_cmd, "FI00000%1d", (int) *value) ;
+  }
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+
+  if (sscanf(rf_cmd, "FD0%5f", &temp) < 1)
+    return -1;
+
+  *value = (double) temp  ;
+
+  return 0;
+}
+
+int updateRFPositionRelativeOutward(int fd, double *value) {
+
+  char rf_cmd[32] ;
+  int ret_read_tmp ;
+  float temp ;
+
+  rf_cmd[0]= 0 ;
+
+  if(*value > 9999) {
+    sprintf( rf_cmd, "FO0%5d", (int) *value) ;
+  } else if(*value > 999) {
+    sprintf( rf_cmd, "FO00%4d", (int) *value) ;
+  } else if(*value > 99) {
+    sprintf( rf_cmd, "FO000%3d", (int) *value) ;
+  } else if(*value > 9) {
+    sprintf( rf_cmd, "FO0000%2d", (int) *value) ;
+  } else {
+    sprintf( rf_cmd, "FO00000%1d", (int) *value) ;
+  }
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+
+  if (sscanf(rf_cmd, "FD0%5f", &temp) < 1)
+    return -1;
+
+  *value = (double) temp  ;
+
+  return 0;
+}
+
+int updateRFPositionAbsolute(int fd, double *value) {
+
+  char rf_cmd[32] ;
+  int ret_read_tmp ;
+  float temp ;
+
+  rf_cmd[0]= 0 ;
+
+  if(*value > 9999) {
+    sprintf( rf_cmd, "FG0%5d", (int) *value) ;
+  } else if(*value > 999) {
+    sprintf( rf_cmd, "FG00%4d", (int) *value) ;
+  } else if(*value > 99) {
+    sprintf( rf_cmd, "FG000%3d", (int) *value) ;
+  } else if(*value > 9) {
+    sprintf( rf_cmd, "FG0000%2d", (int) *value) ;
+  } else {
+    sprintf( rf_cmd, "FG00000%1d", (int) *value) ;
+  }
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+
+  if (sscanf(rf_cmd, "FD0%5f", &temp) < 1)
+    return -1;
+
+  *value = (double) temp  ;
+
+  return 0;
+}
+int updateRFPowerSwitches(int fd, int s, int  new_sn, int *cur_s1LL, int *cur_s2LR, int *cur_s3RL, int *cur_s4RR) {
+
+  char rf_cmd[32] ;
+  char rf_cmd_tmp[32] ;
+  int ret_read_tmp ;
+  int i = 0 ;
+
+
+    /* Get first the status */
+    strcpy(rf_cmd_tmp, "FP000000" ) ;
+
+    if ((ret_read_tmp= commRF(fd, rf_cmd_tmp)) < 0)   
+      return ret_read_tmp ;
+
+    for(i= 0; i < 9; i++) {
+      rf_cmd[i]= rf_cmd_tmp[i] ;
+    } 
+
+
+    if( rf_cmd[new_sn + 4]== '2') {
+      rf_cmd[new_sn + 4]= '1' ;
+    } else {
+      rf_cmd[new_sn + 4]= '2' ;
+    }
+
+
+ /*    if( s== ISS_ON) { */
+
+/*       rf_cmd[new_sn + 4]= '2' ; */
+/*     } else { */
+/*       rf_cmd[new_sn + 4]= '1' ; */
+/*     } */
+
+    rf_cmd[8]= 0 ;
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)   
+    return ret_read_tmp ;
+  
+
+  *cur_s1LL= *cur_s2LR= *cur_s3RL= *cur_s4RR= ISS_OFF ;
+
+  if(rf_cmd[4]== '2' ) {
+    *cur_s1LL= ISS_ON ;
+  }
+
+  if(rf_cmd[5]== '2' ) {
+    *cur_s2LR= ISS_ON ;
+  }
+
+  if(rf_cmd[6]== '2' ) {
+    *cur_s3RL= ISS_ON ;
+  }
+
+  if(rf_cmd[7]== '2' ) {
+    *cur_s4RR= ISS_ON ;
+  }
+  return 0 ; 
+}
+
+
+int updateRFMaxPosition(int fd, double *value) {
+
+  float temp ;
+  char rf_cmd[32] ;
+  char vl_tmp[6] ;
+  int ret_read_tmp ;
+  char waste[1] ;
+
+  if(*value== MAXTRAVEL_READOUT) {
+ 
+    strcpy(rf_cmd, "FL000000" ) ;
+
+  } else {
+
+    rf_cmd[0]=  'F' ;
+    rf_cmd[1]=  'L' ;
+    rf_cmd[2]=  '0' ;
+
+    if(*value > 9999) {
+      sprintf( vl_tmp, "%5d", (int) *value) ;
+
+    } else if(*value > 999) {
+
+      sprintf( vl_tmp, "0%4d", (int) *value) ;
+
+    } else if(*value > 99) {
+      sprintf( vl_tmp, "00%3d", (int) *value) ;
+
+    } else if(*value > 9) {
+      sprintf( vl_tmp, "000%2d", (int) *value) ;
+    } else {
+      sprintf( vl_tmp, "0000%1d", (int) *value) ;
+    }
+    rf_cmd[3]= vl_tmp[0] ;
+    rf_cmd[4]= vl_tmp[1] ;
+    rf_cmd[5]= vl_tmp[2] ;
+    rf_cmd[6]= vl_tmp[3] ; 
+    rf_cmd[7]= vl_tmp[4] ;
+    rf_cmd[8]= 0 ;
+  }
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+    
+
+  if (sscanf(rf_cmd, "FL%1c%5f", waste, &temp) < 1)
+    return -1;
+
+  *value = (double) temp  ;
+
+  return 0;
+}
+
+int updateRFSetPosition(int fd, double *value) {
+
+  char rf_cmd[32] ;
+  char vl_tmp[6] ;
+  int ret_read_tmp ;
+
+  rf_cmd[0]=  'F' ;
+  rf_cmd[1]=  'S' ;
+  rf_cmd[2]=  '0' ;
+
+  if(*value > 9999) {
+    sprintf( vl_tmp, "%5d", (int) *value) ;
+  } else if(*value > 999) {
+    sprintf( vl_tmp, "0%4d", (int) *value) ;
+  } else if(*value > 99) {
+    sprintf( vl_tmp, "00%3d", (int) *value) ;
+  } else if(*value > 9) {
+    sprintf( vl_tmp, "000%2d", (int) *value) ;
+  } else {
+    sprintf( vl_tmp, "0000%1d", (int) *value) ;
+  }
+  rf_cmd[3]= vl_tmp[0] ;
+  rf_cmd[4]= vl_tmp[1] ;
+  rf_cmd[5]= vl_tmp[2] ;
+  rf_cmd[6]= vl_tmp[3] ; 
+  rf_cmd[7]= vl_tmp[4] ;
+  rf_cmd[8]= 0 ;
+
+  if ((ret_read_tmp= commRF(fd, rf_cmd)) < 0)
+    return ret_read_tmp;
+  
+  return 0;
+}
Index: /BAORadio/libindi/v1/drivers/focuser/robofocusdriver.h
===================================================================
--- /BAORadio/libindi/v1/drivers/focuser/robofocusdriver.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/focuser/robofocusdriver.h	(revision 500)
@@ -0,0 +1,22 @@
+ #if 0
+    Robofocus driver
+    Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+#define BACKLASH_READOUT 99999
+#define MAXTRAVEL_READOUT 99999
+#define RF_TIMEOUT 5 
Index: /BAORadio/libindi/v1/drivers/telescope/BAO.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/BAO.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/BAO.cpp	(revision 500)
@@ -0,0 +1,1731 @@
+  #if 0
+  
+  #############################
+  ##
+  ## BAORadio Indi driver
+  ## Franck RICHARD
+  ## Mai 2010
+  ##
+  #############################
+  #endif
+  
+  #include <stdio.h>
+  #include <stdlib.h>
+  #include <string.h>
+  #include <stdarg.h>
+  #include <math.h>
+  #include <unistd.h>
+  #include <time.h>
+  #include <memory>
+  #include <pthread.h>
+  #include <iostream>
+  #include <time.h>
+  #include <unistd.h>
+  #include <sys/time.h>
+  
+  #include <config.h>
+  
+  #include "indicom.h"
+  
+  #include "Socket.h"
+  
+  #include "BAO.h"
+  
+  using namespace std;
+  
+  auto_ptr<BAO> telescope(0);
+  
+  const int POLLMS = 1;				// Period of update, 1 ms.
+  
+  const char *mydev = "BAO";			// Name of our device.
+  
+  const char *BASIC_GROUP    = "Main Control";		// Main Group
+  const char *OPTIONS_GROUP  = "Options";			// Options Group
+  
+  /* Handy Macros */
+  //#define currentRA	EquatorialCoordsRN[0].value
+  //#define currentDEC	EquatorialCoordsRN[1].value
+  #define targetRA	EquatorialCoordsWN[0].value
+  #define targetDEC	EquatorialCoordsWN[1].value
+  
+  
+  static void ISPoll(void *);
+  
+  static void retry_connection(void *);
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void *pThreadSocket (void * arg)
+  {
+    try
+    {
+      int pos = SocketsNumber;
+      
+      // Trouver Ã©ventuellement un emplacement disponible dans l'intervalle [1..SocketsNumber]
+      
+      /*
+      for (int i=1; i<SocketsNumber; i++)
+      {
+	if (!Sockets[i].Connected)
+	{
+	  pos = i;
+	  break;
+    }
+    }*/
+      
+      server.accept ( Sockets[pos].new_sock );
+      
+      Sockets[pos].IP=server.recupip(Sockets[pos].new_sock);
+      
+      Sockets[pos].Connected=true;
+      
+      if (pos == SocketsNumber ) SocketsNumber++;
+      
+      InitThreadOK=true;
+    }
+    catch ( SocketException& e )
+    {
+      //A activer pour vÃ©rif
+      
+      /*std::string oss;
+      oss="pThreadSocket exception : " + e.description() + "\n";
+      size_t size = oss.size() + 1;
+      char* buffer = new char[size];
+      strncpy(buffer, oss.c_str(), size);
+      
+      IDLog(buffer);
+      
+      delete [] buffer;*/
+    }
+    
+    return NULL;
+  }
+  
+  
+  /**************************************************************************************
+  ** Utilisation d'un thread pour Ã©viter de bloquer l'execution du pilote
+  ** avec la commande accept
+  ***************************************************************************************/
+  
+  void BAO::InitThread()
+  {
+    if (pthread_create (&th1, NULL, pThreadSocket, NULL) < 0)
+    {
+      IDLog("pthread_create error for threadSocket\n");
+    }
+    
+    pthread_join (th1, NULL);
+  }
+  
+  /**************************************************************************************
+  ** Initialisation du pilote BAO
+  ***************************************************************************************/
+  void ISInit()
+  {
+    static int isInit=0;
+    
+    if (isInit) return;
+    
+    if (telescope.get() == 0) telescope.reset(new BAO());
+    
+    isInit = 1;
+    
+    IEAddTimer (POLLMS, ISPoll, NULL);
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void ISGetProperties (const char *dev)
+  {
+    ISInit();
+    telescope->ISGetProperties(dev);
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+  {
+    ISInit();
+    telescope->ISNewSwitch(dev, name, states, names, n);
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+  {
+    ISInit();
+    telescope->ISNewText(dev, name, texts, names, n);
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+  {
+    ISInit();
+    telescope->ISNewNumber(dev, name, values, names, n);
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void ISPoll (void *p)
+  {
+    INDI_UNUSED(p);
+    
+    telescope->ISPoll();
+    IEAddTimer (POLLMS, ISPoll, NULL);
+  }
+  
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
+  {
+    INDI_UNUSED(dev);
+    INDI_UNUSED(name);
+    INDI_UNUSED(sizes);
+    INDI_UNUSED(blobsizes);
+    INDI_UNUSED(blobs);
+    INDI_UNUSED(formats);
+    INDI_UNUSED(names);
+    INDI_UNUSED(n);
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void ISSnoopDevice (XMLEle *root)
+  {
+    INDI_UNUSED(root);
+  }
+  
+  /**************************************************************************************
+  ** Initialisation de la classe BAO
+  ***************************************************************************************/
+  BAO::BAO()
+  {
+    init_properties();
+    
+    ConnectSP.s = IPS_IDLE;
+    
+    lastSet        = -1;
+    fd             = -1;
+    simulation     = false;
+    lastRA         = 0;
+    lastDEC        = 0;
+    currentSet     = 0;
+    JJAnc          = 0.0;
+    
+    SocketsNumber  = 1;
+    
+    ActualisationTM1 = 15.0*60.0;
+    
+    ActualisationTM2 = 5.0;
+    
+    InitThreadOK=false;
+    LecturePosition=false;
+    Abort=false;
+    Park=false;
+    Goto=false;
+    LastGotoOK=true;
+    
+    TrackingMode=1;
+    
+    for (int i=0; i<MAXHOSTNAME; i++)
+    {
+      Sockets[i].Connected=false;
+      Sockets[i].IP="";
+    }
+    
+    InitAntennes();
+    
+    
+    IDLog("Initilizing from BAO device...\n");
+    IDLog("Driver Version: 2010-05-12\n");
+    
+    //enableSimulation(true);
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  BAO::~BAO()
+  {
+    
+  }
+  
+  /**************************************************************************************
+  ** Initialisation des boutons et des zones d'affichage dans la boÃ®te de dialogue INDI
+  ***************************************************************************************/
+  void BAO::init_properties()
+  {
+    // Connection
+    IUFillSwitch(&ConnectS[0], "CONNECT", "Connect", ISS_OFF);
+    IUFillSwitch(&ConnectS[1], "DISCONNECT", "Disconnect", ISS_ON);
+    IUFillSwitchVector(&ConnectSP, ConnectS, NARRAY(ConnectS), mydev, "CONNECTION", "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+    
+    // Coord Set
+    IUFillSwitch(&OnCoordSetS[0], "TRANSIT", "Transit", ISS_ON);
+    IUFillSwitch(&OnCoordSetS[1], "TRACKING", "Tracking", ISS_OFF);
+    IUFillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+    
+    // Abort
+    IUFillSwitch(&AbortSlewS[0], "ABORT", "Abort", ISS_OFF);
+    IUFillSwitchVector(&AbortSlewSP, AbortSlewS, NARRAY(AbortSlewS), mydev, "ABORT_MOTION", "Abort", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
+    
+    // Park
+    IUFillSwitch(&ParkS[0], "PARK", "Park", ISS_OFF);
+    IUFillSwitchVector(&ParkSP, ParkS, NARRAY(ParkS), mydev, "", "Park", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
+    
+    // Object Name
+    IUFillText(&ObjectT[0], "OBJECT_NAME", "Name", "--");
+    IUFillTextVector(&ObjectTP, ObjectT, NARRAY(ObjectT), mydev, "OBJECT_INFO", "Object", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
+    
+    
+    // Equatorial Coords - SET
+    IUFillNumber(&EquatorialCoordsWN[0], "RA", "RA  H:M:S", "%10.6m",  0., 24., 0., 0.);
+    IUFillNumber(&EquatorialCoordsWN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.);
+    IUFillNumberVector(&EquatorialCoordsWNP, EquatorialCoordsWN, NARRAY(EquatorialCoordsWN), mydev, "EQUATORIAL_EOD_COORD_REQUEST" , "Equatorial JNow", BASIC_GROUP, IP_WO, 0, IPS_IDLE);
+    
+    // Equatorial Coords - READ
+    //    IUFillNumber(&EquatorialCoordsRN[0], "RA", "RA  H:M:S", "%10.6m",  0., 24., 0., 0.);
+    //    IUFillNumber(&EquatorialCoordsRN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.);
+    //    IUFillNumberVector(&EquatorialCoordsRNP, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), mydev, "EQUATORIAL_EOD_COORD" , "Equatorial JNow", BASIC_GROUP, IP_RO, 0, IPS_IDLE);
+    
+    // Geographic coord - SET
+    IUFillNumber(&GeographicCoordsWN[0], "LAT", "Lat  D", "%10.6m",  -90., 90., 0., 0.);
+    IUFillNumber(&GeographicCoordsWN[1], "LONG", "Long D", "%10.6m", 0., 360., 0., 0.);
+    IUFillNumberVector(&GeographicCoordsWNP, GeographicCoordsWN, NARRAY(GeographicCoordsWN), mydev, "GEOGRAPHIC_COORD" , "Geographic coords", OPTIONS_GROUP, IP_WO, 0, IPS_IDLE);
+    
+    // Actualisation - SET
+    IUFillNumber(&ActualisationN1[0], "DELAY", "Transit mode delay (Sec)", "%10.6m",  0., 3600., 0., 0.);
+    IUFillNumberVector(&ActualisationNP1, ActualisationN1, NARRAY(ActualisationN1), mydev, "DELAY1" , "", OPTIONS_GROUP, IP_WO, 0, IPS_IDLE);
+    
+    IUFillNumber(&ActualisationN2[0], "DELAY", "Tracking mode delay (Sec)", "%10.6m",  0., 3600., 0., 0.);
+    IUFillNumberVector(&ActualisationNP2, ActualisationN2, NARRAY(ActualisationN2), mydev, "DELAY2" , "", OPTIONS_GROUP, IP_WO, 0, IPS_IDLE);
+    
+    // Transit threshold
+    //IUFillNumber(&SlewAccuracyN[0], "TransitRA",  "RA (arcmin)", "%10.6m",  0., 60., 1., 3.0);
+    //IUFillNumber(&SlewAccuracyN[1], "TransitDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0);
+    //IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), mydev, "Transit Accuracy", "", OPTIONS_GROUP, IP_RW, 0, IPS_IDLE);
+    
+    // Tracking threshold
+    //IUFillNumber(&TrackAccuracyN[0], "TrackingRA", "RA (arcmin)", "%10.6m",  0., 60., 1., 3.0);
+    //IUFillNumber(&TrackAccuracyN[1], "TrackingDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0);
+    //IUFillNumberVector(&TrackAccuracyNP, TrackAccuracyN, NARRAY(TrackAccuracyN), mydev, "Tracking Accuracy", "", OPTIONS_GROUP, IP_RW, 0, IPS_IDLE);
+    
+  }
+  
+  /**************************************************************************************
+  ** Initialisation de la boÃ®te de dialogue INDI (suite)
+  ***************************************************************************************/
+  void BAO::ISGetProperties(const char *dev)
+  {
+    
+    if (dev && strcmp (mydev, dev))
+      return;
+    
+    // Main Control
+    IDDefSwitch(&ConnectSP, NULL);
+    IDDefText(&ObjectTP, NULL);
+    IDDefNumber(&EquatorialCoordsWNP, NULL);
+    //IDDefNumber(&EquatorialCoordsRNP, NULL);
+    IDDefNumber(&GeographicCoordsWNP, NULL);
+    IDDefSwitch(&OnCoordSetSP, NULL);
+    IDDefSwitch(&AbortSlewSP, NULL);
+    IDDefSwitch(&ParkSP, NULL);
+    
+    // Options
+    //IDDefNumber(&SlewAccuracyNP, NULL);
+    //IDDefNumber(&TrackAccuracyNP, NULL);   
+    IDDefNumber(&ActualisationNP1, NULL);
+    IDDefNumber(&ActualisationNP2, NULL);
+    
+  }
+  
+  /**************************************************************************************
+  ** En cas de changement de texte dans la boÃ®te de dialogue
+  ***************************************************************************************/
+  void BAO::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+  {
+    // Ignore if not ours
+    if (strcmp (dev, mydev))
+      return;
+    
+    if (is_connected() == false)
+    {
+      IDMessage(mydev, "BAORadio. Please connect before issuing any commands.");
+      reset_all_properties();
+      return;
+    }
+    
+    // ===================================
+    // Object Name
+    // ===================================
+    if (!strcmp (name, ObjectTP.name))
+    {
+      if (IUUpdateText(&ObjectTP, texts, names, n) < 0)
+	return;
+      
+      ObjectTP.s = IPS_OK;
+      IDSetText(&ObjectTP, NULL);
+      return;
+    }
+  }
+  
+  /**************************************************************************************
+  ** En cas de changement d'une valeur numÃ©rique dans la boÃ®te de dialogue Indi
+  ***************************************************************************************/
+  void BAO::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+  {
+    
+    // Ignore if not ours
+    if (strcmp (dev, mydev))
+      return;
+    
+    if (is_connected() == false)
+    {
+      IDMessage(mydev, "BAO is offline. Please connect before issuing any commands.");
+      reset_all_properties();
+      return;
+    }
+    
+    
+    // ===================================
+    // Geographic  Coords
+    // ===================================
+    if (!strcmp (name, GeographicCoordsWNP.name))
+    {
+      int i=0, nset=0, error_code=0;
+      
+      Latitude=0.0;
+      Longitude=0.0;
+      
+      for (nset = i = 0; i < n; i++)
+      {
+	INumber *eqp = IUFindNumber (&GeographicCoordsWNP, names[i]);
+	if (eqp == &GeographicCoordsWN[0])
+	{
+	  Latitude = values[i];
+	  nset += Latitude >= -90.0 && Latitude <= 90.0;
+	  
+	  Latitude*=Pidiv180;
+	}
+	else if (eqp == &GeographicCoordsWN[1])
+	{
+	  Longitude = values[i];
+	  nset += Longitude >= 0.0 && Longitude <= 360.0;
+	  
+	  Longitude*=-Pidiv180;
+	}
+      }
+      
+      if (nset == 2)
+      {
+	//VÃ©rification
+	//IDLog("Geographic : RA %5.2f - DEC %5.2f\n", Latitude, Longitude);
+	
+	GeographicCoordsWNP.s = IPS_OK;
+	IDSetNumber(&GeographicCoordsWNP, NULL);
+      }
+      else
+      {
+	GeographicCoordsWNP.s = IPS_ALERT;
+	IDSetNumber(&GeographicCoordsWNP, "Latitude or Longitude missing or invalid");
+	
+	Latitude=0.0;
+	Longitude=0.0;
+      }
+      
+      return;
+    }
+    
+    
+    // ===================================
+    // Equatorial Coords
+    // ===================================
+    if (!strcmp (name, EquatorialCoordsWNP.name))
+    {
+      int i=0, nset=0, error_code=0;
+      double newRA =0, newDEC =0;
+      
+      for (nset = i = 0; i < n; i++)
+      {
+	INumber *eqp = IUFindNumber (&EquatorialCoordsWNP, names[i]);
+	if (eqp == &EquatorialCoordsWN[0])
+	{
+	  newRA = values[i];	  
+	  nset += newRA >= 0 && newRA <= 24.0;
+	}
+	else if (eqp == &EquatorialCoordsWN[1])
+	{
+	  newDEC = values[i];
+	  nset += newDEC >= -90.0 && newDEC <= 90.0;
+	}
+      }
+      
+      targetRA  = newRA;
+      targetDEC = newDEC;
+      
+      if (nset == 2)
+      {
+	char RAStr[32], DecStr[32];
+	double targetAZ, targetAlt;
+	
+	fs_sexa(RAStr, newRA, 2, 3600);
+	fs_sexa(DecStr, newDEC, 2, 3600);
+	
+	IDLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr);
+	
+	// on convertit les coordonnÃ©es Ã©quatoriales de la zone du ciel observÃ©e
+	// en unitÃ©s de codeurs des moteurs
+	
+	ADDEC2Motor(newRA, newDEC);
+	
+	if (process_coords() == false)
+	{
+	  EquatorialCoordsWNP.s = IPS_ALERT;
+	  IDSetNumber(&EquatorialCoordsWNP, NULL);
+	}
+      }
+      else
+      {
+	EquatorialCoordsWNP.s = IPS_ALERT;
+	IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid");
+      }
+      
+      return;
+    }
+      
+    // ===================================
+    // Actualisation
+    // ===================================
+    if (!strcmp (name, ActualisationNP1.name))
+    {
+      int i=0, nset=0, error_code=0;
+      double newAct1 =0;
+      
+      for (nset = i = 0; i < n; i++)
+      {
+	INumber *eqp = IUFindNumber (&ActualisationNP1, names[i]);
+	if (eqp == &ActualisationN1[0])
+	{
+	  newAct1 = values[i];
+	  
+	  if (newAct1 >= 0.0 && newAct1 <= 3600.0)
+	  {
+	    ActualisationTM1=newAct1;
+		
+	    ActualisationNP1.s = IPS_OK;
+	    IDSetNumber(&ActualisationNP1, NULL);
+          }
+          else
+          {
+	    ActualisationNP1.s = IPS_ALERT;
+	    IDSetNumber(&ActualisationNP1, "Delay invalid");
+          }
+	}
+      }
+      
+    }
+    
+    if (!strcmp (name, ActualisationNP2.name))
+    {
+      int i=0, nset=0, error_code=0;
+      double newAct2 =0;
+      
+      for (nset = i = 0; i < n; i++)
+      {
+	INumber *eqp = IUFindNumber (&ActualisationNP2, names[i]);
+	if (eqp == &ActualisationN2[0])
+	{
+	  newAct2 = values[i];
+	  
+	  if (newAct2 >= 0.0 && newAct2 <= 3600.0)
+	  {
+	    ActualisationTM2=newAct2;
+		
+	    ActualisationNP2.s = IPS_OK;
+	    IDSetNumber(&ActualisationNP2, NULL);
+          }
+          else
+          {
+	    ActualisationNP2.s = IPS_ALERT;
+	    IDSetNumber(&ActualisationNP2, "Delay invalid");
+          }
+	}
+      }
+      
+    } /* end EquatorialCoordsWNP */
+  }
+  
+  /**************************************************************************************
+  ** L'utilisateur clique sur l'un des boutons de la boÃ®te Indi
+  ***************************************************************************************/
+  void BAO::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+  {
+    // ignore if not ours //
+    if (strcmp (mydev, dev))
+      return;
+    
+    // ===================================
+    // Connect Switch
+    // ===================================
+    if (!strcmp (name, ConnectSP.name))
+    {
+      if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0)
+	return;
+      
+      connect_telescope();
+      return;
+    }
+    
+    if (is_connected() == false)
+    {
+      IDMessage(mydev, "BAORadio is offline. Please connect before issuing any commands.");
+      reset_all_properties();
+      return;
+    }
+    
+    // ===================================
+    // Coordinate Set
+    // ===================================
+    if (!strcmp(name, OnCoordSetSP.name))
+    {
+      if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0)
+	return;
+      
+      currentSet = get_switch_index(&OnCoordSetSP);
+      OnCoordSetSP.s = IPS_OK;
+      IDSetSwitch(&OnCoordSetSP, NULL);
+    }
+    
+    // ===================================
+    // Abort slew
+    // ===================================
+    if (!strcmp (name, AbortSlewSP.name))
+    {
+      Abort=true;
+      
+      IUResetSwitch(&AbortSlewSP);
+      
+      /*
+      if (EquatorialCoordsWNP.s == IPS_BUSY)
+      {
+	
+	AbortSlewSP.s = IPS_OK;
+	EquatorialCoordsWNP.s       = IPS_IDLE;
+	EquatorialCoordsRNP.s       = IPS_IDLE;
+	HorizontalCoordsWNP.s       = IPS_IDLE;
+	IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+	IDSetNumber(&EquatorialCoordsWNP, NULL);
+	IDSetNumber(&EquatorialCoordsRNP, NULL);
+	IDSetNumber(&HorizontalCoordsWNP, NULL);
+    }
+    */
+      return;
+    }
+    
+    
+    // ===================================
+    // Park
+    // ===================================
+    if (!strcmp (name, ParkSP.name))
+    {
+      Park=true;
+      
+      IUResetSwitch(&ParkSP);
+      
+      /*
+      if (EquatorialCoordsWNP.s == IPS_BUSY)
+      {
+	
+	AbortSlewSP.s = IPS_OK;
+	EquatorialCoordsWNP.s       = IPS_IDLE;
+	EquatorialCoordsRNP.s       = IPS_IDLE;
+	HorizontalCoordsWNP.s       = IPS_IDLE;
+	IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+	IDSetNumber(&EquatorialCoordsWNP, NULL);
+	IDSetNumber(&EquatorialCoordsRNP, NULL);
+	IDSetNumber(&HorizontalCoordsWNP, NULL);
+    }
+    */
+      return;
+    }
+  }
+  
+  /**************************************************************************************
+  ** fct peut-Ãªtre inutile
+  ***************************************************************************************/
+  void BAO::handle_error(INumberVectorProperty *nvp, int err, const char *msg)
+  {
+    nvp->s = IPS_ALERT;
+    
+    /* If the error is a time out, then the device doesn't support this property */
+    if (err == -2)
+    {
+      nvp->s = IPS_ALERT;
+      IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
+    }
+    else
+      /* Changing property failed, user should retry. */
+      IDSetNumber( nvp , "%s failed.", msg);
+    
+    fault = true;
+  }
+  
+  /**************************************************************************************
+  ** Initialisation des vecteurs INDI
+  ***************************************************************************************/
+  void BAO::reset_all_properties()
+  {
+    ConnectSP.s			= IPS_IDLE;
+    OnCoordSetSP.s		= IPS_IDLE;
+    AbortSlewSP.s		= IPS_IDLE;
+    ParkSP.s			= IPS_IDLE;
+    ObjectTP.s			= IPS_IDLE;
+    EquatorialCoordsWNP.s	= IPS_IDLE;
+    //EquatorialCoordsRNP.s	= IPS_IDLE;
+    GeographicCoordsWNP.s	= IPS_IDLE;
+    //SlewAccuracyNP.s		= IPS_IDLE;
+    //TrackAccuracyNP.s		= IPS_IDLE;
+    ActualisationNP1.s		= IPS_IDLE;
+    ActualisationNP2.s		= IPS_IDLE;
+    
+    IUResetSwitch(&OnCoordSetSP);
+    IUResetSwitch(&AbortSlewSP);
+    IUResetSwitch(&ParkSP);
+    
+    OnCoordSetS[0].s = ISS_ON;
+    ConnectS[0].s = ISS_OFF;
+    ConnectS[1].s = ISS_ON;
+    
+    IDSetSwitch(&ConnectSP, NULL);
+    IDSetSwitch(&OnCoordSetSP, NULL);
+    IDSetSwitch(&AbortSlewSP, NULL);
+    IDSetSwitch(&ParkSP, NULL);
+    IDSetText(&ObjectTP, NULL);
+    IDSetNumber(&EquatorialCoordsWNP, NULL);
+    //IDSetNumber(&EquatorialCoordsRNP, NULL);
+    IDSetNumber(&GeographicCoordsWNP, NULL);
+    //IDSetNumber(&SlewAccuracyNP, NULL);
+    //IDSetNumber(&TrackAccuracyNP, NULL);
+    IDSetNumber(&ActualisationNP1, NULL);
+    IDSetNumber(&ActualisationNP2, NULL);
+   
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void BAO::correct_fault()
+  {
+    fault = false;
+    IDMessage(mydev, "Telescope is online.");
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  bool BAO::is_connected()
+  {
+    if (simulation) return true;
+    
+    // return (ConnectSP.sp[0].s == ISS_ON);
+    return (ConnectSP.s == IPS_OK);
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  static void retry_connection(void * p)
+  {
+    
+  }
+  
+  
+  /**************************************************************************************
+  ** Extraction de la position de l'antenne
+  ** dans le retour de la commande POS
+  ** POS/Valeur az/Valeur alt
+  ***************************************************************************************/
+  
+  Position BAO::ExtractPosition(std::string str)
+  {
+    Position result;
+    
+    std::string str2;
+    
+    result.x = -1;
+    result.y = -1;
+    
+    int pos = str.find("/");
+    
+    if (pos != string::npos)
+    {
+      str2 = str.substr(pos+1);
+      
+      pos = str2.find("/");
+      
+      if (pos != string::npos)
+      {
+	result.x = atoi(str2.substr(0, pos).c_str());
+	
+	result.y = atoi(str2.substr(pos+1).c_str());
+      }
+    }
+    
+    return result;
+  }
+  
+  
+  
+  /************************************************************************************
+  * cette procÃ©dure convertit les coordonnÃ©es equatoriales de l'objet visÃ©
+  * en unitÃ©s de codeurs des paraboles (nb de tours des deux axes moteurs depuis la position PARK)
+  ************************************************************************************/
+  void BAO::ADDEC2Motor(double newRA, double newDEC)
+  {
+    double targetAz;
+    double targetAlt;
+    char AzStr[32];
+    char AltStr[32];
+    
+    // Calcule la hauteur et l'azimut de la zone du ciel pointÃ©e (en fonction de la date et du lieu)
+    
+    Azimut(tsl, Latitude, newRA * 15.0 * Pidiv180, newDEC * Pidiv180, &targetAz, &targetAlt);
+    
+    // En degrÃ©s
+    
+    targetAlt *= N180divPi;
+    targetAz *= N180divPi;
+    
+    // Affichage dans les logs
+    
+    fs_sexa(AzStr, targetAz, 2, 3600);
+    fs_sexa(AltStr, targetAlt, 2, 3600);
+    
+    IDLog("Horizontal coords : az %s - Alt %s\n", AzStr, AltStr);
+    
+    // Le calcul est ici trÃšs sommaire et arbitraire :
+    // Je considÃšre qu'il y a 100 positions possibles sur les deux axes
+    // De plus, je considÃšre qu'il n'est pas possible de viser un objet Ã 
+    // moins de 30Â° de hauteur au-dessus de l'horizon
+    
+    TargetPosition.x=(int)(targetAz*100.0/360.0);
+    
+    targetAlt=((90.0-targetAlt)/60.0);
+    
+    if (targetAlt>=1.0) 
+    {
+          targetAlt=1.0; //on ne peut pas viser un objet situÃ© Ã  moins de 30Â°
+          //au-dessus de l'horizon
+	  
+	  IDSetSwitch(&OnCoordSetSP, "Erreur : l objet suivi est situÃ© Ã  moins de 30Â° en-dessus de l horizon. Goto annulÃ©.");
+	  
+	  Goto=false;
+	  
+	  LecturePosition=false;
+	
+	  InitAntennes();
+    }
+  
+    TargetPosition.y=(int)(100.0*targetAlt);
+  }
+  
+  
+  /************************************************************************************
+  * Retourne simplement le nombre d'antennes connectÃ©es
+  * et capables de communiquer
+  ************************************************************************************/
+  
+  int BAO::AntennesConnectees()
+  {
+    int num=0;
+    
+    for (int i=1; i<SocketsNumber; i++) if (Sockets[i].Connected) num++;
+    
+    return num;
+  }
+  
+  
+  /************************************************************************************
+  * Initialisation des paramÃštres des antennes
+  *
+  ************************************************************************************/
+  void BAO::InitAntennes()
+  {
+    for (int i=0; i < MAXHOSTNAME ; i++)
+    {
+      Sockets[i].status=0;
+      Sockets[i].sendalertes=0;
+      Sockets[i].AttenteExecution=0;
+      Sockets[i].AnomaliesExecution=0;
+      Sockets[i].etape=0;
+      
+      Sockets[i].ack_status=false;
+      Sockets[i].ack_pos=false;
+      Sockets[i].ack_park=false;
+      Sockets[i].ack_abort=false;
+      Sockets[i].ack_goto=false;
+      
+      Sockets[i].PosValides=false;
+      Sockets[i].GotoOk=false;
+    }
+  }
+  
+  
+  /**************************************************************************************
+  ** ProcÃ©dure principale
+  ** Elle est appelÃ©e toutes les POLLMS ms (ici 1 ms)
+  ***************************************************************************************/
+  void BAO::ISPoll()
+  {
+    static bool ISPOLLRunning=false;
+    static int memSocketsNumber=-1;
+    static unsigned int compt=100;
+    
+    int pos;
+    
+    struct tm date;
+    time_t t;
+    struct timeval tv;
+    struct timezone tz;
+    
+    if (is_connected() == false) return;
+    
+    if (ISPOLLRunning) return;
+    
+    ISPOLLRunning=true;
+    
+    compt++;
+    
+    
+    //toutes les 100 millisec
+    
+    if ( compt%100 == 0)
+    {
+      //RÃ©cupÃ©ration de la date et de l'heure
+      
+      time(&t);
+      date=*gmtime(&t);
+      gettimeofday(&tv, &tz);
+      
+      Annee=(double)(date.tm_year+1900);
+      Mois=(double)(date.tm_mon+1);
+      Jour=(double)date.tm_mday;
+      Heu=(double)date.tm_hour;
+      Min=(double)date.tm_min;
+      Sec=(double)date.tm_sec+tv.tv_usec/1.0E6;
+      UTCP=0.0;//(double)date.tm_isdst;
+      
+      
+      //Calcul du temps sidÃ©ral local
+      
+      CalculTSL();
+      
+      
+      //Y a-t-il de nouvelles tentatives de connexion sur le serveur ?
+      
+      InitThread();          
+    }
+    
+    
+    
+    
+    if (InitThreadOK)  // Il faut qu'il y ait eu au moins une connexion dÃ©tectÃ©e par le thread pour continuer
+    {
+      
+      // Nouvelle connexion sur le socket !
+      
+      if (SocketsNumber>memSocketsNumber)
+      {
+	memSocketsNumber=SocketsNumber;
+	
+	IDSetSwitch(&ConnectSP, "Connexion de l antenne %s. (Antennes connectÃ©es : %i)",
+		    Sockets[SocketsNumber-1].IP.c_str(), AntennesConnectees());
+      }
+      
+      
+      
+      // DÃ©but des Ã©changes avec les microcontrÃŽleurs
+      
+      // Analyse des rÃ©ponses des microcontrÃŽleurs
+      
+      for (int i=1; i<SocketsNumber; i++) /*if (Sockets[i].Connected)*/
+      {
+	try
+	{
+	  std::string reponse, memreponse;
+	  // on rÃ©cupÃšre la rÃ©ponse du microcontrÃŽleur
+	  
+	  Sockets[i].new_sock >> reponse;
+	  
+	  //IDSetSwitch(&OnCoordSetSP, "RÃ©ponse ISPOLL : %s\n", reponse.c_str());        // pour vÃ©rif
+	  
+	  //Dans le cas oÃ¹ plusieurs trames seraient arrivÃ©es entre deux appels de POLLMS
+	  //les traiter successivement
+	  
+	  pos=reponse.find("\n");   // d'oÃ¹ l'intÃ©rÃªt de mettre un '\n' Ã  la fin des trames
+	  //pour diffÃ©rencier une trame de la prÃ©cÃ©dente
+	  while ((pos!=string::npos) && (reponse.length()>1))
+	  {
+	    memreponse=reponse.substr(pos+1);
+	    
+	    reponse=reponse.substr(0, pos);
+	    
+	    
+	    // On traite ici les acknowledges
+	    
+	    if ((reponse.find("ACK")!=string::npos) && (reponse.find("NACK")==string::npos))
+	    {	      
+	      if (reponse.find("POS")!=string::npos)
+	      {
+		Sockets[i].ack_pos=true;
+	      }
+	      else if (reponse.find("GOTO")!=string::npos)
+	      {
+		Sockets[i].ack_goto=true;
+	      }
+	      else if (reponse.find("PARK")!=string::npos)
+	      {
+		Sockets[i].ack_park=true;
+	      }
+	      else if (reponse.find("ABORT")!=string::npos)
+	      {
+		Sockets[i].ack_abort=true;
+	      }
+	    }
+	    else
+	    {
+	      
+	      //rÃ©ponse Ã  la requÃªte POSITION
+	      if (reponse.find("POS")!=string::npos)
+	      {
+		if (reponse.find("NACK")!=string::npos)
+		{
+		  OnCoordSetSP.s = IPS_ALERT;
+		  IDSetSwitch(&OnCoordSetSP, "ALERTE antenne %s : position de l antenne inconnue !\n",
+			      Sockets[i].IP.c_str());
+			      Sockets[i].PosValides=false;
+			      // Si la position de l'antenne est inconnue, on dÃ©connecte l'antenne
+			      Sockets[i].Connected=false;
+		}
+		else if (Sockets[i].ack_pos)
+		{
+		  OnCoordSetSP.s = IPS_OK;
+		  Sockets[i].Pos = ExtractPosition(reponse);
+		  Sockets[i].PosValides = true;
+		  IDSetSwitch(&ParkSP, "Antenne %s : POSITION OK  (x=%i, y=%i)\n",
+		    Sockets[i].IP.c_str(), Sockets[i].Pos.x, Sockets[i].Pos.y);
+		}
+		
+	      }//rÃ©ponse Ã  la requÃªte PARK
+	      else if (reponse.find("PARK")!=string::npos)
+	      {
+		if (reponse.find("NACK")!=string::npos)
+		{
+		  ParkSP.s = IPS_ALERT;
+		  IDSetSwitch(&ParkSP, "ALERTE antenne %s : erreur PARK !\n", Sockets[i].IP.c_str());
+		} 
+		else if (reponse.find("OK")!=string::npos)
+		{
+		  ParkSP.s = IPS_OK;
+		  IDSetSwitch(&ParkSP, "Antenne %s : PARK OK\n",  Sockets[i].IP.c_str());
+		}
+		
+	      }//rÃ©ponse Ã  la requÃªte ABORT
+	      else if (reponse.find("ABORT")!=string::npos)
+	      {
+		if (reponse.find("NACK")!=string::npos)
+		{
+		  AbortSlewSP.s = IPS_ALERT;
+		  IDSetSwitch(&AbortSlewSP, "ALERTE antenne %s : erreur ABORT !\n",  Sockets[i].IP.c_str());
+		}
+		
+		if (reponse.find("OK")!=string::npos)
+		{
+		  AbortSlewSP.s = IPS_OK;
+		  IDSetSwitch(&AbortSlewSP, "Antenne %s : ABORT OK\n",  Sockets[i].IP.c_str());
+		}
+		
+	      } //rÃ©ponse Ã  la requÃªte GOTO
+	      else if (reponse.find("GOTO")!=string::npos)
+	      {
+		if (reponse.find("NACK")!=string::npos)
+		{
+		  OnCoordSetSP.s = IPS_ALERT;
+		  IDSetSwitch(&OnCoordSetSP, "ALERTE antenne %s : Erreur GOTO !\n",  Sockets[i].IP.c_str());
+		  Sockets[i].Connected=false;
+		}
+		else if (Sockets[i].ack_goto)
+		{
+		  if (reponse.find("OK")!=string::npos)
+		  {
+		    OnCoordSetSP.s = IPS_OK;
+		  
+		    Sockets[i].GotoOk=true;
+		  
+		    IDSetSwitch(&ParkSP, "Antenne %s : GOTO OK.\n",  Sockets[i].IP.c_str());
+		  
+		    lastRA  = targetRA;
+		    lastDEC = targetDEC;
+		  
+		     //IDLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr);*/
+		  
+		    EquatorialCoordsWNP.s = IPS_OK;
+		    IDSetNumber (&EquatorialCoordsWNP, NULL);
+		  
+		    // Fin du Goto pour toutes les antennes ?
+		  
+		    int num=0;
+		  
+		    for (int j=1; j<SocketsNumber; j++) if (Sockets[j].Connected)
+		    {
+		      if (Sockets[j].GotoOk) num++;
+		    }
+		  
+		    if ((num == AntennesConnectees()) && (num>0))
+		    {
+		      LecturePosition=false;
+		    
+		      InitAntennes();
+		      
+		      LastGotoOK=true;
+		    
+		      IDSetSwitch(&OnCoordSetSP, "GOTO OK !");
+		    }
+		  }  
+		}
+	      }
+	    }
+	    
+	    // On passe Ã©ventuellement Ã  la trame suivante
+	    
+	    reponse=memreponse;
+	    pos=reponse.find("\n");
+	    
+	  }
+	}
+	catch (SocketException& e) //AÃ¯e
+	{
+	  Sockets[i].new_sock.shutdown();
+	  Sockets[i].new_sock.create();
+	  Sockets[i].Connected = Sockets[i].new_sock.connect((std::string)Sockets[i].IP);
+	  
+	  if (Sockets[i].Connected)
+	  {
+	    Sockets[i].AttenteExecution=0;
+	    Sockets[i].AnomaliesExecution=0;
+	  }  
+	  
+	  std::string oss;
+	  oss="SocketException IsPoll : " + e.description() + "\n";
+	  size_t size = oss.size() + 1;
+	  char* buffer = new char[size];
+	  strncpy(buffer, oss.c_str(), size);
+	  IDLog(buffer);
+	  delete [] buffer;
+	}
+      }
+      
+      
+      
+      if (Abort)
+      {
+	IDSetSwitch(&ConnectSP, "Envoi de la commande Abort\n");
+	
+	Goto=false;
+	
+	for (int i=1; i<SocketsNumber; i++) if (Sockets[i].Connected)
+	{
+	  if (!ABORT(i)) Sockets[i].sendalertes++;
+	}
+	
+	LecturePosition=false;
+	
+	InitAntennes();
+	
+	Abort=false;
+      }
+      
+      
+      if (Park)
+      {
+	IDSetSwitch(&ConnectSP, "Envoi de la commande Park\n");
+	
+	Goto=false;
+	
+	for (int i=1; i<SocketsNumber; i++) if (Sockets[i].Connected)
+	{
+	  if (!PARK(i)) Sockets[i].sendalertes++;
+	}
+	
+	LecturePosition=false;
+	
+	InitAntennes();
+	
+	Park=false;
+      }
+      
+      
+      // Gestion du suivi
+      
+      if ((Goto) && (LastGotoOK))
+      {
+	// DurÃ©e entre deux actualisations
+	
+	double delai=ActualisationTM1/3600.0/24.0;   // Actualisation toutes les 15 minutes en mode transit
+	
+	if (TrackingMode==2) delai=ActualisationTM2/3600.0/24.0;   //et 5 secs en mode tracking
+	  
+	  
+	  // On actualise la position
+	  
+	  if (JJ-JJAnc > delai)
+	  {
+	    
+	    LastGotoOK=false;
+	    
+	    LecturePosition=true;
+	    
+	    ADDEC2Motor(targetRA, targetDEC);
+	    
+	    InitAntennes();	    
+	    
+	    JJAnc=JJ;
+	  }
+	  
+	  //Plus d'antenne !
+	  
+	  if (AntennesConnectees() == 0)
+	  {
+	    // LecturePosition=false;
+	    
+	    // Goto=false;
+	    
+	    // InitAntennes();
+	    
+	    if ( compt % 1000 == 0)  IDSetSwitch(&OnCoordSetSP, "Erreur ! Plus d antennes connectÃ©es !");
+	  }
+      }
+      
+      
+      
+      // ExÃ©cution de la procÃ©dure complÃšte de lecture de la position de l'antenne
+      // puis envoi d'une commande Goto
+      
+      if (LecturePosition)
+      {
+	for (int i=1; i<SocketsNumber; i++) /*if (Sockets[i].Connected)*/
+	{
+	  switch (Sockets[i].etape)
+	  {
+	   
+	    //Envoi de la commande POS
+	    case 0 :
+	    {
+	      Sockets[i].ack_pos=false;
+	      Sockets[i].PosValides=false;
+	      
+	      if (!POSITION(i)) Sockets[i].sendalertes++;
+	      
+	      Sockets[i].etape++;
+	    }
+	    break;
+	    
+	    //ack POS
+	    case 1 :
+	    {
+	      if (Sockets[i].ack_pos)
+	      {
+		Sockets[i].AttenteExecution=0;
+		Sockets[i].AnomaliesExecution=0;
+		Sockets[i].etape++;
+		i--;
+	      }
+	      else
+	      {
+		// on rÃ©itÃšre l'ordre prÃ©cÃ©dent si rien ne se passe
+		
+		Sockets[i].AttenteExecution++;
+		
+		if (Sockets[i].AttenteExecution>MAXATTENTE)
+		{
+		  Sockets[i].etape=0;
+		  Sockets[i].AttenteExecution=0;
+		  Sockets[i].AnomaliesExecution++;
+		}
+		
+		if (Sockets[i].AnomaliesExecution>MAXANOMALIES)
+		{
+		  Sockets[i].etape=3;
+		  
+		 // if ( compt % 1000 == 0)
+		  {
+		    IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s. Pas d acknowledge reÃ§u aprÃšs l ordre POSITION. DÃ©connexion de l antenne.",
+				Sockets[i].IP.c_str());
+				Sockets[i].Connected=false;
+		  }
+		}
+	      }
+	    }
+	    break;
+	    
+	    //Valeurs pos valides ?
+	    case 2 :
+	    {
+	      if (Sockets[i].PosValides)
+	      {
+		Sockets[i].AttenteExecution=0;
+		Sockets[i].etape++;
+	      }
+	      else
+	      {
+		// on rÃ©itÃšre l'ordre prÃ©cÃ©dent si rien ne se passe
+		
+		Sockets[i].AttenteExecution++;
+		
+		if (Sockets[i].AttenteExecution>MAXATTENTE)
+		{
+		  Sockets[i].etape=2;
+		  Sockets[i].AttenteExecution=0;
+		  Sockets[i].AnomaliesExecution++;
+		}
+		
+		if (Sockets[i].AnomaliesExecution>MAXANOMALIES)
+		{
+		  Sockets[i].etape=3;
+		  
+		 // if ( compt % 1000 == 0)
+		  {
+		    IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s. La position retournÃ©e n est pas valide. DÃ©connexion de l antenne.",
+				Sockets[i].IP.c_str());
+				Sockets[i].Connected=false;
+		  }
+		}
+	      }
+	    }
+	    break;
+	    
+	    //ack goto  ?
+	    case 4 :
+	    {
+	      if (Sockets[i].ack_goto)
+	      {
+		Sockets[i].AttenteExecution=0;
+		Sockets[i].AnomaliesExecution=0;
+		Sockets[i].etape++;
+	      }
+	      else
+	      {
+		// on rÃ©itÃšre l'ordre prÃ©cÃ©dent si rien ne se passe
+		
+		Sockets[i].AttenteExecution++;
+		
+		if (Sockets[i].AttenteExecution>MAXATTENTE)
+		{
+		  Sockets[i].etape=4;
+		  Sockets[i].AttenteExecution=0;
+		  Sockets[i].AnomaliesExecution++;
+		}
+		
+		if (Sockets[i].AnomaliesExecution>MAXANOMALIES)
+		{
+		  Sockets[i].etape=6;
+		  
+		 // if ( compt % 1000 == 0)
+		  {
+		    IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s. Pas d acknowledge reÃ§u aprÃšs l ordre GOTO. DÃ©connexion de l antenne.",
+				Sockets[i].IP.c_str());
+				Sockets[i].Connected=false;
+		  }
+		}
+	      }
+	    }
+	    break;
+	    
+	    //goto ok  ?
+	    case 5 :
+	    {
+	      if (Sockets[i].GotoOk)
+	      {
+		Sockets[i].AttenteExecution=0;
+		Sockets[i].AnomaliesExecution=0;
+		Sockets[i].etape++;
+	      }
+	      else
+	      {
+		// on rÃ©itÃšre l'ordre prÃ©cÃ©dent si rien ne se passe
+		
+		Sockets[i].AttenteExecution++;
+		
+		if (Sockets[i].AttenteExecution>MAXATTENTE)
+		{
+		  Sockets[i].etape=5;
+		  Sockets[i].AttenteExecution=0;
+		  Sockets[i].AnomaliesExecution++;
+		}
+		
+		if (Sockets[i].AnomaliesExecution>MAXANOMALIESGOTO)
+		{
+		  Sockets[i].etape=6;
+		  
+		 // if ( compt % 1000 == 0)
+		  {
+		    IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s. L antenne n a pas renvoyÃ© GOTO/OK. DÃ©connexion de l antenne.",
+				Sockets[i].IP.c_str());
+				Sockets[i].Connected=false;
+				
+				
+		  }
+		}
+	      }
+	    }
+	    break;
+	    
+	  }
+	}
+      }
+      
+      
+      
+      
+      
+      
+      // DÃ©tection d'anomalies concernant l'envoi de trames sur la socket. dÃ©connexion du micro-cont ?
+      
+      for (int i=1; i<SocketsNumber; i++) if (Sockets[i].Connected)
+      {
+	if (Sockets[i].sendalertes > 0)
+	{
+	  Sockets[i].etape=5;
+	  
+	//  if ( compt % 1000 == 0)
+	  {
+	    IDSetSwitch(&OnCoordSetSP, "Anomalie dÃ©tectÃ©e sur l antenne %s. DÃ©connexion de l antenne.",
+			Sockets[i].IP.c_str());
+			
+			Sockets[i].Connected=false;
+	  }
+	}
+      }
+      
+      
+      
+      //On attend que toutes les antennes soient prÃªtes pour lancer l'ordre Goto -> meilleure synchronisation
+      
+      int num=0;
+      
+      for (int i=1; i<SocketsNumber; i++) if (Sockets[i].Connected)
+      {
+	if (Sockets[i].etape == 3) num++; //fin de la procÃ©dure LecturePosition. Les antennes sont prÃªtes
+	  //Ã  recevoir l'ordre GOto
+      }
+      
+      if ((num == AntennesConnectees()) && (num>0))
+      {
+	for (int i=1; i<SocketsNumber; i++ ) if (Sockets[i].Connected)
+	{
+	  Sockets[i].ack_goto=false;
+	  Sockets[i].AttenteExecution=0;
+          Sockets[i].AnomaliesExecution=0;
+	  
+	  if (!GOTO(i, Sockets[i].Pos.x - TargetPosition.x, Sockets[i].Pos.y - TargetPosition.y )) Sockets[i].sendalertes++;
+	  
+	  Sockets[i].etape++;
+	}
+      }
+      
+      
+       
+    }
+    
+    ISPOLLRunning=false;
+  }
+  
+  
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  bool BAO::process_coords()
+  {
+    switch (currentSet)
+    {
+      // Transit
+      case BAO_TRANSIT:
+	
+	EquatorialCoordsWNP.s = IPS_BUSY;
+	
+	IDSetNumber (&EquatorialCoordsWNP, NULL);
+	
+	InitAntennes();
+	
+	JJAnc=JJ;
+	
+	TrackingMode = 1;
+	
+	Goto=true;
+	
+	LastGotoOK=false;
+	
+	LecturePosition=true;
+	
+	ADDEC2Motor(targetRA, targetDEC);
+	
+	break;
+	
+	// Tracking
+      case BAO_TRACKING:
+	
+	EquatorialCoordsWNP.s = IPS_BUSY;
+	
+	IDSetNumber (&EquatorialCoordsWNP, NULL);
+	
+	InitAntennes();
+	
+	JJAnc=JJ;
+	
+	TrackingMode = 2;
+	
+	Goto=true;
+	
+	LastGotoOK=false;
+	
+	LecturePosition=true;
+	
+	ADDEC2Motor(targetRA, targetDEC);
+	
+	break;
+    }
+    
+    return true;
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  int BAO::get_switch_index(ISwitchVectorProperty *sp)
+  {
+    for (int i=0; i < sp->nsp ; i++)
+      if (sp->sp[i].s == ISS_ON)
+	return i;
+      
+      return -1;
+  }
+  
+  /**************************************************************************************
+  ** Activation de l'interface
+  ***************************************************************************************/
+  void BAO::connect_telescope()
+  {
+    switch (ConnectSP.sp[0].s)
+    {
+      case ISS_ON:
+	ConnectS[0].s = ISS_ON;
+	ConnectS[1].s = ISS_OFF;
+	IDLog("\nHello BAORadio !\n");
+	
+	ConnectSP.s = IPS_OK;
+	IDSetSwitch (&ConnectSP, "BAORadio is online. Retrieving basic data...");
+	
+	
+	break;
+	
+      case ISS_OFF:
+	ConnectS[0].s = ISS_OFF;
+	ConnectS[1].s = ISS_ON;
+	ConnectSP.s = IPS_IDLE;
+	
+	SocketsNumber=1;
+	InitThreadOK=false;
+	
+	for (int i=0; i<MAXHOSTNAME; i++)
+	{
+	  Sockets[i].Connected=false;
+	  Sockets[i].IP="";
+	  Sockets[i].new_sock.shutdown();
+	}
+	
+	InitAntennes();
+	
+	IDSetSwitch (&ConnectSP, "BAORadio is offline.");
+	IDLog("Telescope is offline.");
+	
+	break;
+    }
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void BAO::get_initial_data()
+  {
+    //  IDSetNumber (&EquatorialCoordsRNP, NULL);
+    
+     
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void BAO::slew_error(int slewCode)
+  {
+    OnCoordSetSP.s = IPS_IDLE;
+    
+    if (slewCode == 1)
+      IDSetSwitch (&OnCoordSetSP, "Object below horizon.");
+    else if (slewCode == 2)
+      IDSetSwitch (&OnCoordSetSP, "Object below the minimum elevation limit.");
+    else
+      IDSetSwitch (&OnCoordSetSP, "Slew failed.");
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void BAO::enable_simulation(bool enable)
+  {
+    simulation = enable;
+    
+    if (simulation)
+      IDLog("Warning: Simulation is activated.\n");
+    else
+      IDLog("Simulation is disabled.\n");
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void BAO::connection_lost()
+  {
+    ConnectSP.s = IPS_IDLE;
+    IDSetSwitch(&ConnectSP, "The connection to the telescope is lost.");
+    return;
+  }
+  
+  /**************************************************************************************
+  **
+  ***************************************************************************************/
+  void BAO::connection_resumed()
+  {
+    ConnectS[0].s = ISS_ON;
+    ConnectS[1].s = ISS_OFF;
+    ConnectSP.s = IPS_OK;
+    
+    IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed.");
+  }
+  
+  
+  /**************************************************************************************
+  **  Envoi d'une commande sur le socket puis attente de l'acknowledge
+  ***************************************************************************************/
+  
+  bool BAO::COMMANDE(int numsocket, char* Commande, char* Params)
+  {
+    char chaine[MAXCARACTERES];
+    
+    try
+    {
+      sprintf(chaine, "%s%s\n", Commande, Params);
+      
+      Sockets[numsocket].new_sock << chaine;
+    }
+    catch (SocketException& e)
+    {        
+      Sockets[numsocket].new_sock.shutdown();
+      Sockets[numsocket].new_sock.create();
+      Sockets[numsocket].Connected = Sockets[numsocket].new_sock.connect((std::string)Sockets[numsocket].IP);
+      
+      if (Sockets[numsocket].Connected)
+      {
+	Sockets[numsocket].AttenteExecution=0;
+	Sockets[numsocket].AnomaliesExecution=0;
+      }
+      
+      //  if (AntennesConnectees() == 0) { InitAntennes(); InitThreadOK=false;}
+      
+      std::string oss;
+      oss="COMMANDE exception : " + e.description() + "\n";
+      size_t size = oss.size() + 1;
+      char* buffer = new char[size];
+      strncpy(buffer, oss.c_str(), size);
+      
+      IDLog(buffer);
+      
+      delete [] buffer;
+      
+      return false;
+    }
+    
+    return true;
+  }
+  
+  
+  /**************************************************************************************
+  ** Commande POSITION
+  ***************************************************************************************/
+  
+  bool BAO::POSITION(int numsocket)
+  {
+    return COMMANDE(numsocket, (char*)"P", (char*)"");
+  }
+  
+  /**************************************************************************************
+  ** Commande PARK
+  ***************************************************************************************/
+  
+  bool BAO::PARK(int numsocket)
+  {
+    return COMMANDE(numsocket, (char*)"Z", (char*)"");
+  }
+  
+  /**************************************************************************************
+  ** Commande ABORT
+  ***************************************************************************************/
+  
+  bool BAO::ABORT(int numsocket)
+  {
+    return COMMANDE(numsocket, (char*)"A", (char*)"");
+  }
+  
+  
+  /**************************************************************************************
+  ** Commande GOTO
+  ***************************************************************************************/
+  
+  bool BAO::GOTO(int numsocket, int deltaAz, int deltaAlt)
+  {
+    char Params[MAXCARACTERES];
+    char sensAz;
+    char sensAlt;
+    
+    sensAlt='b';
+    sensAz='b';
+    
+    if (deltaAz<0)
+    {
+      deltaAz=-deltaAz;
+      sensAz='f';
+    }
+    
+    if (deltaAlt<0)
+    {
+      deltaAlt=-deltaAlt;
+      sensAlt='f';
+    }
+    
+    sprintf(Params, "%c%04i%c%04i", sensAz, deltaAz, sensAlt, deltaAlt);
+    
+    return COMMANDE(numsocket, (char*)"G", Params);
+  }
+  
+  
+  
Index: /BAORadio/libindi/v1/drivers/telescope/BAO.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/BAO.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/BAO.h	(revision 500)
@@ -0,0 +1,198 @@
+/*
+    LX200 Basic Driver
+    Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef BAO_H
+#define BAO_H
+
+#include "indidevapi.h"
+#include "indicom.h"
+#include "ServerSocket.h"
+#include "SocketException.h"
+#include "astro.h"
+
+#define MAXCARACTERES 1024
+
+#define MAXATTENTE 80                //Si une commande ne recoit pas d'acknowledge. Alors refaire 80 tentatives en renvoyant la commande
+#define MAXANOMALIES 2               //Si pas de rÃ©ponse au bout de 80 tentatives -> erreur critique -> socket perdu ?
+#define MAXANOMALIESGOTO 1500
+
+struct Position
+{
+    int x;
+    int y;
+};
+
+struct DefSocket
+{
+    ServerSocket new_sock;
+    
+    std::string IP;              //IP de l'antenne
+    
+    bool Connected;              //le micro-contrÃŽleur est-il connectÃ© ?
+    bool PosValides;             //le micro-contrÃŽleur a-t-il donnÃ© une position valide ?
+    char status;                 //status='B' pour busy  'R' pour READY
+    int sendalertes;             //une requÃªte "send" a gÃ©nÃ©rÃ© une erreur sur le rÃ©seau
+    int AttenteExecution;	 //L'antenne parvient-elle Ã  executer un cycle de commandes ?
+    int AnomaliesExecution;	 //Erreur critique. L'antenne ne rÃ©pond plus !
+                    
+    Position Pos;                //derniÃšre position retournÃ©e par le microcontrÃŽleur    
+    int etape;
+    
+    bool ack_status;             //Etat des acknowledges ?
+    bool ack_pos;
+    bool ack_park;
+    bool ack_abort;
+    bool ack_goto;
+    bool GotoOk;                 //Est-ce que le dernier goto est OK ?
+};
+
+ServerSocket server( 8000 );
+int SocketsNumber;
+bool InitThreadOK;
+DefSocket Sockets[MAXHOSTNAME + 1];
+pthread_t th1;
+
+class BAO : public Astro
+{
+public:
+    BAO();
+    ~BAO();
+    
+    void ISGetProperties (const char *dev);
+    void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+    void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+    void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+    void ISPoll ();
+    void InitThread();
+ 
+    bool COMMANDE(int numsocket, char* Commande, char* Params);
+    Position ExtractPosition(std::string str);
+  
+    void connection_lost();
+    void connection_resumed();
+    
+    bool STATUS(int numsocket);
+    bool POSITION(int numsocket);
+    bool ABORT(int numsocket);
+    bool PARK(int numsocket);
+    bool GOTO(int numsocket, int deltaAz, int deltaAlt);
+    void ADDEC2Motor(double newRA, double newDEC);
+    int  AntennesConnectees();
+    void InitAntennes();
+    
+        
+    
+private:
+
+    enum BAO_STATUS { BAO_TRANSIT, BAO_TRACKING, BAO_PARK };
+
+    /* Switches */
+    ISwitch ConnectS[2];
+    ISwitch OnCoordSetS[2];
+    ISwitch AbortSlewS[1];
+    ISwitch ParkS[1];
+
+    /* Texts */
+    IText PortT[1];
+    IText ObjectT[1];
+
+    /* Numbers */
+    //INumber EquatorialCoordsRN[2];
+    INumber EquatorialCoordsWN[2];
+    INumber GeographicCoordsWN[2];
+    INumber ActualisationN1[1];
+    INumber ActualisationN2[1];
+    
+    //INumber SlewAccuracyN[2];
+    //INumber TrackAccuracyN[2];
+
+    /* Switch Vectors */
+    ISwitchVectorProperty ConnectSP;
+    ISwitchVectorProperty OnCoordSetSP;
+    ISwitchVectorProperty AbortSlewSP;
+    ISwitchVectorProperty ParkSP;
+
+    /* Number Vectors */
+    //INumberVectorProperty EquatorialCoordsRNP;
+    INumberVectorProperty EquatorialCoordsWNP;
+    INumberVectorProperty GeographicCoordsWNP;
+    //INumberVectorProperty SlewAccuracyNP;
+    //INumberVectorProperty TrackAccuracyNP;
+    INumberVectorProperty ActualisationNP1;
+    INumberVectorProperty ActualisationNP2;
+   
+
+    /* Text Vectors */
+    ITextVectorProperty PortTP;
+    ITextVectorProperty ObjectTP;
+
+    /*******************************************************/
+    /* Connection Routines
+    ********************************************************/
+    void init_properties();
+    void get_initial_data();
+    void connect_telescope();
+    bool is_connected(void);
+
+    /*******************************************************/
+    /* Misc routines
+    ********************************************************/
+    bool process_coords();
+    int get_switch_index(ISwitchVectorProperty *sp);
+
+    /*******************************************************/
+    /* Simulation Routines
+    ********************************************************/
+    void enable_simulation(bool enable);
+
+    /*******************************************************/
+    /* Error handling routines
+    ********************************************************/
+    void slew_error(int slewCode);
+    void reset_all_properties();
+    void handle_error(INumberVectorProperty *nvp, int err, const char *msg);
+    void correct_fault();
+
+protected:
+
+    double JD;				/* Julian Date */
+    double lastRA;
+    double lastDEC;
+    double JJAnc;                       // Sauvegarde du jour julien de la derniÃšre actualisation de la position (fct Goto)
+    double ActualisationTM1;
+    double ActualisationTM2;
+    bool   simulation;
+    bool   fault;
+    bool   LecturePosition;             // Ã©tape dans le processus d'actualisation de la position
+    bool   Abort;
+    bool   Park;
+    bool   Goto;
+    bool   BAOConnected;
+    bool   LastGotoOK;
+    
+    int    fd;				/* Telescope tty file descriptor */
+    int    currentSet;
+    int    lastSet; 
+    int    TrackingMode;                //1 : Transit           2: Tracking
+     
+    Position TargetPosition;            //Position Ã  atteindre en coordonnÃ©es Ã©quatoriales 
+};
+
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/ServerSocket.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/ServerSocket.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/ServerSocket.cpp	(revision 500)
@@ -0,0 +1,94 @@
+// Implementation of the ServerSocket class
+// Franck RICHARD
+// BAORadio
+
+#include "ServerSocket.h"
+#include "SocketException.h"
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+
+
+ServerSocket::ServerSocket ( int port )
+{
+    if ( ! Socket::create() )
+    {
+        throw SocketException ( "Could not create server socket." );
+    }
+
+    if ( ! Socket::bind ( port ) )
+    {
+        throw SocketException ( "Could not bind to port." );
+    }
+
+    if ( ! Socket::listen() )
+    {
+        throw SocketException ( "Could not listen to socket." );
+    }
+
+    Socket::set_non_blocking(true);
+}
+
+ServerSocket::~ServerSocket()
+{
+}
+
+
+const ServerSocket& ServerSocket::operator << ( const std::string& s ) const
+{
+    if ( ! Socket::send ( s ) )
+    {
+        throw SocketException ( "Could not write to socket." );
+    }
+
+    return *this;
+
+}
+
+
+const ServerSocket& ServerSocket::operator >> ( std::string& s ) const
+{
+    if ( ! Socket::recv ( s ) )
+    {
+        throw SocketException ( "Could not read from socket." );
+    }
+
+    return *this;
+}
+
+
+void ServerSocket::accept ( ServerSocket& sock )
+{
+    if ( ! Socket::accept ( sock ) )
+    {
+        throw SocketException ( "Could not accept socket." );
+    }
+}
+
+void ServerSocket::shutdown ( )
+{
+    if ( ! Socket::shutdown (  ) )
+    {
+        throw SocketException ( "Could not shutdown socket." );
+    }
+}
+
+void ServerSocket::create ( )
+{
+    if ( ! Socket::create (  ) )
+    {
+        throw SocketException ( "Could not create socket." );
+    }
+}
+
+bool ServerSocket::connect(std::string IP ) 
+{
+   return Socket::connect (IP, 8000);  
+}
+
+std::string ServerSocket::recupip( ServerSocket& sock)
+{ 
+   return ( Socket::recupip() ); 
+}
Index: /BAORadio/libindi/v1/drivers/telescope/ServerSocket.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/ServerSocket.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/ServerSocket.h	(revision 500)
@@ -0,0 +1,34 @@
+// Definition of the ServerSocket class
+
+#ifndef ServerSocket_class
+#define ServerSocket_class
+
+#include "Socket.h"
+
+
+
+
+class ServerSocket : private Socket
+{
+ public:
+
+  ServerSocket ( int port );
+  ServerSocket (){};
+  virtual ~ServerSocket();
+
+  const ServerSocket& operator << ( const std::string& ) const;
+  const ServerSocket& operator >> ( std::string& ) const;
+  
+  void accept ( ServerSocket& );
+
+  void shutdown ( );
+  
+  void create();
+  
+  bool connect(std::string IP );
+  
+  std::string recupip( ServerSocket& );
+};
+
+
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/Socket.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/Socket.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/Socket.cpp	(revision 500)
@@ -0,0 +1,235 @@
+// Implementation of the Socket class.
+
+
+#include "Socket.h"
+#include "string.h"
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <iostream>
+#include <netinet/tcp.h>
+
+
+
+Socket::Socket() :
+        m_sock ( -1 )
+{
+
+    memset ( &m_addr,
+             0,
+             sizeof ( m_addr ) );
+}
+
+Socket::~Socket()
+{
+    if ( is_valid() )
+        ::close ( m_sock );
+}
+
+bool Socket::create()
+{
+    m_sock = socket ( AF_INET,
+                      SOCK_STREAM,
+                      0); //IPPROTO_TCP
+
+    if ( ! is_valid() )
+        return false;
+
+
+    int on = 1;
+
+    if ( setsockopt ( m_sock, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 ) return false;
+
+    // RÃ©duire les dÃ©lais lors des transmissions TCP/IP
+    // Voir article Ã  l'adresse
+    // http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_MRG/1.0/html/Realtime_Tuning_Guide/sect-Realtime_Tuning_Guide-Application_Tuning_and_Deployment-TCP_NODELAY_and_Small_Buffer_Writes.html
+    
+    if ( setsockopt(m_sock, SOL_TCP, TCP_NODELAY, (const char*) &on, sizeof(on)) < 0 ) return false;
+
+    return true;
+}
+
+
+
+bool Socket::bind ( const int port )
+{
+    if ( ! is_valid() ) return false;
+    
+    m_addr.sin_family = AF_INET;
+    m_addr.sin_addr.s_addr = INADDR_ANY;
+    m_addr.sin_port =  htons ( port );
+
+    int bind_return = ::bind ( m_sock,
+                               ( struct sockaddr * ) &m_addr,
+                               sizeof ( m_addr ) );
+
+
+    if ( bind_return == -1 ) return false;
+    
+    return true;
+}
+
+
+bool Socket::listen() const
+{
+    if ( ! is_valid() ) return false;
+    
+    int listen_return = ::listen ( m_sock, MAXCONNECTIONS );
+
+    if ( listen_return == -1 ) return false;
+    
+    return true;
+}
+
+
+bool Socket::accept ( Socket& new_socket ) const
+{
+    int addr_length = sizeof ( m_addr );
+    
+    new_socket.m_sock = ::accept ( m_sock, ( sockaddr * ) &m_addr, ( socklen_t * ) &addr_length );
+
+    if ( new_socket.m_sock <= 0 ) return false;
+        
+    return true;
+}
+
+
+bool Socket::shutdown()
+{
+  int ret = 0;
+
+  if ( is_valid() )
+      ret =  ::shutdown ( m_sock, 2 );
+  
+  m_sock=-1;
+
+  if ( ret == 0 ) return true;
+
+  return false;
+}
+
+
+bool Socket::send ( const std::string s ) const
+{
+    if ( ! is_valid() ) return false;
+    
+    int status = ::send ( m_sock, s.c_str(), s.size(), MSG_NOSIGNAL);
+    
+    if ( status == -1 ) return false;
+        
+    return true;    
+}
+
+
+int Socket::recv ( std::string& s ) const
+{
+    int sel;
+    fd_set r;
+    struct timeval timeout;
+    
+    if ( ! is_valid() ) return false;
+    
+    s="";
+
+    timeout.tv_sec = 0; // initialise le timeout, ici  les secondes
+    timeout.tv_usec = 1; // les microsecondes
+
+    FD_ZERO(&r); // initialise la liste de fd
+    FD_SET(m_sock, &r); // ajoute la socket dans la liste des fd
+    sel = select(m_sock + 1, &r, NULL, NULL, &timeout);
+    if (sel < 0) // select a rencontrÃ© un problÃšme
+    {
+        return -1;
+    }
+    else if (sel == 0) // timeout
+    {
+	return 1;
+    }
+    else // quelque chose est Ã  lire sur un file descriptor
+    {
+        if (FD_ISSET(m_sock, &r)) // si la socket est prÃªte Ã  Ãªtre lue
+        {
+            char buf [ MAXRECV + 1 ];
+
+            s = "";
+
+            memset ( buf, 0, MAXRECV + 1 );
+
+            int status = ::recv ( m_sock, buf, MAXRECV, 0 );
+
+            if ( status == -1 )
+            {
+	         // lÃ , nous ne sommes pas en prÃ©sence d'une vraie erreur
+		 // car le mode non-bloquant est activÃ© ici
+		 // (consulter la doc de la fct recv...)
+                 if (errno == EAGAIN )
+		 {
+	           return 0;
+		 }
+		 
+		 return -1;
+            }
+            else if ( status == 0 )
+            {
+                return 0;
+            }
+            else
+            {
+                s = buf;
+                return status;
+            }
+        }
+    }
+}
+
+
+
+bool Socket::connect ( const std::string host, const int port )
+{
+    if ( ! is_valid() ) return false;
+    
+    memset ( &m_addr,
+             0,
+             sizeof ( m_addr ) );
+
+
+    m_addr.sin_family = AF_INET;
+    m_addr.sin_port = htons ( port );
+
+    int status = inet_pton ( AF_INET, host.c_str(), &m_addr.sin_addr );
+
+    if ( errno == EAFNOSUPPORT ) return false;
+
+    status = ::connect ( m_sock, ( sockaddr * ) &m_addr, sizeof ( m_addr ) );
+
+    if ( status == 0 ) return true;
+    
+    return false;
+}
+
+void Socket::set_non_blocking ( const bool b )
+{
+    int opts;
+
+    opts = fcntl ( m_sock,F_GETFL );
+
+    if ( opts < 0 )
+    {
+        return;
+    }
+
+    if ( b )
+        opts = ( opts | O_NONBLOCK );
+    else
+        opts = ( opts & ~O_NONBLOCK );
+
+    fcntl ( m_sock,
+            F_SETFL,opts );
+
+}
+
+
+std::string Socket::recupip() const
+{
+    return inet_ntoa(m_addr.sin_addr);
+}
Index: /BAORadio/libindi/v1/drivers/telescope/Socket.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/Socket.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/Socket.h	(revision 500)
@@ -0,0 +1,56 @@
+// Definition of the Socket class
+
+#ifndef Socket_class
+#define Socket_class
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string>
+#include <arpa/inet.h>
+
+
+const int MAXHOSTNAME = 501;
+const int MAXCONNECTIONS = 254;
+const int MAXRECV = 1024;
+
+  
+class Socket
+{
+ public:
+  Socket();
+  virtual ~Socket();
+
+  // Server initialization
+  bool create();
+  bool bind ( const int port );
+  bool listen() const;
+  bool accept ( Socket& ) const;
+
+  // Client initialization
+  bool connect ( const std::string host, const int port );
+
+  // Data Transimission
+  bool send ( const std::string ) const;
+  int recv ( std::string& ) const;
+
+  std::string recupip() const;
+
+  void set_non_blocking ( const bool );
+
+  bool is_valid() const { return m_sock != -1; }
+
+  bool shutdown();
+  
+ private:
+
+  int m_sock;
+  sockaddr_in m_addr;
+
+};
+
+
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/SocketException.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/SocketException.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/SocketException.h	(revision 500)
@@ -0,0 +1,23 @@
+// SocketException class
+
+
+#ifndef SocketException_class
+#define SocketException_class
+
+#include <string>
+
+class SocketException
+{
+ public:
+  SocketException ( std::string s ) : m_s ( s ) {};
+  ~SocketException (){};
+
+  std::string description() { return m_s; }
+
+ private:
+
+  std::string m_s;
+
+};
+
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/astro.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/astro.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/astro.cpp	(revision 500)
@@ -0,0 +1,210 @@
+#include "astro.h"
+
+////////////////////
+// Routines Astro //
+////////////////////
+
+Astro::Astro()
+{
+    Longitude=0.0;
+    Latitude=0.0;
+    Lst=0.0;
+    JJ=0.0;
+    CorP=0.0;
+    CorEP=0.0;
+    Annee=0.0;
+    Mois=0.0;
+    Jour=0.0;
+    Heu=0.0;
+    Min=0.0;
+    Sec=0.0;
+    ep=0.0;
+    hs=0.0;
+    UTCP=0.0;
+    tsl=0.0;
+}
+
+Astro::~Astro()
+{
+}
+
+
+//0<=Angle<=2*PI
+double Astro::VerifAngle(double Angle)
+{
+    Angle=fmod(Angle, Pi2);
+    if (Angle<0.0) Angle+=Pi2;
+
+    return(Angle);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//Nutation
+
+void Astro::Nutation()
+{
+    double T,L,LP,M,MP,O,L2,LP2,O2;
+
+    T=(JJ-2415020.0)/36525.0;
+
+    L=(279.6967+(36000.7689+0.000303*T)*T)*Pidiv180;
+    LP=(270.4342+(481267.8831-0.001133*T)*T)*Pidiv180;
+    M=(358.4758+(35999.0498-0.000150*T)*T)*Pidiv180;
+    MP=(296.1046+(477198.8491+0.009192*T)*T)*Pidiv180;
+    O=(259.1833+(-1934.1420+0.002078*T)*T)*Pidiv180;
+
+    L2=2.0*L;
+    LP2=2.0*LP;
+    O2=2.0*O;
+
+    CorP=-(17.2327+0.01737*T)*sin(O)
+         -(1.2729+0.00013*T)*sin(L2)
+         +0.2088*sin(O2)
+         -0.2037*sin(LP2)
+         +(0.1261-0.00031*T)*sin(M)
+         +0.0675*sin(MP)
+         -(0.0497-0.00012*T)*sin(L2+M)
+         -0.0342*sin(LP2-O)
+         -0.0261*sin(LP2+MP)
+         +0.0214*sin(L2-M)
+         -0.0149*sin(L2-LP2+MP)
+         +0.0124*sin(L2-O)
+         +0.0114*sin(LP2-MP);
+
+    CorEP=(9.2100+0.00091*T)*cos(O)
+          +(0.5522-0.00029*T)*cos(L2)
+          -0.0904*cos(O2)
+          +0.0884*cos(LP2)
+          +0.0216*cos(L2+M)
+          +0.0183*cos(LP2-O)
+          +0.0113*cos(LP2+MP)
+          -0.0093*cos(L2-M)
+          -0.0066*cos(L2-O);
+
+    CorP=CorP/3600.0*Pidiv180;
+    CorEP=CorEP/3600.0*Pidiv180;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// calcul Jour julien
+
+void Astro::CalculJJ(double Heure)
+{
+
+    long y, a, b, c, e, m;
+
+    long year = (long)Annee;
+    int month = (int)Mois;
+    double day = Jour + Heure;
+
+
+    y = year + 4800;
+
+    m = month;
+    if ( m <= 2 )
+    {
+        m += 12;
+        y -= 1;
+    }
+    e = (306 * (m+1))/10;
+
+    a = y/100;
+    if ( year <= 1582L )
+    {
+        if ( year == 1582L )
+        {
+            if ( month < 10 )
+                goto julius;
+            if ( month > 10)
+                goto gregor;
+            if ( day >= 15 )
+                goto gregor;
+        }
+julius:
+
+        b = -38;
+    }
+    else
+    {
+
+gregor:
+        b = (a/4) - a;
+    }
+
+    c = (36525L * y)/100;
+
+    JJ = b + c + e + day - 32167.5;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//ObliquitÃ©
+
+void Astro::Obliquite(double JJ)
+{
+    double T;
+
+    T = (JJ-2415020.0) / 36525.0;
+
+    ep = (23.452294+ (((0.000000503 * T ) - 0.00000164 ) * T - 0.0130125 ) * T ) * Pidiv180;
+}
+
+///////////////////////////////////////////////////////////////////////
+//Temps sidÃ©ral local
+
+double Astro::TSL(double JJ, double HeureSiderale, double Longitude)
+{
+    double rd,T;
+
+    T = (JJ - 2415020.0 ) / 36525.0;
+    rd = 0.276919398 + ( 100.0021359 + 0.000001075 * T ) * T;
+    rd += HeureSiderale;
+    rd *= Pi2;
+    rd += CorP * cos(ep);
+    rd -= Longitude;
+
+    return VerifAngle(rd);
+}
+
+
+void Astro::CalculTSL()
+{
+    hs=(Heu+Min/60.0+Sec/3600.0)/24.0;
+
+    hs-=UTCP/24.0;
+
+    CalculJJ(hs);
+
+    Obliquite(JJ);
+
+    Nutation();
+
+    tsl=TSL(JJ, hs, Longitude);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//Azimut et hauteur Ã  partir de AR et Dec
+
+void Astro::Azimut(double ts, double Latitude, double Ar, double De, double *azi, double *hau)
+{
+    double ah, ht, a1, az, zc, ac;
+
+    ah=ts-Ar;
+
+    zc=sin(Latitude)*sin(De)+cos(Latitude)*cos(De)*cos(ah);
+    ht=atan(zc/sqrt((-zc*zc)+1.0));
+
+    a1=cos(De)*sin(ah)/cos(ht);
+    ac=(-cos(Latitude)*sin(De)+sin(Latitude)*cos(De)*cos(ah))/cos(ht);
+    az=atan(a1/sqrt((-a1*a1)+1.0));
+    if (ac<0.0) az=Pi-az;
+
+    az=VerifAngle(Pi+az);
+
+    *azi=az;
+    *hau=ht;
+}
+
Index: /BAORadio/libindi/v1/drivers/telescope/astro.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/astro.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/astro.h	(revision 500)
@@ -0,0 +1,54 @@
+// Definition of the Astro class
+// Franck RICHARD
+// BAORadio
+
+#ifndef Astro_class
+#define Astro_class
+
+#include "math.h"
+
+//////////////////////////////
+// Constantes MathÃ©matiques //
+//////////////////////////////
+
+#define Pi		3.14159265358979323846264338327
+#define Pidiv180	0.01745329251994329576923690768
+#define N180divPi	57.2957795130823208767981548141
+#define Pi2          	6.28318530717958647692528676655
+#define Pidiv2		1.57079632679489661923132169163
+
+
+class Astro
+{
+public:
+    Astro();
+    ~Astro();
+
+    double VerifAngle(double Angle);
+    void  Azimut(double ts, double Latitude, double Ar, double De, double *azi, double *hau);
+    void  CalculJJ(double Heure);
+    double TSL(double JJ,double HeureSiderale,double Longitude);
+    void Nutation();
+    void Obliquite(double JJ);
+    void CalculTSL();
+    
+    double Longitude;
+    double Latitude;
+    double Lst;
+    double JJ;
+    double CorP;
+    double CorEP;
+    double Annee;
+    double Mois;
+    double Jour;
+    double Heu;
+    double Min;
+    double Sec;
+    double ep;
+    double hs;
+    double UTCP;
+    double tsl;
+};
+
+
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/celestrongps.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/celestrongps.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/celestrongps.cpp	(revision 500)
@@ -0,0 +1,846 @@
+#if 0
+    Celestron GPS
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "celestronprotocol.h"
+#include "celestrongps.h"
+
+#define mydev 		"Celestron GPS"
+
+/* Handy Macros */
+#define currentRA	EquatorialCoordsRN[0].value
+#define currentDEC	EquatorialCoordsRN[1].value
+#define targetRA	EquatorialCoordsWN[0].value
+#define targetDEC	EquatorialCoordsWN[1].value
+
+/* Enable to log debug statements 
+#define CELESTRON_DEBUG	1
+*/
+
+CelestronGPS *telescope = NULL;
+
+
+/* There is _one_ binary for all LX200 drivers, but each binary is renamed
+** to its device name (i.e. lx200gps, lx200_16..etc). The main function will
+** fetch from std args the binary name and ISInit will create the apporpiate
+** device afterwards. If the binary name does not match any known devices,
+** we simply create a generic device
+*/
+extern char* me;
+
+#define COMM_GROUP	"Communication"
+#define BASIC_GROUP	"Main Control"
+#define MOVE_GROUP	"Movement Control"
+
+static void ISPoll(void *);
+
+/*INDI controls */
+static ISwitch SlewModeS[]       = {{"Slew", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0, 0}};
+
+/* Equatorial Coordinates: Request */
+static INumber EquatorialCoordsWN[] = {    {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0},    {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}};
+static INumberVectorProperty EquatorialCoordsWNP = {  mydev, "EQUATORIAL_EOD_COORD_REQUEST", "Equatorial JNow", BASIC_GROUP, IP_WO, 120, IPS_IDLE,  EquatorialCoordsWN, NARRAY(EquatorialCoordsWN), "", 0};
+
+/* Equatorial Coordinates: Info */
+static INumber EquatorialCoordsRN[] = {    {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0},    {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}};
+static INumberVectorProperty EquatorialCoordsRNP = {  mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 120, IPS_IDLE,  EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), "", 0};
+
+/* Tracking precision */
+INumber TrackingAccuracyN[] = {
+    {"TrackRA",  "RA (arcmin)", "%10.6m",  0., 60., 1., 3.0, 0, 0, 0},
+    {"TrackDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0, 0, 0, 0},
+};
+static INumberVectorProperty TrackingAccuracyNP = {mydev, "Tracking Accuracy", "", MOVE_GROUP, IP_RW, 0, IPS_IDLE, TrackingAccuracyN, NARRAY(TrackingAccuracyN), "", 0};
+
+/* Slew precision */
+INumber SlewAccuracyN[] = {
+    {"SlewRA",  "RA (arcmin)", "%10.6m",  0., 60., 1., 3.0, 0, 0, 0},
+    {"SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0, 0, 0, 0},
+};
+static INumberVectorProperty SlewAccuracyNP = {mydev, "Slew Accuracy", "", MOVE_GROUP, IP_RW, 0, IPS_IDLE, SlewAccuracyN, NARRAY(SlewAccuracyN), "", 0};
+
+/* Fundamental group */
+static ISwitch ConnectS[]          = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty ConnectSP	= { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0};
+
+static IText PortT[]			= {{"PORT", "Port", 0, 0, 0, 0}};
+static ITextVectorProperty PortTP		= { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
+
+/* Movement group */
+static ISwitch OnCoordSetS[]     = {{"SLEW", "Slew", ISS_ON, 0 , 0}, {"TRACK", "Track", ISS_OFF, 0, 0}, {"SYNC", "Sync", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty OnCoordSetSP    = { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
+
+static ISwitch AbortSlewS[]      = {{"ABORT", "Abort", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty AbortSlewSP     = { mydev, "TELESCOPE_ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, AbortSlewS, NARRAY(AbortSlewS), "", 0};
+static ISwitchVectorProperty SlewModeSP      = { mydev, "Slew rate", "", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0};
+
+/* Movement (Arrow keys on handset). North/South */
+static ISwitch MovementNSS[]       = {{"MOTION_NORTH", "North", ISS_OFF, 0, 0}, {"MOTION_SOUTH", "South", ISS_OFF, 0, 0}};
+
+static ISwitchVectorProperty MovementNSSP      = { mydev, "TELESCOPE_MOTION_NS", "North/South", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementNSS, NARRAY(MovementNSS), "", 0};
+
+/* Movement (Arrow keys on handset). West/East */
+static ISwitch MovementWES[]       = {{"MOTION_WEST", "West", ISS_OFF, 0, 0}, {"MOTION_EAST", "East", ISS_OFF, 0, 0}};
+
+static ISwitchVectorProperty MovementWESP      = { mydev, "TELESCOPE_MOTION_WE", "West/East", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0};
+
+
+/* send client definitions of all properties */
+void ISInit()
+{
+  static int isInit=0;
+
+ if (isInit)
+  return;
+
+ isInit = 1;
+
+  IUSaveText(&PortT[0], "/dev/ttyS0");
+  
+  telescope = new CelestronGPS();
+
+  IEAddTimer (POLLMS, ISPoll, NULL);
+}
+
+void ISGetProperties (const char *dev)
+{ ISInit(); telescope->ISGetProperties(dev);}
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{ ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);}
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{ ISInit(); telescope->ISNewText(dev, name, texts, names, n);}
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{ ISInit(); telescope->ISNewNumber(dev, name, values, names, n);}
+void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;}
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+/**************************************************
+*** LX200 Generic Implementation
+***************************************************/
+
+CelestronGPS::CelestronGPS()
+{
+
+   lastRA = 0;
+   lastDEC = 0;
+   currentSet   = 0;
+   lastSet      = -1;
+
+   // Children call parent routines, this is the default
+   IDLog("initilizaing from Celeston GPS device...\n");
+
+}
+
+void CelestronGPS::ISGetProperties(const char *dev)
+{
+
+ if (dev && strcmp (mydev, dev))
+    return;
+
+  // COMM_GROUP
+  IDDefSwitch (&ConnectSP, NULL);
+  IDDefText   (&PortTP, NULL);
+  
+  // BASIC_GROUP
+  IDDefNumber (&EquatorialCoordsWNP, NULL);
+  IDDefNumber (&EquatorialCoordsRNP, NULL);
+  IDDefSwitch (&OnCoordSetSP, NULL);
+  IDDefSwitch (&AbortSlewSP, NULL);
+  IDDefSwitch (&SlewModeSP, NULL);
+
+  // Movement group
+  IDDefSwitch (&MovementNSSP, NULL);
+  IDDefSwitch (&MovementWESP, NULL);
+  IDDefNumber (&TrackingAccuracyNP, NULL);
+  IDDefNumber (&SlewAccuracyNP, NULL);
+  
+  /* Send the basic data to the new client if the previous client(s) are already connected. */		
+  if (ConnectSP.s == IPS_OK)
+        getBasicData();
+
+}
+
+void CelestronGPS::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+        IText *tp;
+
+	INDI_UNUSED(n);
+
+	// ignore if not ours //
+	if (strcmp (dev, mydev))
+	    return;
+
+	if (!strcmp(name, PortTP.name) )
+	{
+	  PortTP.s = IPS_OK;
+
+	  tp = IUFindText( &PortTP, names[0] );
+	  if (!tp)
+	   return;
+
+	  IUSaveText(&PortT[0], texts[0]);
+	  IDSetText (&PortTP, NULL);
+	  return;
+	}
+}
+
+int CelestronGPS::handleCoordSet()
+{
+
+  int i=0;
+  char RAStr[32], DecStr[32];
+
+  switch (currentSet)
+  {
+
+    // Slew
+    case 0:
+          lastSet = 0;
+	  if (EquatorialCoordsWNP.s == IPS_BUSY)
+	  {
+	     StopNSEW();
+	     // sleep for 500 mseconds
+	     usleep(500000);
+	  }
+
+	  if ((i = SlewToCoords(targetRA, targetDEC)))
+	  {
+	    slewError(i);
+	    return (-1);
+	  }
+
+	  EquatorialCoordsWNP.s = IPS_BUSY;
+	  EquatorialCoordsRNP.s = IPS_BUSY;
+	  fs_sexa(RAStr, targetRA, 2, 3600);
+	  fs_sexa(DecStr, targetDEC, 2, 3600);
+	  IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
+	  IDSetNumber(&EquatorialCoordsRNP, NULL);
+	  IDLog("Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
+	  break;
+
+
+  // Track
+  case 1: 
+          if (EquatorialCoordsWNP.s == IPS_BUSY)
+	  {
+	      StopNSEW();
+	     // sleep for 500 mseconds
+	     usleep(500000);
+	  }
+
+	  if ( (fabs ( targetRA - currentRA ) >= (TrackingAccuracyN[0].value/(15.0*60.0))) ||
+ 	       (fabs (targetDEC - currentDEC) >= (TrackingAccuracyN[1].value)/60.0))
+	  {
+
+		#ifdef CELESTRON_DEBUG
+	        IDLog("Exceeded Tracking threshold, will attempt to slew to the new target.\n");
+		IDLog("targetRA is %g, currentRA is %g\n", targetRA, currentRA);
+	        IDLog("targetDEC is %g, currentDEC is %g\n*************************\n", targetDEC, currentDEC);
+		#endif
+
+          	if (( i =  SlewToCoords(targetRA, targetDEC)))
+	  	{
+	    		slewError(i);
+	    		return (-1);
+	  	}
+		
+		fs_sexa(RAStr, targetRA, 2, 3600);
+	        fs_sexa(DecStr, targetDEC, 2, 3600);
+		EquatorialCoordsWNP.s = IPS_BUSY;
+		EquatorialCoordsRNP.s = IPS_BUSY;
+		IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
+		IDSetNumber(&EquatorialCoordsRNP, NULL);
+		IDLog("Slewing to JNOW RA %s - DEC %s", RAStr, DecStr);
+	  }
+	  else
+	  {
+	    #ifdef CELESTRON_DEBUG
+	    IDLog("Tracking called, but tracking threshold not reached yet.\n");
+	    #endif
+	    EquatorialCoordsWNP.s = IPS_OK;
+	    EquatorialCoordsRNP.s = IPS_OK;
+            if (lastSet != 1)
+	      IDSetNumber(&EquatorialCoordsWNP, "Tracking...");
+	    else
+	      IDSetNumber(&EquatorialCoordsWNP, NULL);
+
+	      IDSetNumber(&EquatorialCoordsRNP, NULL);
+	  }
+	  lastSet = 1;
+      break;
+      
+    // Sync
+    case 2:
+          lastSet = 2;
+	  OnCoordSetSP.s = IPS_OK;
+	  SyncToCoords(targetRA, targetDEC);
+          EquatorialCoordsWNP.s = IPS_OK;
+	  EquatorialCoordsRNP.s = IPS_OK;
+   	  IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful.");
+	  IDSetNumber(&EquatorialCoordsRNP, NULL);
+	  break;
+   }
+
+   return (0);
+
+}
+
+void CelestronGPS::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+        double newRA=0, newDEC=0;
+
+        // ignore if not ours //
+	if (strcmp (dev, mydev))
+	    return;
+
+	struct tm *tp;
+	time_t t;
+
+	time (&t);
+	tp = gmtime (&t);
+
+        if (!strcmp (name, TrackingAccuracyNP.name))
+	{
+		if (!IUUpdateNumber(&TrackingAccuracyNP, values, names, n))
+		{
+			TrackingAccuracyNP.s = IPS_OK;
+			IDSetNumber(&TrackingAccuracyNP, NULL);
+			return;
+		}
+		
+		TrackingAccuracyNP.s = IPS_ALERT;
+		IDSetNumber(&TrackingAccuracyNP, "unknown error while setting tracking precision");
+		return;
+	}
+
+	if (!strcmp(name, SlewAccuracyNP.name))
+	{
+		IUUpdateNumber(&SlewAccuracyNP, values, names, n);
+		{
+			SlewAccuracyNP.s = IPS_OK;
+			IDSetNumber(&SlewAccuracyNP, NULL);
+			return;
+		}
+		
+		SlewAccuracyNP.s = IPS_ALERT;
+		IDSetNumber(&SlewAccuracyNP, "unknown error while setting slew precision");
+		return;
+	}
+
+	if (!strcmp (name, EquatorialCoordsWNP.name))
+	{
+	  int i=0, nset=0;
+
+	  if (checkPower(&EquatorialCoordsWNP))
+	   return;
+
+	    for (nset = i = 0; i < n; i++)
+	    {
+		INumber *eqp = IUFindNumber (&EquatorialCoordsWNP, names[i]);
+		if (eqp == &EquatorialCoordsWN[0])
+		{
+                    newRA = values[i];
+		    nset += newRA >= 0 && newRA <= 24.0;
+		} else if (eqp == &EquatorialCoordsWN[1])
+		{
+		    newDEC = values[i];
+		    nset += newDEC >= -90.0 && newDEC <= 90.0;
+		}
+	    }
+
+	  if (nset == 2)
+	  {
+	   //EquatorialCoordsNP.s = IPS_BUSY;
+
+	   tp->tm_mon   += 1;
+	   tp->tm_year  += 1900;
+
+	   targetRA  = newRA;
+	   targetDEC = newDEC;
+	       
+	   if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
+	   {
+	   	IUResetSwitch(&MovementNSSP);
+		IUResetSwitch(&MovementWESP);
+		MovementNSSP.s = MovementWESP.s = IPS_IDLE;
+		IDSetSwitch(&MovementNSSP, NULL);
+		IDSetSwitch(&MovementWESP, NULL);
+	   }
+	   
+	       if (handleCoordSet())
+	       {
+	        EquatorialCoordsWNP.s = IPS_ALERT;
+	    	IDSetNumber(&EquatorialCoordsWNP, NULL);
+	       }
+	    }
+	    else
+	    {
+		EquatorialCoordsWNP.s = IPS_ALERT;
+		IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid.");
+	    }
+
+	    return;
+	 }
+}
+
+void CelestronGPS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+
+        int index;
+
+	INDI_UNUSED(names);
+
+	// ignore if not ours //
+	if (strcmp (dev, mydev))
+	    return;
+
+	// FIRST Switch ALWAYS for power
+	if (!strcmp (name, ConnectSP.name))
+	{
+	 if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return;
+   	 connectTelescope();
+	 return;
+	}
+
+	if (!strcmp(name, OnCoordSetSP.name))
+	{
+  	  if (checkPower(&OnCoordSetSP))
+	   return;
+
+	  
+	  if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return;
+	  currentSet = getOnSwitch(&OnCoordSetSP);
+	}
+	
+	// Abort Slew
+	if (!strcmp (name, AbortSlewSP.name))
+	{
+	  if (checkPower(&AbortSlewSP))
+	  {
+	    AbortSlewSP.s = IPS_ALERT;
+	    IDSetSwitch(&AbortSlewSP, NULL);
+	    return;
+	  }
+	  
+	  IUResetSwitch(&AbortSlewSP);
+	  StopNSEW();
+
+	    if (EquatorialCoordsWNP.s == IPS_BUSY)
+	    {
+		AbortSlewSP.s = IPS_OK;
+		EquatorialCoordsWNP.s       = IPS_IDLE;
+		EquatorialCoordsRNP.s       = IPS_IDLE;
+		IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+		IDSetNumber(&EquatorialCoordsWNP, NULL);
+		IDSetNumber(&EquatorialCoordsRNP, NULL);
+            }
+	    else if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
+	    {
+		MovementNSSP.s  = MovementWESP.s =  IPS_IDLE; 
+	
+		AbortSlewSP.s = IPS_OK;		
+		EquatorialCoordsRNP.s       = IPS_IDLE;
+		IUResetSwitch(&MovementNSSP);
+		IUResetSwitch(&MovementWESP);
+		IUResetSwitch(&AbortSlewSP);
+
+		IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+		IDSetSwitch(&MovementNSSP, NULL);
+		IDSetSwitch(&MovementWESP, NULL);
+		IDSetNumber(&EquatorialCoordsRNP, NULL);
+	    }
+	    else
+	    {
+	        AbortSlewSP.s = IPS_OK;
+	        IDSetSwitch(&AbortSlewSP, NULL);
+	    }
+
+	    return;
+	}
+
+	// Slew mode
+	if (!strcmp (name, SlewModeSP.name))
+	{
+	  if (checkPower(&SlewModeSP))
+	   return;
+
+	  IUResetSwitch(&SlewModeSP);
+	  IUUpdateSwitch(&SlewModeSP, states, names, n);
+	  index = getOnSwitch(&SlewModeSP);
+	  SetRate(index);
+          
+	  SlewModeSP.s = IPS_OK;
+	  IDSetSwitch(&SlewModeSP, NULL);
+	  return;
+	}
+
+	// Movement (North/South)
+	if (!strcmp (name, MovementNSSP.name))
+	{
+	  if (checkPower(&MovementNSSP))
+	   return;
+
+	 int last_move=-1;
+         int current_move = -1;
+
+	// -1 means all off previously
+	 last_move = getOnSwitch(&MovementNSSP);
+
+	 if (IUUpdateSwitch(&MovementNSSP, states, names, n) < 0)
+		return;
+
+	current_move = getOnSwitch(&SlewModeSP);
+
+	// Previosuly active switch clicked again, so let's stop.
+	if (current_move == last_move)
+	{
+		StopSlew((current_move == 0) ? NORTH : SOUTH);
+		IUResetSwitch(&MovementNSSP);
+	    	MovementNSSP.s = IPS_IDLE;
+	    	IDSetSwitch(&MovementNSSP, NULL);
+		return;
+	}
+
+	#ifdef CELESTRON_DEBUG
+        IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
+	#endif
+
+	// 0 (North) or 1 (South)
+	last_move      = current_move;
+
+	// Correction for Celestron Driver: North 0 - South 3
+	current_move = (current_move == 0) ? NORTH : SOUTH;
+
+	StartSlew(current_move);
+	
+	  MovementNSSP.s = IPS_BUSY;
+	  IDSetSwitch(&MovementNSSP, "Moving toward %s", (current_move == NORTH) ? "North" : "South");
+	  return;
+	}
+
+	// Movement (West/East)
+	if (!strcmp (name, MovementWESP.name))
+	{
+	  if (checkPower(&MovementWESP))
+	   return;
+
+	 int last_move=-1;
+         int current_move = -1;
+
+	// -1 means all off previously
+	 last_move = getOnSwitch(&MovementWESP);
+
+	 if (IUUpdateSwitch(&MovementWESP, states, names, n) < 0)
+		return;
+
+	current_move = getOnSwitch(&SlewModeSP);
+
+	// Previosuly active switch clicked again, so let's stop.
+	if (current_move == last_move)
+	{
+		StopSlew((current_move ==0) ? WEST : EAST);
+		IUResetSwitch(&MovementWESP);
+	    	MovementWESP.s = IPS_IDLE;
+	    	IDSetSwitch(&MovementWESP, NULL);
+		return;
+	}
+
+	#ifdef CELESTRON_DEBUG
+        IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
+	#endif
+
+	// 0 (West) or 1 (East)
+	last_move      = current_move;
+
+	// Correction for Celestron Driver: West 1 - East 2
+	current_move = (current_move == 0) ? WEST : EAST;
+
+	StartSlew(current_move);
+	
+	  MovementWESP.s = IPS_BUSY;
+	  IDSetSwitch(&MovementWESP, "Moving toward %s", (current_move == WEST) ? "West" : "East");
+	  return;
+	}
+}
+
+
+int CelestronGPS::getOnSwitch(ISwitchVectorProperty *sp)
+{
+ for (int i=0; i < sp->nsp ; i++)
+     if (sp->sp[i].s == ISS_ON)
+      return i;
+
+ return -1;
+}
+
+
+int CelestronGPS::checkPower(ISwitchVectorProperty *sp)
+{
+  if (ConnectSP.s != IPS_OK)
+  {
+    if (!strcmp(sp->label, ""))
+       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->name);
+    else
+       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->label);
+       
+    sp->s = IPS_IDLE;
+    IDSetSwitch(sp, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int CelestronGPS::checkPower(INumberVectorProperty *np)
+{
+  if (ConnectSP.s != IPS_OK)
+  {
+    if (!strcmp(np->label, ""))
+       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->name);
+    else
+       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->label);
+       
+    np->s = IPS_IDLE;
+    IDSetNumber(np, NULL);
+    return -1;
+  }
+  return 0;
+}
+
+int CelestronGPS::checkPower(ITextVectorProperty *tp)
+{
+
+  if (ConnectSP.s != IPS_OK)
+  {
+    if (!strcmp(tp->label, ""))
+       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->name);
+    else
+       IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->label);
+       
+    tp->s = IPS_IDLE;
+    IDSetText(tp, NULL);
+    return -1;
+  }
+
+  return 0;
+
+}
+
+void CelestronGPS::ISPoll()
+{
+       double dx, dy;
+       int status;
+
+	switch (EquatorialCoordsWNP.s)
+	{
+	case IPS_IDLE:
+	if (ConnectSP.s != IPS_OK)
+	 break;
+	currentRA = GetRA();
+	currentDEC = GetDec();
+
+        if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
+	{
+		lastRA  = currentRA;
+		lastDEC = currentDEC;
+		IDSetNumber (&EquatorialCoordsRNP, NULL);
+
+	}
+        break;
+
+        case IPS_BUSY:
+	    currentRA = GetRA();
+	    currentDEC = GetDec();
+	    dx = targetRA - currentRA;
+	    dy = targetDEC - currentDEC;
+
+            #ifdef CELESTRON_DEBUG
+	    IDLog("targetRA is %f, currentRA is %f\n", (float) targetRA, (float) currentRA);
+	    IDLog("targetDEC is %f, currentDEC is %f\n****************************\n", (float) targetDEC, (float) currentDEC);
+	    #endif
+
+	    status = CheckCoords(targetRA, targetDEC, SlewAccuracyN[0].value/(15.0*60.0) , SlewAccuracyN[1].value/60.0);
+
+	    // Wait until acknowledged or within 3.6', change as desired.
+	    switch (status)
+	    {
+	    case 0:		/* goto in progress */
+		IDSetNumber (&EquatorialCoordsRNP, NULL);
+		break;
+	    case 1:		/* goto complete within tolerance */
+	    case 2:		/* goto complete but outside tolerance */
+		currentRA = targetRA;
+		currentDEC = targetDEC;
+
+		EquatorialCoordsWNP.s = IPS_OK;
+		EquatorialCoordsRNP.s = IPS_OK;
+
+		if (currentSet == 0)
+		{
+		  IDSetNumber (&EquatorialCoordsWNP, "Slew is complete.");
+		  IDSetNumber (&EquatorialCoordsRNP, NULL);
+		}
+		else
+		{
+		  IDSetNumber (&EquatorialCoordsWNP, "Slew is complete. Tracking...");
+		  IDSetNumber (&EquatorialCoordsRNP, NULL);
+		}
+		
+		break;
+	    }   
+	    break;
+
+	case IPS_OK:
+	if (ConnectSP.s != IPS_OK)
+	 break;
+	currentRA = GetRA();
+	currentDEC = GetDec();
+
+        if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
+	{
+		lastRA  = currentRA;
+		lastDEC = currentDEC;
+		IDSetNumber (&EquatorialCoordsRNP, NULL);
+
+	}
+        break;
+
+
+	case IPS_ALERT:
+	    break;
+	}
+
+	switch (MovementNSSP.s)
+	{
+	  case IPS_IDLE:
+	   break;
+	 case IPS_BUSY:
+	     currentRA = GetRA();
+	     currentDEC = GetDec();
+	     IDSetNumber (&EquatorialCoordsRNP, NULL);
+
+	     break;
+	 case IPS_OK:
+	   break;
+	 case IPS_ALERT:
+	   break;
+	 }
+
+	switch (MovementWESP.s)
+	{
+	  case IPS_IDLE:
+	   break;
+	 case IPS_BUSY:
+	     currentRA = GetRA();
+	     currentDEC = GetDec();
+	     IDSetNumber (&EquatorialCoordsRNP, NULL);
+
+	     break;
+	 case IPS_OK:
+	   break;
+	 case IPS_ALERT:
+	   break;
+	 }
+
+}
+
+void CelestronGPS::getBasicData()
+{
+
+  currentRA = GetRA();
+  currentDEC = GetDec();
+
+  IDSetNumber(&EquatorialCoordsRNP, NULL);
+
+}
+
+void CelestronGPS::connectTelescope()
+{
+
+     switch (ConnectSP.sp[0].s)
+     {
+      case ISS_ON:
+
+         if (ConnectTel(PortTP.tp[0].text) < 0)
+	 {
+	   ConnectS[0].s = ISS_OFF;
+	   ConnectS[1].s = ISS_ON;
+	   IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to the port.", PortTP.tp[0].text);
+	   return;
+	 }
+
+	ConnectSP.s = IPS_OK;
+	IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data...");
+	getBasicData();
+	break;
+
+     case ISS_OFF:
+         IDSetSwitch (&ConnectSP, "Telescope is offline.");
+	 IDLog("Telescope is offline.");
+	 DisconnectTel();
+	 break;
+
+    }
+}
+
+void CelestronGPS::slewError(int slewCode)
+{
+    EquatorialCoordsWNP.s = IPS_ALERT;
+
+    switch (slewCode)
+    {
+      case 1:
+       IDSetNumber (&EquatorialCoordsWNP, "Invalid newDec in SlewToCoords");
+       break;
+      case 2:
+       IDSetNumber (&EquatorialCoordsWNP, "RA count overflow in SlewToCoords");
+       break;
+      case 3:
+       IDSetNumber (&EquatorialCoordsWNP, "Dec count overflow in SlewToCoords");
+       break;
+      case 4:
+       IDSetNumber (&EquatorialCoordsWNP, "No acknowledgment from telescope after SlewToCoords");
+       break;
+      default:
+       IDSetNumber (&EquatorialCoordsWNP, "Unknown error");
+       break;
+    }
+
+}
Index: /BAORadio/libindi/v1/drivers/telescope/celestrongps.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/celestrongps.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/celestrongps.h	(revision 500)
@@ -0,0 +1,61 @@
+/*
+    Celestron GPS
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef CELESTRONGPS_H
+#define CELESTRONGPS_H
+
+#include "indidevapi.h"
+#include "indicom.h"
+
+#define	POLLMS		1000		/* poll period, ms */
+
+class CelestronGPS
+{
+ public:
+ CelestronGPS();
+ virtual ~CelestronGPS() {}
+
+ virtual void ISGetProperties (const char *dev);
+ virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ virtual void ISPoll ();
+ virtual void getBasicData();
+
+ int checkPower(INumberVectorProperty *np);
+ int checkPower(ISwitchVectorProperty *sp);
+ int checkPower(ITextVectorProperty *tp);
+ void connectTelescope();
+ void slewError(int slewCode);
+ int handleCoordSet();
+ int getOnSwitch(ISwitchVectorProperty *sp);
+
+ private:
+  int timeFormat;
+
+  double lastRA;
+  double lastDEC;
+
+  int lastSet;
+  int currentSet;
+};
+
+#endif
+
Index: /BAORadio/libindi/v1/drivers/telescope/celestronprotocol.c
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/celestronprotocol.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/celestronprotocol.c	(revision 500)
@@ -0,0 +1,821 @@
+/*
+ * Telescope Control Protocol for Celestron NexStar GPS telescopes
+ *
+ * Copyright 2003 John Kielkopf 
+ * John Kielkopf (kielkopf@louisville.edu)
+ *
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * 15 May  2003  -- Version 2.00
+ *
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+/* do NOT change this to config-kstars.h! 
+INDI is independent of KStars*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef _WIN32
+#include <termios.h>
+#endif
+
+
+#include <math.h>
+#include "celestronprotocol.h"
+
+#define NULL_PTR(x) (x *)0
+
+/* There are two classes of routines defined here:                    */
+
+/*   XmTel commands to allow easy NexStar access.  These              */
+/*     include routines that mimic the extensive LX200 command        */
+/*     language and, for the most part, trap calls and                */
+/*     respond with an error message to the console.                  */
+
+/*   NexStar specific commands and data.                              */
+
+/*   The NexStar command set as documented by Celestron               */
+/*     is very limited.  This version of xmtel uses ta few            */
+/*     auxilliary commands which permit direct access to the motor    */
+/*     controllers.                                                   */
+
+
+/* XmTel compatibility commands */
+
+int ConnectTel(char *port);
+void DisconnectTel(void);
+int  CheckConnectTel(void);
+
+void SetRate(int newRate);
+void SetLimits(double limitLower, double limitHigher);
+void StartSlew(int direction);
+void StopSlew(int direction);
+double GetRA(void);
+double GetDec(void);
+int  SlewToCoords(double newRA, double newDec);
+int  SyncToCoords(double newRA, double newDec);
+int  CheckCoords(double desRA, double desDec, double tolRA, double tolDEC);
+
+void StopNSEW(void);
+int  SetSlewRate(void);
+
+int  SyncLST(double newTime);
+int  SyncLocalTime(void);
+
+void Reticle(int reticle);
+void Focus(int focus);
+void Derotator(int rotate);
+void Fan(int fan);
+
+static int TelPortFD;
+static int TelConnectFlag = 0;
+
+
+/* NexStar local data */
+
+static double returnRA;    /* Last update of RA */
+static double returnDec;   /* Last update of Dec */
+static int updateRA;       /* Set if no RA  inquiry since last update */ 
+static int updateDec;      /* Set if no Dec inquiry since last update */
+static int slewRate;       /* Rate for slew request in StartSlew */
+
+
+/* Coordinate reported by NexStar  = true coordinate + offset. */
+
+static double offsetRA = 0;   /* Correction to RA from NexStar */
+static double offsetDec = 0;  /* Correction to Dec from NexStar */
+
+
+/* NexStar local commands */
+
+void GetRAandDec(void);    /* Update RA and Dec from NexStar */
+
+
+/* Serial communication utilities */
+
+
+typedef fd_set telfds;
+
+static int readn(int fd, char *ptr, int nbytes, int sec);
+static int writen(int fd, char *ptr, int nbytes);
+static int telstat(int fd,int sec,int usec);
+
+
+int CheckConnectTel(void)
+{
+  return TelConnectFlag;
+}
+
+
+
+int ConnectTel(char *port)
+{
+#ifdef _WIN32
+  return -1;
+#else
+  struct termios tty;
+  char returnStr[128];
+  int numRead;
+
+  fprintf(stderr, "Connecting to port: %s\n",port);
+
+  if(TelConnectFlag != 0)
+    return 0;
+
+  /* Make the connection */
+
+  TelPortFD = open(port,O_RDWR);
+  if(TelPortFD == -1)
+    return -1;
+
+  tcgetattr(TelPortFD,&tty);
+  cfsetospeed(&tty, (speed_t) B9600);
+  cfsetispeed(&tty, (speed_t) B9600);
+  tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
+  tty.c_iflag =  IGNBRK;
+  tty.c_lflag = 0;
+  tty.c_oflag = 0;
+  tty.c_cflag |= CLOCAL | CREAD;
+  tty.c_cc[VMIN] = 1;
+  tty.c_cc[VTIME] = 5;
+  tty.c_iflag &= ~(IXON|IXOFF|IXANY);
+  tty.c_cflag &= ~(PARENB | PARODD);
+  tcsetattr(TelPortFD, TCSANOW, &tty);
+
+  /* Flush the input (read) buffer */
+
+  tcflush(TelPortFD,TCIOFLUSH);
+
+  /* Test connection */
+
+  writen(TelPortFD,"Kx",2);
+  numRead=readn(TelPortFD,returnStr,3,2);
+  returnStr[numRead] = '\0';
+
+  /* Diagnostic tests */
+
+  fprintf(stderr, "ConnectTel read %d characters: %s\n",numRead,returnStr);
+  fprintf(stderr, "TelConnectFlag set to: %d\n",TelConnectFlag);
+
+  if (numRead == 2)
+  {
+    TelConnectFlag = 1;
+    return (0);
+  }
+  else
+   return -1;
+
+#endif
+}
+
+/* Assign and save slewRate for use in StartSlew */
+
+void SetRate(int newRate)
+{
+  if(newRate == SLEW)
+    {
+      slewRate = 9; 
+    }
+  else if(newRate == FIND) 
+    {
+      slewRate = 6;
+    }
+  else if(newRate == CENTER) 
+    {
+      slewRate = 3;
+    }
+  else if(newRate == GUIDE) 
+    {
+      slewRate = 1;
+    }
+  
+}
+ 
+
+/* Start a slew in chosen direction at slewRate */
+/* Use auxilliary NexStar command set through the hand control computer */
+
+void StartSlew(int direction)
+{
+  char slewCmd[] = { 0x50, 0x02, 0x11, 0x24, 0x09, 0x00, 0x00, 0x00 };
+  char inputStr[2048];
+  
+  if(direction == NORTH)
+    {
+      slewCmd[2] = 0x11; 
+      slewCmd[3] = 0x24;
+      slewCmd[4] = slewRate;
+    }
+  else if(direction == EAST)
+    {
+      slewCmd[2] = 0x10; 
+      slewCmd[3] = 0x25;
+      slewCmd[4] = slewRate;
+    }
+  else if(direction == SOUTH)
+    {
+      slewCmd[2] = 0x11; 
+      slewCmd[3] = 0x25;
+      slewCmd[4] = slewRate;
+    }
+  else if(direction == WEST)
+    {
+      slewCmd[2] = 0x10; 
+      slewCmd[3] = 0x24;
+      slewCmd[4] = slewRate;
+    }
+
+  writen(TelPortFD,slewCmd,8);
+
+  /* Look for '#' acknowledgment of request*/
+
+  for (;;) 
+  {
+    if ( readn(TelPortFD,inputStr,1,1) ) 
+    {
+      if (inputStr[0] == '#') break;
+    }
+    else 
+    { 
+      fprintf(stderr,"No acknowledgment from telescope in StartSlew.\n");
+    }
+  }   
+}
+
+
+/* Stop the slew in chosen direction */
+
+void StopSlew(int direction)
+{
+  char slewCmd[] = { 0x50, 0x02, 0x11, 0x24, 0x00, 0x00, 0x00, 0x00 };
+  char inputStr[2048];
+  
+  if(direction == NORTH)
+    {
+      slewCmd[2] = 0x11; 
+      slewCmd[3] = 0x24;
+    }
+  else if(direction == EAST)
+    {
+      slewCmd[2] = 0x10; 
+      slewCmd[3] = 0x24;
+    }
+  else if(direction == SOUTH)
+    {
+      slewCmd[2] = 0x11; 
+      slewCmd[3] = 0x24;
+    }
+  else if(direction == WEST)
+    {
+      slewCmd[2] = 0x10; 
+      slewCmd[3] = 0x24;
+    }
+
+  writen(TelPortFD,slewCmd,8);
+
+  /* Look for '#' acknowledgment of request*/
+
+  for (;;) 
+  {
+    if ( readn(TelPortFD,inputStr,1,1) ) 
+    {
+      if (inputStr[0] == '#') break;
+    }
+    else 
+    { 
+      fprintf(stderr,"No acknowledgment from telescope in StartSlew.\n");
+    }
+  }  
+}
+
+void DisconnectTel(void)
+{
+  /* printf("DisconnectTel\n"); */
+  if(TelConnectFlag == 1)
+    close(TelPortFD);
+  TelConnectFlag = 0;
+}
+
+
+/* Test update status and return the telescope right ascension */
+/* Set updateRA flag false */
+/* Last telescope readout will be returned if no RA inquiry since then */
+/* Otherwise force a new readout */
+/* Two successive calls to GetRA will always force a new readout */
+
+double GetRA(void)
+{
+  if( updateRA != 1) GetRAandDec();
+  updateRA = 0;
+  return returnRA;
+}
+
+
+/* Test update status and return the telescope declination */
+/* Set updateDec flag false */
+/* Last telescope readout will returned if no Dec inquiry since then */
+/* Otherwise force a new readout */
+/* Two successive calls to GetDec will always force a new readout */
+
+double GetDec(void)
+{
+  if( updateDec != 1) GetRAandDec();
+  updateDec = 0;
+  return returnDec;
+}
+
+
+/* Read the telescope right ascension and declination and set update status */
+
+void GetRAandDec(void)
+{
+  char returnStr[12];
+  int countRA,countDec;
+  int numRead;
+
+  writen(TelPortFD,"E",1);
+  numRead=readn(TelPortFD,returnStr,10,1);
+  returnStr[4] = returnStr[9] = '\0';  
+
+/* Diagnostic
+ *
+ * printf("GetRAandDec: %d read %x\n",numRead,returnStr); 
+ *
+ */
+ 
+  sscanf(returnStr,"%x",&countRA);                  
+  sscanf(returnStr+5,"%x:",&countDec);               
+  returnRA = (double) countRA;
+  returnRA = returnRA / (3. * 15. * 60. * 65536./64800.);
+  returnDec = (double) countDec;
+  returnDec = returnDec / (3. * 60. * 65536./64800.);
+
+
+/* Account for the quadrant in declination */
+
+/* 90 to 180 */
+
+  if ( (returnDec > 90.) && (returnDec <= 180.) )
+  {  
+    returnDec = 180. - returnDec; 
+  }
+
+
+/* 180 to 270 */
+
+  if ( (returnDec > 180.) && (returnDec <= 270.) )
+  {
+    returnDec = returnDec - 270.;
+  }
+
+
+/* 270 to 360 */
+
+  if ( (returnDec > 270.) && (returnDec <= 360.) )
+  {
+    returnDec = returnDec - 360.;
+  }
+
+
+/* Set update flags */
+
+  updateRA = 1;
+  updateDec = 1;
+
+
+/* Correct for offsets and return true coordinate */
+/* Coordinate reported by NexStar  = true coordinate + offset. */
+
+   returnRA = returnRA - offsetRA;
+   returnDec = returnDec - offsetDec;
+
+}
+
+
+
+/* Reset telescope coordinates to new coordinates by adjusting offsets*/
+/* Coordinate reported by NexStar  = true coordinate + offset. */
+
+int SyncToCoords(double newRA, double newDec)
+{
+   offsetRA = 0.;
+   offsetDec = 0.;
+   GetRAandDec();
+   offsetRA = returnRA - newRA;
+   offsetDec = returnDec - newDec;
+
+   return (0);
+}
+
+
+/* Slew to new coordinates */
+/* Coordinate sent to NexStar  = true coordinate + offset. */
+
+int SlewToCoords(double newRA, double newDec)
+{
+  int countRA,countDec;
+  char r0,r1,r2,r3,d0,d1,d2,d3;
+  double degs, hrs;
+  char outputStr[32], inputStr[2048];
+
+  /* Add offsets */
+
+  hrs = newRA + offsetRA;
+  degs = newDec + offsetDec;  
+
+  /* Convert float RA to integer count */
+
+  hrs = hrs*(3. * 15. * 60. * 65536./64800.);
+  countRA = (int) hrs;
+  
+
+/* Account for the quadrant in declination */
+
+  if ( (newDec >= 0.0) && (newDec <= 90.0) )
+  {
+    degs = degs*(3. * 60. * 65536./64800.);
+  }
+  else if ( (newDec < 0.0) && (newDec >= -90.0) )
+  {
+    degs = (360. + degs)*(3. * 60. * 65536./64800.);
+  }
+  else
+  {
+    fprintf(stderr,"Invalid newDec in SlewToCoords.\n");
+    return 1;
+  }
+
+
+
+  /* Convert float Declination to integer count */
+
+  countDec = (int) degs;
+
+
+  /* Convert each integer count to four HEX characters */
+  /* Inline coding just to be fast */
+  
+
+  if(countRA < 65536)
+  {
+    r0 = countRA % 16;
+    if(r0 < 10)
+    {
+      r0 = r0 + 48;
+    }
+    else
+    {
+      r0 = r0 + 55;
+    }
+    countRA = countRA/16;
+    r1 = countRA % 16;
+    if(r1 < 10)
+    {
+      r1 = r1 + 48;
+    }
+    else
+    {
+      r1 = r1 + 55;
+    }    
+    countRA = countRA/16;
+    r2 = countRA % 16;
+    if(r2 < 10)
+    {
+      r2 = r2 + 48;
+    }
+    else
+    {
+      r2 = r2 + 55;
+    }    
+    r3 = countRA/16;
+    if(r3 < 10)
+    {
+      r3 = r3 + 48;
+    }
+    else
+    {
+      r3 = r3 + 55;
+    }    
+  }
+  else
+  {
+    printf("RA count overflow in SlewToCoords.\n");
+    return 2;
+  }
+   if(countDec < 65536)
+  {
+    d0 = countDec % 16;
+    if(d0 < 10)
+    {
+      d0 = d0 + 48;
+    }
+    else
+    {
+      d0 = d0 + 55;
+    }    
+    countDec = countDec/16;
+    d1 = countDec % 16;
+    if(d1 < 10)
+    {
+      d1 = d1 + 48;
+    }
+    else
+    {
+      d1 = d1 + 55;
+    }    
+    countDec = countDec/16;
+    d2 = countDec % 16;
+    if(d2 < 10)
+    {
+      d2 = d2 + 48;
+    }
+    else
+    {
+      d2 = d2 + 55;
+    }
+    d3 = countDec/16;
+    if(d3 < 10)
+    {
+      d3 = d3 + 48;
+    }
+    else
+    {
+      d3 = d3 + 55;
+    }    
+  }
+  else
+  {
+    fprintf(stderr,"Dec count overflow in SlewToCoords.\n");
+    return 3;
+  }
+    
+
+  
+  /* Send the command and characters to the NexStar */
+
+  sprintf(outputStr,"R%c%c%c%c,%c%c%c%c",r3,r2,r1,r0,d3,d2,d1,d0);
+  writen(TelPortFD,outputStr,10);
+
+  /* Look for '#' in response */
+  
+  for (;;) 
+  {
+    if ( readn(TelPortFD,inputStr,1,2) ) 
+    {
+      if (inputStr[0] == '#') break;
+    }
+    else 
+    fprintf(stderr,"No acknowledgment from telescope after SlewToCoords.\n");
+    return 4;
+  }
+  return 0;
+}
+
+
+/* Test whether the destination has been reached */
+/* With the NexStar we use the goto in progress query */
+/* Return value is  */
+/*   0 -- goto in progress */
+/*   1 -- goto complete within tolerance */
+/*   2 -- goto complete but outside tolerance */
+
+int CheckCoords(double desRA, double desDec, double tolRA, double tolDEC)
+{
+  double errorRA, errorDec, nowRA, nowDec;
+  char inputStr[2048];
+
+  writen(TelPortFD,"L",1);
+
+  /* Look for '0#' in response indicating goto is not in progress */
+  
+  for (;;) 
+  {
+    if ( readn(TelPortFD,inputStr,2,2) ) 
+    {
+      if ( (inputStr[0] == '0') &&  (inputStr[1] == '#')) break;
+    }
+    else 
+    return 0;
+  }
+
+ 
+  nowRA=GetRA();
+  errorRA = nowRA - desRA;
+  nowDec=GetDec();
+  errorDec = nowDec - desDec;
+
+
+  /* For 6 minute of arc precision; change as needed.  */
+
+  if( fabs(errorRA) > tolRA || fabs(errorDec) > tolDEC)
+    return 1;
+  else
+    return 2;
+}
+
+
+/* Set lower and upper limits to protect hardware */
+
+void SetLimits(double limitLower, double limitHigher)
+{
+  limitLower = limitHigher;
+  fprintf(stderr,"NexStar does not support software limits.\n");
+}
+
+
+/* Set slew speed limited by MAXSLEWRATE */
+
+int SetSlewRate(void)
+{
+  fprintf(stderr,"NexStar does not support remote setting of slew rate.\n");
+  return 0;
+}
+
+
+
+/* Stop all slew motion */
+
+void StopNSEW(void)
+{
+  char inputStr[2048];
+
+  writen(TelPortFD,"M",1);
+
+  /* Look for '#' */
+
+  for (;;) 
+  {
+    if ( readn(TelPortFD,inputStr,1,1) ) 
+    {
+      if (inputStr[0] == '#') break;
+    }
+    else 
+    { 
+      fprintf(stderr,"No acknowledgment from telescope in StopNSEW.\n");
+    }
+  }
+}
+
+
+
+/* Control the reticle function using predefined values */
+
+void Reticle(int reticle)
+{
+  reticle = reticle;
+  fprintf(stderr,"NexStar does not support remote setting of reticle.\n");
+}
+
+
+/* Control the focus using predefined values */
+
+void Focus(int focus)
+{
+  focus = focus;
+  fprintf(stderr,"NexStar does not support remote setting of focus.\n");
+}
+
+
+
+/* Control the derotator using predefined values */
+
+void Derotator(int rotate)
+
+{
+  rotate = rotate;
+  fprintf(stderr,"NexStar does not support an image derotator.\n");
+}
+
+
+/* Control the fan using predefined values */
+
+void Fan(int fan)
+
+{
+  fan = fan;
+  fprintf(stderr,"NexStar does not have a fan.\n");
+}
+
+
+/* Time synchronization utilities */
+
+/* Reset the telescope sidereal time */
+
+int  SyncLST(double newTime)
+{	
+  newTime = newTime;	
+  fprintf(stderr,"NexStar does not support remote setting of sidereal time.\n");
+  return -1;
+}
+
+
+/*  Reset the telescope local time */
+
+int SyncLocalTime()
+{
+  fprintf(stderr,"NexStar does not support remote setting of local time.\n");
+  return -1;
+}
+
+
+
+
+/* Serial port utilities */
+
+static int writen(fd, ptr, nbytes)
+int fd;
+char *ptr;
+int nbytes;
+{
+  int nleft, nwritten;
+  nleft = nbytes;
+  while (nleft > 0) 
+  {
+    nwritten = write (fd, ptr, nleft);
+    if (nwritten <=0 ) break;
+    nleft -= nwritten;
+    ptr += nwritten;
+  }
+  return (nbytes - nleft);
+}
+
+static int readn(fd, ptr, nbytes, sec)
+int fd;
+char *ptr;
+int nbytes;
+int sec;
+{
+  int status;
+  int nleft, nread;
+  nleft = nbytes;
+  while (nleft > 0)
+  {
+    status = telstat(fd,sec,0);
+    if (status <=  0 ) break;
+    nread  = read (fd, ptr, nleft);
+
+/*  Diagnostic */
+
+/*    printf("readn: %d read\n", nread);  */
+
+    if (nread <= 0)  break;
+    nleft -= nread;
+    ptr += nread;
+  }
+  return (nbytes - nleft);
+}
+
+/*
+ * Examines the read status of a file descriptor.
+ * The timeout (sec, usec) specifies a maximum interval to
+ * wait for data to be available in the descriptor.
+ * To effect a poll, the timeout (sec, usec) should be 0.
+ * Returns non-negative value on data available.
+ * 0 indicates that the time limit referred by timeout expired.
+ * On failure, it returns -1 and errno is set to indicate the
+ * error.
+ */
+static int telstat(fd,sec,usec)
+register int fd, sec, usec;
+{
+  int ret;
+  int width;
+  struct timeval timeout;
+  telfds readfds;
+
+  memset((char *)&readfds,0,sizeof(readfds));
+  FD_SET(fd, &readfds);
+  width = fd+1;
+  timeout.tv_sec = sec;
+  timeout.tv_usec = usec;
+  ret = select(width,&readfds,NULL_PTR(telfds),NULL_PTR(telfds),&timeout);
+  return(ret);
+}
+
Index: /BAORadio/libindi/v1/drivers/telescope/celestronprotocol.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/celestronprotocol.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/celestronprotocol.h	(revision 500)
@@ -0,0 +1,148 @@
+/*
+* Header File for the Telescope Control protocols for the Meade LX200
+* Author:  John Kielkopf (kielkopf@louisville.edu)
+*
+* This file contains header information used in common with xmtel.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* 15 May 2003 -- Version 2.00
+*
+*/
+
+
+#ifndef CELESTRON_PROTOCOL_H
+#define CELESTRON_PROTOCOL_H
+
+/* These are user defined quantities that set the limits over which it */
+/* is safe to operate the telescope.  */
+
+
+/* LOWER is the number of degrees from the zenith that you will allow. */
+/* Use 80, for example, to keep the eyepiece end out of the fork arm space */
+/* of an LX200 telescope. */
+
+#define LOWER         90.
+
+/* HIGHER is the horizon.  0 is an unobstructed horizon in every direction. */
+/* Use 10, for example, to limit sighting below 10 degrees above the horizon. */
+
+#define HIGHER         0.
+
+
+/* Set this if a slew to the north sends the telescope south. */
+
+#define REVERSE_NS	0 	/* 1 for reverse; 0 for normal. */
+
+
+/* Set this for maximum slew rate allowed in degree/sec. */
+
+#define MAXSLEWRATE	4 	/* 2 for safety; 4 for 16-inch; 8 otherwise. */
+
+
+
+
+/* The following parameters are used internally to set speed and direction. */
+/* Do not change these values. */
+
+
+#define	SLEW		0
+#define	FIND		1
+#define	CENTER		2
+#define	GUIDE		3
+
+#if REVERSE_NS > 0
+#define	NORTH		3
+#define	SOUTH		0
+#else
+#define	NORTH		0
+#define	SOUTH		3
+#endif
+
+#define	EAST		2
+#define	WEST		1
+
+/* Slew speed defines */
+
+# define SLEWRATE8     8    /* should be 8 degrees per second (not 16-inch) */
+# define SLEWRATE4     4    /* should be 4 degrees per second */
+# define SLEWRATE3     3    /* should be 3 degrees per second */
+# define SLEWRATE2     2    /* should be 2 degrees per second */
+
+/* Reticle defines */
+
+#define BRIGHTER        16  /* increase */
+#define DIMMER          8   /* decrease */
+#define BLINK0          0   /* no blinking */ 
+#define BLINK1          1   /* blink rate 1 */
+#define BLINK2          2   /* blink rate 2 */
+#define BLINK3          4   /* blink rate 3 */
+ 
+
+/* Focus defines */
+
+#define FOCUSOUT        8   /* positive voltage output */
+#define FOCUSIN         4   /* negative voltage output */
+#define FOCUSSTOP       0   /* no output */ 
+#define FOCUSSLOW       1   /* half voltage */
+#define FOCUSFAST       2   /* full voltage */
+
+
+/* Rotator defines */
+
+#define ROTATORON        1   /* image rotator on */
+#define ROTATOROFF       0   /* image rotator off */
+
+
+/* Fan defines */
+
+#define FANON        1   /* cooling fan on */
+#define FANOFF       0   /* cooling fan off */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ConnectTel(char *port);
+void DisconnectTel(void);
+int  CheckConnectTel(void);
+
+void SetRate(int newRate);
+void SetLimits(double limitLower, double limitHigher);
+void StartSlew(int direction);
+void StopSlew(int direction);
+double GetRA(void);
+double GetDec(void);
+int  SlewToCoords(double newRA, double newDec);
+int  SyncToCoords(double newRA, double newDec);
+int  CheckCoords(double desRA, double desDec, double tolRA, double tolDEC);
+
+void StopNSEW(void);
+int  SetSlewRate(void);
+
+int  SyncLST(double newTime);
+int  SyncLocalTime();
+
+void Reticle(int reticle);
+void Focus(int focus);
+void Derotator(int rotate);
+void Fan(int fan);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
Index: /BAORadio/libindi/v1/drivers/telescope/intelliscope.c
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/intelliscope.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/intelliscope.c	(revision 500)
@@ -0,0 +1,201 @@
+#if 0
+    Intelliscope INDI driver
+    Copyright (C) 2005 Douglas Philipson (dougp AT intermind DOT net)
+
+    Based on code by Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+
+#endif
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "indidevapi.h"
+#include "indicom.h"
+#include "lx200driver.h"
+
+#define mydev		"Intelliscope"
+#define BASIC_GROUP	"Main Control"
+#define POLLMS		1000
+#define currentRA	eq[0].value
+#define currentDEC	eq[1].value
+
+static void ISPoll(void *);
+static void ISInit(void);
+static void connectTelescope(void);
+
+int fd;
+
+static ISwitch PowerS[]          = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+ISwitchVectorProperty PowerSP		= { mydev, "CONNECTION" , "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+
+static IText PortT[]			= {{"PORT", "Port", 0, 0, 0, 0}};
+static ITextVectorProperty PortTP		= { mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
+
+/* equatorial position */
+INumber eq[] = {
+    {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0},
+    {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0},
+};
+INumberVectorProperty eqNum = {
+    mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 0, IPS_IDLE,
+    eq, NARRAY(eq), "", 0};
+
+
+void ISInit(void)
+{
+  static int isInit=0;
+
+  if (isInit) return;
+
+  isInit = 1;
+  fd = -1;
+
+  IEAddTimer (POLLMS, ISPoll, NULL);
+
+}
+
+void ISGetProperties (const char *dev)
+{
+  
+  ISInit(); 
+
+  dev=dev;
+
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefText(&PortTP, NULL);
+  IDDefNumber(&eqNum, NULL);
+}
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+   ISInit();
+
+   dev = dev;
+
+   if (!strcmp(name, PowerSP.name))
+   {
+      IUResetSwitch(&PowerSP);
+      IUUpdateSwitch(&PowerSP, states, names, n);
+      connectTelescope();
+      return;
+   }
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+
+  ISInit();
+
+  dev=dev; names=names; n=n;
+
+  if (!strcmp(name, PortTP.name))
+  {
+    IUSaveText(&PortT[0], texts[0]);
+    PortTP.s = IPS_OK;
+    IDSetText(&PortTP, NULL);
+    return;
+  }
+
+}
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+ dev=dev;name=name;values=values;names=names;n=n;
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+void ISPoll (void *p)
+{
+  p=p;
+
+  if (PowerS[0].s == ISS_ON)
+  {
+  	switch (eqNum.s)
+		{
+		case IPS_IDLE:
+	        case IPS_OK:
+	        case IPS_BUSY:
+		if (updateIntelliscopeCoord(fd, &currentRA, &currentDEC) < 0)
+                 {
+                   eqNum.s = IPS_ALERT;
+                   IDSetNumber(&eqNum, "Unknown error while reading telescope coordinates");
+                   IDLog("Unknown error while reading telescope coordinates\n");
+                   break;
+                 }
+
+	        IDSetNumber(&eqNum, NULL);
+	        break;
+	        
+	        case IPS_ALERT:
+	    	break;
+		}
+  }
+
+  IEAddTimer(POLLMS, ISPoll, NULL);
+}
+
+void connectTelescope(void)
+{
+
+  switch (PowerS[0].s)
+  {
+    case ISS_ON:
+     if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
+     {
+       PowerSP.s = IPS_ALERT;
+       IUResetSwitch(&PowerSP);
+       IDSetSwitch(&PowerSP, "Error connecting to port %s", PortT[0].text);
+       return;
+     }
+
+     PowerSP.s = IPS_OK;
+     IDSetSwitch(&PowerSP, "Intelliscope is online.");
+     break;
+
+   case ISS_OFF:
+	tty_disconnect(fd);
+	IUResetSwitch(&PowerSP);
+        eqNum.s = PortTP.s = PowerSP.s = IPS_IDLE;
+	IDSetSwitch(&PowerSP, "Intelliscope is offline.");
+        IDSetText(&PortTP, NULL);
+	IDSetNumber(&eqNum, NULL);
+	break;
+  }
+
+}
+
Index: /BAORadio/libindi/v1/drivers/telescope/lx200_16.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200_16.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200_16.cpp	(revision 500)
@@ -0,0 +1,386 @@
+/*
+    LX200 16"
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "lx200_16.h"
+#include "lx200driver.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+
+#define LX16GROUP	"GPS/16 inch Features"
+
+#define currentAZ	HorizontalCoordsRNP.np[0].value
+#define currentALT	HorizontalCoordsRNP.np[1].value
+#define targetAZ	HorizontalCoordsWNP.np[0].value
+#define targetALT	HorizontalCoordsWNP.np[1].value
+
+extern LX200Generic *telescope;
+extern ITextVectorProperty Time;
+extern int MaxReticleFlashRate;
+
+static ISwitch FanStatusS[]		= { {"On", "", ISS_OFF, 0, 0}, {"Off", "", ISS_OFF, 0, 0}};
+static ISwitch HomeSearchS[]		= { {"Save home", "", ISS_OFF, 0, 0} , {"Set home", "", ISS_OFF, 0, 0}};
+static ISwitch FieldDeRotatorS[]	= { {"On", "", ISS_OFF, 0, 0}, {"Off", "", ISS_OFF,0 ,0}};
+
+static ISwitchVectorProperty FanStatusSP	= { mydev, "Fan", "", LX16GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FanStatusS, NARRAY(FanStatusS), "", 0};
+
+static ISwitchVectorProperty HomeSearchSP	= { mydev, "Park", "", LX16GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, HomeSearchS, NARRAY(HomeSearchS), "", 0};
+
+static ISwitchVectorProperty FieldDeRotatorSP	= { mydev, "Field De-rotator", "", LX16GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FieldDeRotatorS, NARRAY(FieldDeRotatorS), "", 0};
+
+//static ISwitches SlewAltAzSw		= { mydev, "AltAzSet", "On Alt/Az Set",  SlewAltAzS, NARRAY(SlewAltAzS), ILS_IDLE, 0, LX16Group};
+
+/* Horizontal Coordinates: Read Only */
+static INumber HorizontalCoordsRN[] = {
+    {"ALT",  "Alt  D:M:S", "%10.6m",  -90., 90., 0., 0., 0, 0, 0},
+    {"AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0., 0, 0, 0}};
+static INumberVectorProperty HorizontalCoordsRNP = {
+    mydev, "HORIZONTAL_COORD", "Horizontal Coords", LX16GROUP, IP_RO, 120, IPS_IDLE,
+    HorizontalCoordsRN, NARRAY(HorizontalCoordsRN), "", 0};
+
+/* Horizontal Coordinates: Request Only */
+static INumber HorizontalCoordsWN[] = {
+    {"ALT",  "Alt  D:M:S", "%10.6m",  -90., 90., 0., 0., 0, 0, 0},
+    {"AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0., 0, 0, 0}};
+static INumberVectorProperty HorizontalCoordsWNP = {
+    mydev, "HORIZONTAL_COORD_REQUEST", "Horizontal Coords", LX16GROUP, IP_WO, 120, IPS_IDLE,
+    HorizontalCoordsWN, NARRAY(HorizontalCoordsWN), "", 0};
+
+
+void changeLX200_16DeviceName(const char * newName)
+{
+  strcpy(HorizontalCoordsWNP.device, newName);
+  strcpy(HorizontalCoordsRNP.device, newName);
+  strcpy(FanStatusSP.device, newName);
+  strcpy(HomeSearchSP.device, newName);
+  strcpy(FieldDeRotatorSP.device,newName);
+}
+
+LX200_16::LX200_16() : LX200Autostar()
+{
+
+}
+ 
+void LX200_16::ISGetProperties (const char *dev)
+{
+
+if (dev && strcmp (thisDevice, dev))
+    return;
+
+  // process parent first
+  LX200Autostar::ISGetProperties(dev);
+
+  IDDefNumber (&HorizontalCoordsWNP, NULL);
+  IDDefNumber (&HorizontalCoordsRNP, NULL);
+
+  IDDefSwitch (&FanStatusSP, NULL);
+  IDDefSwitch (&HomeSearchSP, NULL);
+  IDDefSwitch (&FieldDeRotatorSP, NULL);
+
+}
+
+void LX200_16::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+
+	// ignore if not ours //
+	if (strcmp (dev, thisDevice))
+	    return;
+
+        LX200Autostar::ISNewText (dev, name, texts, names,  n);
+
+}
+
+void LX200_16::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+  double newAlt=0, newAz=0;
+  char altStr[64], azStr[64];
+  int err;
+
+  // ignore if not ours //
+  if (strcmp (dev, thisDevice))
+    return;
+
+  if ( !strcmp (name, HorizontalCoordsWNP.name) )
+  {
+      int i=0, nset=0;
+
+      if (checkPower(&HorizontalCoordsWNP))
+	   return;
+
+        for (nset = i = 0; i < n; i++)
+	    {
+		INumber *horp = IUFindNumber (&HorizontalCoordsWNP, names[i]);
+		if (horp == &HorizontalCoordsWN[0])
+		{
+                    newAlt = values[i];
+		    nset += newAlt >= -90. && newAlt <= 90.0;
+		} else if (horp == &HorizontalCoordsWN[1])
+		{
+		    newAz = values[i];
+		    nset += newAz >= 0. && newAz <= 360.0;
+		}
+	    }
+
+	  if (nset == 2)
+	  {
+	   if ( (err = setObjAz(fd, newAz)) < 0 || (err = setObjAlt(fd, newAlt)) < 0)
+	   {
+	     handleError(&HorizontalCoordsWNP, err, "Setting Alt/Az");
+	     return;
+	   }
+	       //HorizontalCoordsWNP.s = IPS_OK;
+	       //HorizontalCoordsWNP.n[0].value = values[0];
+	       //HorizontalCoordsWNP.n[1].value = values[1];
+	       targetAZ  = newAz;
+	       targetALT = newAlt;
+
+	       fs_sexa(azStr, targetAZ, 2, 3600);
+	       fs_sexa(altStr, targetALT, 2, 3600);
+
+	       //IDSetNumber (&HorizontalCoordsWNP, "Attempting to slew to Alt %s - Az %s", altStr, azStr);
+	       handleAltAzSlew();
+	  }
+	  else
+	  {
+		HorizontalCoordsWNP.s = IPS_ALERT;
+		IDSetNumber(&HorizontalCoordsWNP, "Altitude or Azimuth missing or invalid");
+	  }
+	
+	  return;  
+    }
+
+    LX200Autostar::ISNewNumber (dev, name, values, names, n);
+}
+    
+
+
+
+void LX200_16::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+   int index;
+   int err;
+
+  if (strcmp (dev, thisDevice))
+    return;
+
+   if (!strcmp(name, FanStatusSP.name))
+   {
+      if (checkPower(&FanStatusSP))
+       return;
+
+          IUResetSwitch(&FanStatusSP);
+          IUUpdateSwitch(&FanStatusSP, states, names, n);
+          index = getOnSwitch(&FanStatusSP);
+
+	  if (index == 0)
+	  {
+	    if ( (err = turnFanOn(fd)) < 0)
+	    {
+	      handleError(&FanStatusSP, err, "Changing fan status");
+	      return;
+	    }
+	  }
+	  else
+	  {
+	    if ( (err = turnFanOff(fd)) < 0)
+	    {
+	      handleError(&FanStatusSP, err, "Changing fan status");
+	      return;
+	    }
+	  }
+	  
+	  FanStatusSP.s = IPS_OK;
+	  IDSetSwitch (&FanStatusSP, index == 0 ? "Fan is ON" : "Fan is OFF");
+	  return;
+   }
+
+   if (!strcmp(name, HomeSearchSP.name))
+   {
+      if (checkPower(&HomeSearchSP))
+       return;
+
+          IUResetSwitch(&HomeSearchSP);
+          IUUpdateSwitch(&HomeSearchSP, states, names, n);
+          index = getOnSwitch(&HomeSearchSP);
+
+	  if (index == 0)
+		seekHomeAndSave(fd);
+	  else 
+		seekHomeAndSet(fd);
+
+	  HomeSearchSP.s = IPS_BUSY;
+	  IDSetSwitch (&HomeSearchSP, index == 0 ? "Seek Home and Save" : "Seek Home and Set");
+	  return;
+   }
+
+   if (!strcmp(name, FieldDeRotatorSP.name))
+   {
+      if (checkPower(&FieldDeRotatorSP))
+       return;
+
+          IUResetSwitch(&FieldDeRotatorSP);
+          IUUpdateSwitch(&FieldDeRotatorSP, states, names, n);
+          index = getOnSwitch(&FieldDeRotatorSP);
+
+	  if (index == 0)
+	  	seekHomeAndSave(fd);
+	  else
+		seekHomeAndSet(fd);
+
+	  FieldDeRotatorSP.s = IPS_OK;
+	  IDSetSwitch (&FieldDeRotatorSP, index == 0 ? "Field deRotator is ON" : "Field deRotator is OFF");
+	  return;
+   }
+
+    LX200Autostar::ISNewSwitch (dev, name, states, names, n);
+
+}
+
+void LX200_16::handleAltAzSlew()
+{
+        int i=0;
+	char altStr[64], azStr[64];
+
+	  if (HorizontalCoordsWNP.s == IPS_BUSY)
+	  {
+	     abortSlew(fd);
+
+	     // sleep for 100 mseconds
+	     usleep(100000);
+	  }
+
+	  if ((i = slewToAltAz(fd)))
+	  {
+	    HorizontalCoordsWNP.s = IPS_ALERT;
+	    IDSetNumber(&HorizontalCoordsWNP, "Slew is not possible.");
+	    return;
+	  }
+
+	  HorizontalCoordsWNP.s = IPS_BUSY;
+	  HorizontalCoordsRNP.s = IPS_BUSY;
+	  fs_sexa(azStr, targetAZ, 2, 3600);
+	  fs_sexa(altStr, targetALT, 2, 3600);
+
+	  IDSetNumber(&HorizontalCoordsWNP, "Slewing to Alt %s - Az %s", altStr, azStr);
+	  IDSetNumber(&HorizontalCoordsRNP, NULL);
+	  return;
+}
+
+ void LX200_16::ISPoll ()
+ {
+   int searchResult=0;
+   double dx, dy;
+   int err;
+   
+   LX200Autostar::ISPoll();
+
+   	switch (HomeSearchSP.s)
+	{
+	case IPS_IDLE:
+	     break;
+
+	case IPS_BUSY:
+
+	    if ( (err = getHomeSearchStatus(fd, &searchResult)) < 0)
+	    {
+	      handleError(&HomeSearchSP, err, "Home search");
+	      return;
+	    }
+
+	    if (searchResult == 0)
+	    {
+	      HomeSearchSP.s = IPS_ALERT;
+	      IDSetSwitch(&HomeSearchSP, "Home search failed.");
+	    }
+	    else if (searchResult == 1)
+	    {
+	      HomeSearchSP.s = IPS_OK;
+	      IDSetSwitch(&HomeSearchSP, "Home search successful.");
+	    }
+	    else if (searchResult == 2)
+	      IDSetSwitch(&HomeSearchSP, "Home search in progress...");
+	    else
+	    {
+	      HomeSearchSP.s = IPS_ALERT;
+	      IDSetSwitch(&HomeSearchSP, "Home search error.");
+	    }
+	    break;
+
+	 case IPS_OK:
+	   break;
+	 case IPS_ALERT:
+	  break;
+	}
+
+	switch (HorizontalCoordsWNP.s)
+	{
+	case IPS_IDLE:
+	     break;
+
+	case IPS_BUSY:
+
+	    if ( (err = getLX200Az(fd, &currentAZ)) < 0 || (err = getLX200Alt(fd, &currentALT)) < 0)
+	    {
+	      handleError(&HorizontalCoordsWNP, err, "Get Alt/Az");
+	      return;
+	    }
+	    
+	    dx = targetAZ - currentAZ;
+	    dy = targetALT - currentALT;
+
+            HorizontalCoordsRNP.np[0].value = currentALT;
+	    HorizontalCoordsRNP.np[1].value = currentAZ;
+
+	    // accuracy threshold (3'), can be changed as desired.
+	    if ( fabs(dx) <= 0.05 && fabs(dy) <= 0.05)
+	    {
+
+		HorizontalCoordsWNP.s = IPS_OK;
+		HorizontalCoordsRNP.s = IPS_OK;
+		currentAZ = targetAZ;
+		currentALT = targetALT;
+                IDSetNumber (&HorizontalCoordsWNP, "Slew is complete.");
+		IDSetNumber (&HorizontalCoordsRNP, NULL);
+	    } else
+	    	IDSetNumber (&HorizontalCoordsRNP, NULL);
+	    break;
+
+	case IPS_OK:
+	    break;
+
+	case IPS_ALERT:
+	    break;
+	}
+
+ }
+
+ void LX200_16::getBasicData()
+ {
+
+   getLX200Az(fd, &currentAZ);
+   getLX200Alt(fd, &currentALT);
+   IDSetNumber (&HorizontalCoordsRNP, NULL);
+
+   LX200Autostar::getBasicData();
+
+ }
Index: /BAORadio/libindi/v1/drivers/telescope/lx200_16.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200_16.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200_16.h	(revision 500)
@@ -0,0 +1,46 @@
+#ifndef LX200_16_H
+#define LX200_16_H
+
+/*
+    LX200 16"
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "lx200autostar.h"
+
+class LX200_16 : public LX200Autostar
+{
+ public:
+  LX200_16();
+  ~LX200_16() {}
+
+ void ISGetProperties (const char *dev);
+ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ void ISPoll ();
+ void getBasicData();
+ void handleAltAzSlew();
+
+};
+
+void changeLX200_16DeviceName(const char * newName);
+
+#endif
+
+
Index: /BAORadio/libindi/v1/drivers/telescope/lx200ap.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200ap.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200ap.cpp	(revision 500)
@@ -0,0 +1,2233 @@
+/*
+    LX200 Astro-Physics INDI driver, tested with controller software version D
+    Copyright (C) 2007 Markus Wildi based on the work of Jasem Mutlaq 
+    (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+
+//HAVE_NOVASCC_H: NOVAS-C, Version 2.0.1, Astronomical Applications Dept. 
+//U.S. Naval Observatory, Washington, DC  20392-5420 http://aa.usno.navy.mil/AA/
+//#define HAVE_NOVASCC_H
+//HAVE_NOVA_H: http://libnova.sourceforge.net/
+//#define HAVE_NOVA_H
+
+#include "lx200ap.h"
+#include "lx200driver.h"
+#include "lx200apdriver.h"
+#include "lx200aplib.h"
+
+#include <config.h>
+
+#ifdef HAVE_NOVA_H
+#include <libnova.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define COMM_GROUP	 "Communication"
+#define BASIC_GROUP      "Main Control"
+#define MOTION_GROUP	 "Motion Control"
+#define FIRMWARE_GROUP   "Firmware data"
+#define SETTINGS_GROUP   "Settings"
+#define ATMOSPHERE_GROUP "Atmosphere"
+#define MOUNT_GROUP      "Mounting"
+
+/* Handy Macros */
+#define currentRA	EquatorialCoordsRNP.np[0].value
+#define currentDEC	EquatorialCoordsRNP.np[1].value
+#define targetRA	EquatorialCoordsWNP.np[0].value
+#define targetDEC	EquatorialCoordsWNP.np[1].value
+#define currentAZ	HorizontalCoordsRNP.np[0].value
+#define currentALT	HorizontalCoordsRNP.np[1].value
+#define targetAZ	HorizontalCoordsWNP.np[0].value
+#define targetALT	HorizontalCoordsWNP.np[1].value
+
+/* SNOOP */
+
+#define CONTROL_GROUP    "Control"
+
+/* Do not forget to remove static in lx200generic.cpp */
+extern INumberVectorProperty EquatorialCoordsWNP;
+extern INumberVectorProperty EquatorialCoordsRNP;
+extern ITextVectorProperty   PortTP ;
+extern ISwitchVectorProperty MovementNSSP ;
+extern ISwitchVectorProperty MovementWESP ;
+extern ISwitchVectorProperty ConnectSP ;
+extern ISwitchVectorProperty AbortSlewSP ;
+extern ISwitchVectorProperty OnCoordSetSP ;
+extern INumberVectorProperty geoNP ;
+extern INumberVectorProperty TrackingAccuracyNP ;
+extern INumberVectorProperty SlewAccuracyNP ;
+
+/* Communication */
+
+static ISwitch DomeControlS[] = 
+{
+    {"ON" , "on" , ISS_ON, 0, 0},
+    {"OFF" , "off" , ISS_OFF, 0, 0},
+};
+
+ISwitchVectorProperty DomeControlSP = 
+{ 
+    myapdev, "DOMECONTROL" , "Dome control", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DomeControlS, NARRAY(DomeControlS), "", 0
+};
+
+static ISwitch StartUpS[] = 
+{
+    {"COLD" , "cold" , ISS_OFF, 0, 0},
+    {"WARM" , "warm" , ISS_ON, 0, 0},
+};
+
+ISwitchVectorProperty StartUpSP = 
+{ 
+    myapdev, "STARTUP" , "Mount init.", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, StartUpS, NARRAY(StartUpS), "", 0
+};
+
+/* Main control */
+#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
+static ISwitch ApparentToObservedS[] = 
+{
+    {"NCTC" , "identity" , ISS_ON, 0, 0},
+    {"NATR" , "app. to refracted" , ISS_OFF, 0, 0},
+    {"NARTT" , "app., refr., telescope" , ISS_OFF, 0, 0},
+    {"NARTTO" , "app., refr., tel., observed" , ISS_OFF, 0, 0},
+};
+
+ISwitchVectorProperty ApparentToObservedSP = 
+{ 
+    myapdev, "TRANSFORMATION" , "Transformation", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ApparentToObservedS, NARRAY(ApparentToObservedS), "", 0
+};
+#endif
+
+static INumber HourangleCoordsN[] = 
+{
+    {"HA",  "HA H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
+    {"Dec",  "Dec D:M:S", "%10.6m",  -90.,  90., 0., 0., 0, 0, 0},
+};
+static INumberVectorProperty  HourangleCoordsNP = 
+{
+    myapdev, "HOURANGLE_COORD", "Hourangle Coords", BASIC_GROUP, IP_RO, 0., IPS_IDLE, HourangleCoordsN, NARRAY( HourangleCoordsN), "", 0
+};
+static INumber HorizontalCoordsRN[] = 
+{
+    {"AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0., 0, 0, 0},
+    {"ALT",  "Alt  D:M:S", "%10.6m",  -90., 90., 0., 0., 0, 0, 0}
+};
+static INumberVectorProperty HorizontalCoordsRNP = 
+{
+    myapdev, "HORIZONTAL_COORD", "Horizontal Coords", BASIC_GROUP, IP_RO, 120, IPS_IDLE, HorizontalCoordsRN, NARRAY(HorizontalCoordsRN), "", 0
+};
+
+/* Horizontal Coordinates: Request Only */
+static INumber HorizontalCoordsWN[] = 
+{
+    {"AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0., 0, 0, 0},
+    {"ALT",  "Alt  D:M:S", "%10.6m",  -90., 90., 0., 0., 0, 0, 0}
+};
+static INumberVectorProperty HorizontalCoordsWNP = 
+{
+    myapdev, "HORIZONTAL_COORD_REQUEST", "Horizontal Coords", BASIC_GROUP, IP_WO, 120, IPS_IDLE, HorizontalCoordsWN, NARRAY(HorizontalCoordsWN), "", 0
+};
+/* Difference of the equatorial coordinates, used to estimate the applied corrections */
+static INumber DiffEquatorialCoordsN[] = 
+{
+    {"RA",  "RA H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
+    {"Dec",  "Dec D:M:S", "%10.6m",  -90.,  90., 0., 0., 0, 0, 0},
+};
+static INumberVectorProperty  DiffEquatorialCoordsNP = 
+{
+    myapdev, "DIFFEQUATORIAL_COORD", "Diff. Eq.", BASIC_GROUP, IP_RO, 0., IPS_IDLE, DiffEquatorialCoordsN, NARRAY( DiffEquatorialCoordsN), "", 0
+};
+
+static ISwitch TrackModeS[] = {
+    {"LUNAR" , "lunar" , ISS_OFF, 0, 0},
+    {"SOLAR" , "solar" , ISS_OFF, 0, 0},
+    {"SIDEREAL", "sidereal" , ISS_OFF, 0, 0},
+    {"ZERO" , "zero" , ISS_ON, 0, 0},
+};
+ISwitchVectorProperty TrackModeSP = 
+{ 
+    myapdev, "TRACKINGMODE" , "Tracking mode", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0
+};
+static ISwitch MoveToRateS[] = {
+    {"1200" , "1200x" , ISS_OFF, 0, 0},
+    {"600" , "600x" , ISS_OFF, 0, 0},
+    {"64" , "64x" , ISS_ON, 0, 0},
+    {"12" , "12x" , ISS_OFF, 0, 0},
+};
+
+ISwitchVectorProperty MoveToRateSP = 
+{ 
+    myapdev, "MOVETORATE" , "Move to rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MoveToRateS, NARRAY(MoveToRateS), "", 0
+};
+static ISwitch SlewRateS[] = {
+    {"1200" , "1200x" , ISS_OFF, 0, 0},
+    {"900" , "900x" , ISS_OFF, 0, 0},
+    {"600" , "600x" , ISS_ON, 0, 0},
+};
+
+ISwitchVectorProperty SlewRateSP = 
+{ 
+    myapdev, "SLEWRATE" , "Slew rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewRateS, NARRAY(SlewRateS), "", 0
+};
+static ISwitch SwapS[] = {
+    {"NS" , "North/Sounth" , ISS_OFF, 0, 0},
+    {"EW" , "East/West" , ISS_OFF, 0, 0},
+};
+
+ISwitchVectorProperty SwapSP = 
+{ 
+    myapdev, "SWAP" , "Swap buttons", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SwapS, NARRAY(SwapS), "", 0
+};
+static ISwitch SyncCMRS[] = {
+    {":CM#" , ":CM#" , ISS_ON, 0, 0},
+    {":CMR#" , ":CMR#" , ISS_OFF, 0, 0},
+};
+
+ISwitchVectorProperty SyncCMRSP = 
+{ 
+    myapdev, "SYNCCMR" , "Sync", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SyncCMRS, NARRAY(SyncCMRS), "", 0
+};
+
+/* Firmware data */
+
+static IText   VersionT[] =
+{
+// AP has only versionnumber
+    { "Number", "", 0, 0, 0 ,0}
+};
+
+static ITextVectorProperty VersionInfo = 
+{
+    myapdev, "Firmware Info", "", FIRMWARE_GROUP, IP_RO, 0, IPS_IDLE, VersionT, NARRAY(VersionT), "" ,0
+};
+
+/* Mount */
+
+static IText   DeclinationAxisT[] =
+{
+    { "RELHA", "rel. to HA", 0, 0, 0, 0} ,
+};
+
+static ITextVectorProperty DeclinationAxisTP = 
+{
+    myapdev, "DECLINATIONAXIS", "Declination axis", MOUNT_GROUP, IP_RO, 0, IPS_IDLE, DeclinationAxisT, NARRAY(DeclinationAxisT), "" ,0
+};
+static INumber APLocalTimeN[] = 
+{
+    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
+};
+static INumberVectorProperty APLocalTimeNP = 
+{
+    myapdev, "APLOCALTIME", "AP local time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APLocalTimeN, NARRAY(APLocalTimeN), "", 0
+};
+static INumber APSiderealTimeN[] = 
+{
+    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
+};
+static INumberVectorProperty APSiderealTimeNP = 
+{
+    myapdev, "APSIDEREALTIME", "AP sidereal time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APSiderealTimeN, NARRAY(APSiderealTimeN), "", 0
+};
+
+static INumber APUTCOffsetN[] = 
+{
+    {"VALUE",  "H:M:S", "%10.6m",  0.,  24., 0., 0., 0, 0, 0},
+};
+static INumberVectorProperty APUTCOffsetNP = 
+{
+    myapdev, "APUTCOFFSET", "AP UTC Offset", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, APUTCOffsetN, NARRAY(APUTCOffsetN), "", 0
+};
+
+static INumber HourAxisN[] = 
+{
+    {"THETA",  "Theta D:M:S", "%10.6m",  0.,  360., 0., 0., 0, 0, 0}, // 0., it points to the apparent pole
+    {"GAMMA",  "Gamma D:M:S", "%10.6m",  0.,  90., 0., 0., 0, 0, 0},
+};
+static INumberVectorProperty HourAxisNP = 
+{
+    myapdev, "HOURAXIS", "Hour axis", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, HourAxisN, NARRAY(HourAxisN), "", 0
+};
+
+/* Atmosphere */
+static INumber AirN[] = 
+{
+    {"TEMPERATURE",  "Temperature K", "%10.2f",  0.,  383.1, 0., 283.1, 0, 0, 0},
+    {"PRESSURE",  "Pressure hPa", "%10.2f",  0.,  1300., 0., 975., 0, 0, 0},
+    {"HUMIDITY",  "Humidity Perc.", "%10.2f",  0.,  100., 0., 70., 0, 0, 0},
+};
+static INumberVectorProperty AirNP = 
+{
+    myapdev, "ATMOSPHERE", "Atmosphere", ATMOSPHERE_GROUP, IP_RW, 0., IPS_IDLE, AirN, NARRAY(AirN), "", 0
+};
+
+/* Settings Group */
+static IText   ConnectionDCODT[] =
+{
+    { "DEVICE", "Device", 0, 0, 0, 0} ,
+    { "PROPERTY", "Property", 0, 0, 0, 0}
+};
+static ITextVectorProperty ConnectionDCODTP = 
+{
+    myapdev, "SNOOPCONNECTIONDC", "Snoop dc connection", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ConnectionDCODT, NARRAY(ConnectionDCODT), "" ,0
+};
+static IText MasterAlarmODT[]= 
+{
+    { "DEVICE", "Device", 0, 0, 0, 0} ,
+    { "PROPERTY", "Property", 0, 0, 0, 0}
+};
+static ITextVectorProperty MasterAlarmODTP = 
+{
+    myapdev, "SNOOPMASTERALARM", "Snoop dc master alarm", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, MasterAlarmODT, NARRAY(MasterAlarmODT), "" ,0
+};
+static IText   ModeDCODT[] =
+{
+    { "DEVICE", "Device", 0, 0, 0, 0} ,
+    { "PROPERTY", "Property", 0, 0, 0, 0}
+};
+static ITextVectorProperty ModeDCODTP = 
+{
+    myapdev, "SNOOPMODEDC", "Snoop dc mode", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ModeDCODT, NARRAY(ModeDCODT), "" ,0
+};
+/********************************************
+ Property: Park telescope to HOME
+*********************************************/
+
+static ISwitch ParkS[] = 
+{ 
+    {"PARK", "Park", ISS_OFF, 0, 0}, 
+};
+static ISwitchVectorProperty ParkSP = 
+{
+    myapdev, "TELESCOPE_PARK", "Park Scope", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, ParkS, NARRAY(ParkS), "", 0 
+};
+
+/* SNOOPed properties */
+
+static ISwitch ConnectionDCS[] = 
+{  
+  {"CONNECT", "Connect", ISS_OFF, 0, 0},                         
+  {"DISCONNECT", "Disconnect", ISS_OFF, 0, 0},
+};
+
+static ISwitchVectorProperty ConnectionDCSP = 
+{ 
+  "dc", "CONNECTION", "Connection", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectionDCS, NARRAY(ConnectionDCS), "", 0
+};	
+
+static ISwitch MasterAlarmS[] = 
+{  
+  {"OFF", "off", ISS_OFF, 0, 0},                         
+  {"DANGER", "danger", ISS_OFF, 0, 0},
+  {"ON", "ON", ISS_OFF, 0, 0},
+  {"RESET", "reset", ISS_OFF, 0, 0},
+};
+
+static ISwitchVectorProperty MasterAlarmSP = 
+{ 
+  "dc", "MASTERALARM", "Master alarm", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MasterAlarmS, NARRAY(MasterAlarmS), "", 0
+};
+static ISwitch ModeS[] = {  
+  {"MANUAL", "manual", ISS_ON, 0, 0},                         
+  {"DOMECONTROL", "dome control", ISS_OFF, 0, 0}
+};
+
+static ISwitchVectorProperty ModeSP = { 
+  "dc", "MODE", "Mode", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ModeS, NARRAY(ModeS), "", 0
+};	
+
+void changeLX200AstroPhysicsDeviceName(const char *newName)
+{
+    strcpy(VersionInfo.device, newName);
+    strcpy(ParkSP.device, newName);
+    strcpy(AirNP.device, newName);
+    strcpy(ConnectionDCODTP.device, newName);
+    strcpy(MasterAlarmODTP.device, newName);
+    strcpy(ModeDCODTP.device, newName);
+    strcpy(TrackModeSP.device, newName);
+    strcpy(MovementNSSP.device, newName);
+    strcpy(MovementWESP.device, newName);
+    strcpy(MoveToRateSP.device, newName);
+    strcpy(SlewRateSP.device, newName);
+    strcpy(SwapSP.device, newName);
+    strcpy(SyncCMRSP.device, newName);
+    strcpy(DeclinationAxisTP.device, newName);
+    strcpy(APLocalTimeNP.device, newName);
+    strcpy(APSiderealTimeNP.device, newName);
+    strcpy(HourAxisNP.device, newName);
+    strcpy(APUTCOffsetNP.device, newName);
+#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
+    strcpy(ApparentToObservedSP.device, newName);
+#endif
+    strcpy(HourangleCoordsNP.device, newName);
+    strcpy(HorizontalCoordsWNP.device, newName);
+    strcpy(HorizontalCoordsRNP.device, newName);
+    strcpy(EquatorialCoordsWNP.device, newName);
+    strcpy(EquatorialCoordsRNP.device, newName);
+    strcpy(DiffEquatorialCoordsNP.device, newName);
+    strcpy(StartUpSP.device, newName);
+    strcpy(DomeControlSP.device, newName);
+}
+
+/* Constructor */
+
+LX200AstroPhysics::LX200AstroPhysics() : LX200Generic()
+{
+    const char dev[]= "/dev/apmount" ;
+    const char status[]= "undefined" ;
+    IUSaveText(&ConnectionDCODT[0], ConnectionDCSP.device);
+    IUSaveText(&ConnectionDCODT[1], ConnectionDCSP.name);
+    IUSaveText(&MasterAlarmODT[0], MasterAlarmSP.device);
+    IUSaveText(&MasterAlarmODT[1], MasterAlarmSP.name);
+    IUSaveText(&ModeDCODT[0], ModeSP.device);
+    IUSaveText(&ModeDCODT[1], ModeSP.name);
+
+
+    IUSaveText(&PortTP.tp[0], dev);
+    IUSaveText(&DeclinationAxisTP.tp[0], status);
+}
+void LX200AstroPhysics::ISGetProperties (const char *dev)
+{
+    if (dev && strcmp (thisDevice, dev))
+	return;
+
+    LX200Generic::ISGetProperties(dev);
+
+    IDDelete(thisDevice, "TELESCOPE_PARK", NULL);
+    IDDefSwitch (&ParkSP, NULL);
+    IDDefText(&VersionInfo, NULL);
+
+/* Communication group */
+
+    // AstroPhysics has no alignment mode
+    IDDelete(thisDevice, "Alignment", NULL);
+    IDDefSwitch (&StartUpSP, NULL);
+    IDDefSwitch (&DomeControlSP, NULL);
+
+/* Main Group */
+#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
+    IDDefSwitch(&ApparentToObservedSP, NULL);
+#endif
+    IDDefNumber(&HourangleCoordsNP, NULL) ;
+    IDDefNumber(&HorizontalCoordsWNP, NULL);
+    IDDefNumber(&HorizontalCoordsRNP, NULL);
+    IDDelete(thisDevice, "EQUATORIAL_EOD_COORD_REQUEST", NULL);
+    IDDelete(thisDevice, "EQUATORIAL_EOD_COORD", NULL);
+    IDDefNumber(&EquatorialCoordsWNP, NULL);
+    IDDefNumber(&EquatorialCoordsRNP, NULL);
+    IDDefNumber(&DiffEquatorialCoordsNP, NULL);
+/* Date&Time group */
+    IDDelete(thisDevice, "TIME_UTC_OFFSET", NULL);
+    IDDefText(&DeclinationAxisTP, NULL);
+/* Mount group */
+
+    IDDefText(&DeclinationAxisTP, NULL);
+    IDDefNumber(&APLocalTimeNP, NULL);
+    IDDefNumber(&APSiderealTimeNP, NULL);
+    IDDefNumber(&APUTCOffsetNP, NULL);
+    IDDefNumber(&HourAxisNP, NULL);
+
+/* Atmosphere group */
+
+    IDDefNumber   (&AirNP, NULL);
+
+/* Settings group */
+
+    IDDefText   (&ConnectionDCODTP, NULL);
+    IDDefText   (&MasterAlarmODTP, NULL);
+    IDDefText   (&ModeDCODTP, NULL);
+
+    // AstroPhysics, we have no focuser, therefore, we don't need the classical one
+    IDDelete(thisDevice, "FOCUS_MODE", NULL);
+    IDDelete(thisDevice, "FOCUS_MOTION", NULL);
+    IDDelete(thisDevice, "FOCUS_TIMER", NULL);
+
+/* Motion group */
+    IDDelete(thisDevice, "Slew rate", NULL);
+    IDDelete(thisDevice, "Tracking Mode", NULL);
+    IDDelete(thisDevice, "Tracking Frequency", NULL); /* AP does not have :GT, :ST commands */
+
+    IDDefSwitch (&TrackModeSP, NULL);
+    IDDefSwitch (&MovementNSSP, NULL);
+    IDDefSwitch (&MovementWESP, NULL);
+    IDDefSwitch (&MoveToRateSP, NULL);
+    IDDefSwitch (&SlewRateSP, NULL);
+    IDDefSwitch (&SwapSP, NULL);
+    IDDefSwitch (&SyncCMRSP, NULL);
+
+/* Site management */
+    /* Astro Physics has no commands to retrieve the values */
+    /* True for all three control boxes and the software  and C-KE1, G-L*/
+    IDDelete(thisDevice, "Sites", NULL);
+    IDDelete(thisDevice, "Site Name", NULL);
+
+}
+
+void LX200AstroPhysics::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+    IText *tp=NULL;
+
+    // ignore if not ours //
+    if (strcmp (dev, thisDevice))
+	return;
+
+    // ===================================
+    // Snoop DC Connection
+    // ===================================
+    if (!strcmp(name, ConnectionDCODTP.name) )
+    {
+	tp = IUFindText( &ConnectionDCODTP, names[0] );
+	if (!tp)
+	    return;
+
+	IUSaveText(tp, texts[0]);
+	tp = IUFindText( &ConnectionDCODTP, names[1] );
+	if (!tp)
+	    return;
+
+	ConnectionDCODTP.s = IPS_OK;
+	IUSaveText(tp, texts[1]);
+
+	IDSnoopDevice( ConnectionDCODT[0].text, ConnectionDCODT[1].text);
+
+	ConnectionDCODTP.s= IPS_OK ;
+	IDSetText (&ConnectionDCODTP, "Snooping property %s at device %s", ConnectionDCODT[1].text, ConnectionDCODT[0].text);
+	return;
+    }
+
+    // ===================================
+    // Master Alarm
+    // ===================================
+    if (!strcmp(name, MasterAlarmODTP.name) )
+    {
+	tp = IUFindText( &MasterAlarmODTP, names[0] );
+	if (!tp)
+	    return;
+	    
+	IUSaveText(tp, texts[0]);
+
+	tp = IUFindText( &MasterAlarmODTP, names[1] );
+	if (!tp)
+	    return;
+	IUSaveText(tp, texts[1]);
+
+	IDSnoopDevice( MasterAlarmODT[0].text, MasterAlarmODT[1].text);
+
+	MasterAlarmODTP.s= IPS_OK ;
+	IDSetText (&MasterAlarmODTP, "Snooping property %s at device %s", MasterAlarmODT[1].text, MasterAlarmODT[0].text) ;
+	return;
+    }
+
+    // ===================================
+    // Snope DC Mode
+    // ===================================
+    if (!strcmp(name, ModeDCODTP.name) )
+    {
+	tp = IUFindText( &ModeDCODTP, names[0] );
+	if (!tp)
+	    return;
+
+	IUSaveText(tp, texts[0]);
+	tp = IUFindText( &ModeDCODTP, names[1] );
+	if (!tp)
+	    return;
+
+	ModeDCODTP.s = IPS_OK;
+	IUSaveText(tp, texts[1]);
+
+	IDSnoopDevice( ModeDCODT[0].text, ModeDCODT[1].text);
+
+	ModeDCODTP.s= IPS_OK ;
+	IDSetText (&ModeDCODTP, "Snooping property %s at device %s", ModeDCODT[1].text, ModeDCODT[0].text);
+	return;
+    }
+
+    LX200Generic::ISNewText (dev, name, texts, names, n);
+}
+
+
+void LX200AstroPhysics::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+    int i=0, nset=0;
+    INumber *np=NULL;
+
+    // ignore if not ours
+    if (strcmp (dev, thisDevice))
+	    return;
+
+    // ===================================
+    // Atmosphere
+    // ===================================
+    if (!strcmp (name, AirNP.name))
+    {
+	double newTemperature ;
+	double newPressure ;
+	double newHumidity ;
+	if (checkPower(&AirNP))
+	    return;
+
+	for (nset = i = 0; i < n; i++)
+	{
+	    np = IUFindNumber (&AirNP, names[i]);
+	    if( np == &AirN[0])
+	    {
+		newTemperature = values[i];
+		nset++ ;
+	    } 
+	    else if( np == &AirN[1])
+	    {
+		newPressure = values[i];
+		nset++ ;
+	    }
+	    else if( np == &AirN[2])
+	    {
+		newHumidity = values[i];
+		nset++  ;
+	    }
+	}
+
+	if (nset == 3)
+	{
+	    AirNP.s = IPS_OK;
+	    AirN[0].value = newTemperature;
+	    AirN[1].value = newPressure;
+	    AirN[2].value = newHumidity;
+
+	    IDSetNumber(&AirNP, NULL);
+	} 
+	else
+	{
+	    AirNP.s = IPS_ALERT;
+	    IDSetNumber(&AirNP, "Temperature, Pressure or Humidity missing or invalid");
+	}
+	return;
+    }
+
+    // ===================================
+    // AP UTC Offset
+    // ===================================
+    if ( !strcmp (name, APUTCOffsetNP.name) )
+    {
+	int ret ;
+        if (checkPower(&APUTCOffsetNP))
+            return;
+
+        if (values[0] <= 0.0 || values[0] > 24.0)
+        {
+            APUTCOffsetNP.s = IPS_IDLE;
+            IDSetNumber(&APUTCOffsetNP , "UTC offset invalid");
+            return;
+        }
+
+        if(( ret = setAPUTCOffset(fd, values[0]) < 0) )
+        {
+            handleError(&APUTCOffsetNP, ret, "Setting AP UTC offset");
+            return;
+        }
+
+        APUTCOffsetN[0].value = values[0];
+        APUTCOffsetNP.s = IPS_OK;
+
+        IDSetNumber(&APUTCOffsetNP, NULL);
+
+        return;
+    }
+
+    // =======================================
+    // Hour axis' intersection with the sphere
+    // =======================================
+    if (!strcmp (name, HourAxisNP.name))
+    {
+        int i=0, nset=0;
+	double newTheta, newGamma ;
+
+        if (checkPower(&HourAxisNP))
+            return;
+
+        for (nset = i = 0; i < n; i++)
+        {
+            np = IUFindNumber (&HourAxisNP, names[i]);
+            if ( np == &HourAxisN[0])
+            {
+                newTheta = values[i];
+                nset += newTheta >= 0 && newTheta <= 360.0;
+            }
+	    else if ( np == &HourAxisN[1])
+            {
+                newGamma = values[i];
+                nset += newGamma >= 0. && newGamma <= 90.0;
+            }
+        }
+
+        if (nset == 2)
+        {
+            HourAxisNP.s = IPS_OK;
+            HourAxisN[0].value = newTheta;
+            HourAxisN[1].value = newGamma;
+            IDSetNumber(&HourAxisNP, NULL);
+        }
+        else
+        {
+            HourAxisNP.s = IPS_ALERT;
+            IDSetNumber(&HourAxisNP, "Theta or gamma missing or invalid");
+        }
+
+        return;
+    }
+
+    // =======================================
+    // Equatorial Coord - SET
+    // =======================================
+    if (!strcmp (name, EquatorialCoordsWNP.name))
+    {
+	int err ;
+	int i=0, nset=0;
+	double newRA, newDEC ;
+	if (checkPower(&EquatorialCoordsWNP))
+	    return;
+
+	for (nset = i = 0; i < n; i++)
+	{
+	    INumber *np = IUFindNumber (&EquatorialCoordsWNP, names[i]);
+	    if (np == &EquatorialCoordsWNP.np[0])
+	    {
+		newRA = values[i];
+		nset += newRA >= 0 && newRA <= 24.0;
+	    } else if (np == &EquatorialCoordsWNP.np[1])
+	    {
+		newDEC = values[i];
+		nset += newDEC >= -90.0 && newDEC <= 90.0;
+	    }
+	}
+
+	if (nset == 2)
+	{
+	    int ret ;
+#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
+
+	    double geo[6] ;
+	    double eqt[2] ;
+	    double eqn[2] ;
+	    double hxt[2] ;
+#endif 
+	    /*EquatorialCoordsWNP.s = IPS_BUSY;*/
+	    char RAStr[32], DecStr[32];
+
+	    fs_sexa(RAStr, newRA, 2, 3600);
+	    fs_sexa(DecStr, newDEC, 2, 3600);
+
+#ifdef INDI_DEBUG
+	    IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC);
+	    IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr);
+#endif
+#if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
+	    // Transfor the coordinates
+	    /* Get the current time. */
+	    geo[0]= geoNP.np[0].value ;
+	    geo[1]= geoNP.np[1].value ;
+	    geo[2]= geoNP.np[2].value ;
+	    geo[3]= AirN[0].value ;
+	    geo[4]= AirN[1].value ;
+	    geo[5]= AirN[2].value ;
+
+	    eqn[0]= newRA ;
+	    eqn[1]= newDEC ;
+	    hxt[0]= HourAxisN[0].value ;
+	    hxt[1]= HourAxisN[1].value ;
+
+	    if((ret = LDAppToX(  getOnSwitch(&ApparentToObservedSP), eqn, ln_get_julian_from_sys(), geo, hxt, eqt)) != 0)
+	    {
+		IDMessage( myapdev, "ISNewNumber: transformation %d failed", getOnSwitch(&ApparentToObservedSP)) ;
+		exit(1) ;
+	    } ;
+	    /*EquatorialCoordsWNP.s = IPS_BUSY;*/
+	    targetRA= eqt[0];
+	    targetDEC= eqt[1];
+#else
+	    targetRA= newRA;
+            targetDEC= newDEC;
+#endif
+	    if ( (ret = setAPObjectRA(fd, targetRA)) < 0 || ( ret = setAPObjectDEC(fd, targetDEC)) < 0)
+	    {
+		DiffEquatorialCoordsNP.s= IPS_ALERT;
+		IDSetNumber(&DiffEquatorialCoordsNP, NULL);
+		handleError(&EquatorialCoordsRNP, err, "Setting RA/DEC");
+		return;
+	    }
+	    EquatorialCoordsWNP.s = IPS_OK;
+	    IDSetNumber(&EquatorialCoordsWNP, NULL);
+
+	    DiffEquatorialCoordsNP.np[0].value= targetRA - currentRA ;
+	    DiffEquatorialCoordsNP.np[1].value= targetDEC - currentDEC;
+	    DiffEquatorialCoordsNP.s= IPS_OK;
+	    IDSetNumber(&DiffEquatorialCoordsNP, NULL);
+
+	    // ToDo don't we need to stop the motion (:Q#)?
+	    if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
+	    {
+		IUResetSwitch(&MovementNSSP);
+		IUResetSwitch(&MovementWESP);
+		MovementNSSP.s = MovementWESP.s = IPS_IDLE;
+		IDSetSwitch(&MovementNSSP, NULL);
+		IDSetSwitch(&MovementWESP, NULL);
+	    }
+	    handleEqCoordSet() ;
+//ToDo : conversion to boolean	    {
+// 		EquatorialCoordsWNP.s = IPS_ALERT;
+// 		IDSetNumber(&EquatorialCoordsWNP, NULL);
+
+// 	    }
+        } // end nset
+        else
+        {
+	    EquatorialCoordsWNP.s = IPS_ALERT;
+	    IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid");
+        }
+	return ;
+    }
+
+    // =======================================
+    // Horizontal Coords - SET
+    // =======================================
+    if ( !strcmp (name, HorizontalCoordsWNP.name) )
+    {
+	int i=0, nset=0;
+	double newAz, newAlt ;
+	int ret ;
+	char altStr[64], azStr[64];
+
+	if (checkPower(&HorizontalCoordsWNP))
+	    return;
+
+        for (nset = i = 0; i < n; i++)
+	{
+	    np = IUFindNumber (&HorizontalCoordsWNP, names[i]);
+	    if (np == &HorizontalCoordsWN[0])
+	    {
+		newAz = values[i];
+		nset += newAz >= 0. && newAz <= 360.0;
+	    } 
+	    else if (np == &HorizontalCoordsWN[1])
+	    {
+		newAlt = values[i];
+		nset += newAlt >= -90. && newAlt <= 90.0;
+	    }
+	}
+	if (nset == 2)
+	{
+	    if ( (ret = setAPObjectAZ(fd, newAz)) < 0 || (ret = setAPObjectAlt(fd, newAlt)) < 0)
+	    {
+		handleError(&HorizontalCoordsWNP, ret, "Setting Alt/Az");
+		return;
+	    }
+	    targetAZ= newAz;
+	    targetALT= newAlt;
+	    HorizontalCoordsWNP.s = IPS_OK;
+	    IDSetNumber(&HorizontalCoordsWNP, NULL) ;
+
+	    fs_sexa(azStr, targetAZ, 2, 3600);
+	    fs_sexa(altStr, targetALT, 2, 3600);
+
+	    //IDSetNumber (&HorizontalCoordsWNP, "Attempting to slew to Alt %s - Az %s", altStr, azStr);
+	    handleAltAzSlew();
+	}
+	else
+	{
+	    HorizontalCoordsWNP.s = IPS_ALERT;
+	    IDSetNumber(&HorizontalCoordsWNP, "Altitude or Azimuth missing or invalid");
+	}
+
+	return;
+    }
+
+    // =======================================
+    // Geographical Location
+    // =======================================
+    if (!strcmp (name, geoNP.name))
+    {
+	// new geographic coords
+	double newLong = 0, newLat = 0;
+	int i, nset, err;
+	char msg[128];
+
+	if (checkPower(&geoNP))
+	    return;
+
+	for (nset = i = 0; i < n; i++)
+	{
+	    np = IUFindNumber (&geoNP, names[i]);
+	    if (np == &geoNP.np[0])
+	    {
+		newLat = values[i];
+		nset += newLat >= -90.0 && newLat <= 90.0;
+	    } else if (np == &geoNP.np[1])
+	    {
+		newLong = values[i];
+		nset += newLong >= 0.0 && newLong < 360.0;
+	    }
+	}
+
+	if (nset == 2)
+	{
+	    char l[32], L[32];
+	    geoNP.s = IPS_OK;
+	    fs_sexa (l, newLat, 3, 3600);
+	    fs_sexa (L, newLong, 4, 3600);
+	    
+	    if ( ( err = setAPSiteLongitude(fd, 360.0 - newLong) < 0) )
+	    {
+		handleError(&geoNP, err, "Setting site coordinates");
+		return;
+	    }
+	    if ( ( err = setAPSiteLatitude(fd, newLat) < 0) )
+	    {
+		handleError(&geoNP, err, "Setting site coordinates");
+		return;
+	    }
+
+	    geoNP.np[0].value = newLat;
+	    geoNP.np[1].value = newLong;
+	    snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L);
+	} 
+	else
+	{
+	    geoNP.s = IPS_IDLE;
+	    strcpy(msg, "Lat or Long missing or invalid");
+	}
+	IDSetNumber (&geoNP, "%s", msg);
+	return;
+    }
+
+    LX200Generic::ISNewNumber (dev, name, values, names, n);
+}
+
+void LX200AstroPhysics::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+    int err=0;
+
+    // ignore if not ours //
+    if (strcmp (thisDevice, dev))
+	    return;
+
+    // =======================================
+    // Connect
+    // =======================================
+    if (!strcmp (name, ConnectSP.name))
+    {
+	IUUpdateSwitch(&ConnectSP, states, names, n) ;
+
+	connectTelescope();
+	return;
+    }
+
+    // ============================================================
+    // Satisfy AP mount initialization, see AP key pad manual p. 76
+    // ============================================================
+    if (!strcmp (name, StartUpSP.name))
+    {
+	int ret ;
+	int switch_nr ;
+	static int mount_status= MOUNTNOTINITIALIZED ;
+
+	IUUpdateSwitch(&StartUpSP, states, names, n) ;
+
+       	if( mount_status == MOUNTNOTINITIALIZED)
+	{
+	    mount_status=MOUNTINITIALIZED;
+	
+	    if(( ret= setBasicDataPart0())< 0)
+	    {
+		// ToDo do something if needed
+		StartUpSP.s = IPS_ALERT ;
+		IDSetSwitch(&StartUpSP, "Mount initialization failed") ;
+		return ;
+	    }
+	    if( StartUpSP.sp[0].s== ISS_ON) // do it only in case a power on (cold start) 
+	    {
+		if(( ret= setBasicDataPart1())< 0)
+		{
+		    // ToDo do something if needed
+		    StartUpSP.s = IPS_ALERT ;
+		    IDSetSwitch(&StartUpSP, "Mount initialization failed") ;
+		    return ;
+		}
+	    }
+	    // Make sure that the mount is setup according to the properties	    
+	    switch_nr = getOnSwitch(&TrackModeSP);
+
+	    if ( ( err = selectAPTrackingMode(fd, switch_nr) < 0) )
+	    {
+		handleError(&TrackModeSP, err, "StartUpSP: Setting tracking mode.");
+		return;
+	    }
+	    TrackModeSP.s = IPS_OK;
+	    IDSetSwitch(&TrackModeSP, NULL);
+	    //ToDo set button swapping acording telescope east west
+	    // ... some code here
+
+	    switch_nr = getOnSwitch(&MoveToRateSP);
+	  
+	    if ( ( err = selectAPMoveToRate(fd, switch_nr) < 0) )
+	    {
+		handleError(&MoveToRateSP, err, "StartUpSP: Setting move to rate.");
+		return;
+	    }
+	    MoveToRateSP.s = IPS_OK;
+
+	    IDSetSwitch(&MoveToRateSP, NULL);
+	    switch_nr = getOnSwitch(&SlewRateSP);
+	  
+	    if ( ( err = selectAPSlewRate(fd, switch_nr) < 0) )
+	    {
+		handleError(&SlewRateSP, err, "StartUpSP: Setting slew rate.");
+		return;
+	    }
+	    SlewRateSP.s = IPS_OK;
+	    IDSetSwitch(&SlewRateSP, NULL);
+
+	    StartUpSP.s = IPS_OK ;
+	    IDSetSwitch(&StartUpSP, "Mount initialized") ;
+	    // Fetch the coordinates and set RNP and WNP
+	    getLX200RA( fd, &currentRA); 
+	    getLX200DEC(fd, &currentDEC);
+ 
+	    // make a IDSet in order the dome controller is aware of the initial values
+	    targetRA= currentRA ;
+	    targetDEC= currentDEC ;
+	    EquatorialCoordsWNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */
+	    IDSetNumber(&EquatorialCoordsWNP,  "EquatorialCoordsWNP.s = IPS_BUSY after initialization");
+
+	    // sleep for 100 mseconds
+	    usleep(100000);
+
+	    EquatorialCoordsWNP.s = IPS_OK; 
+	    IDSetNumber(&EquatorialCoordsWNP, NULL);
+
+	    getLX200Az(fd, &currentAZ);
+	    getLX200Alt(fd, &currentALT);
+
+	    HorizontalCoordsRNP.s = IPS_OK ;
+	    IDSetNumber (&HorizontalCoordsRNP, NULL);
+
+	    VersionInfo.tp[0].text = new char[64];
+	    getAPVersionNumber(fd, VersionInfo.tp[0].text);
+
+	    VersionInfo.s = IPS_OK ;
+	    IDSetText(&VersionInfo, NULL);
+
+	    if(( getOnSwitch(&DomeControlSP))== DOMECONTROL)
+	    {
+	        //ToDo compare that with other driver, not the best way
+		IDSnoopDevice( MasterAlarmODTP.tp[0].text, MasterAlarmODTP.tp[1].text);
+		MasterAlarmODTP.s= IPS_OK ;
+		IDSetText (&MasterAlarmODTP, "SNOOPing %s on device %s", MasterAlarmODTP.tp[1].text, MasterAlarmODTP.tp[0].text);
+
+		IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text);
+		ConnectionDCODTP.s= IPS_OK ;
+		IDSetText (&ConnectionDCODTP, "SNOOPing %s on device %s", ConnectionDCODTP.tp[1].text, ConnectionDCODTP.tp[0].text);
+		IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text);
+
+		IDSnoopDevice( ModeDCODTP.tp[0].text, ModeDCODTP.tp[1].text);
+		ModeDCODTP.s= IPS_OK ;
+		IDSetText (&ModeDCODTP, "SNOOPing %s on device %s", ModeDCODTP.tp[1].text, ModeDCODTP.tp[0].text);
+
+	        // once chosen no unsnooping is possible
+		DomeControlSP.s= IPS_OK ;
+		IDSetSwitch(&DomeControlSP, NULL) ;
+	    }
+	    else
+	    {
+		IDMessage( myapdev, "Not operating in dome control mode") ;
+	    }
+	     #ifndef HAVE_NOVA_H
+	    IDMessage( myapdev, "Libnova not compiled in, consider to install it (http://libnova.sourceforge.net/)") ;
+	    #endif
+	    #ifndef HAVE_NOVASCC_H
+	    IDMessage( myapdev, "NOVASCC not compiled in, consider to install it (http://aa.usno.navy.mil/AA/)") ;
+	    #endif
+	}
+	else
+	{
+	    StartUpSP.s = IPS_ALERT ;
+	    IDSetSwitch(&StartUpSP, "Mount is already initialized") ;
+	}
+	return;
+    }
+
+    // =======================================
+    // Park
+    // =======================================
+    if (!strcmp(name, ParkSP.name))
+    {
+	if (checkPower(&ParkSP))
+	    return;
+	
+	if (EquatorialCoordsWNP.s == IPS_BUSY)
+	{
+	    // ToDo handle return value
+	    abortSlew(fd);
+	    // sleep for 200 mseconds
+	    usleep(200000);
+	    AbortSlewSP.s = IPS_OK;
+            IDSetSwitch(&AbortSlewSP, NULL);
+ 
+	}
+
+	if (setAPPark(fd) < 0)
+	{
+	    ParkSP.s = IPS_ALERT;
+	    IDSetSwitch(&ParkSP, "Parking Failed.");
+	    return;
+	}
+
+	ParkSP.s = IPS_OK;
+	IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting...");
+        // avoid sending anything to the mount controller
+	tty_disconnect( fd);
+	ConnectSP.s   = IPS_IDLE;
+	ConnectSP.sp[0].s = ISS_OFF;
+	ConnectSP.sp[1].s = ISS_ON;
+        
+	IDSetSwitch(&ConnectSP, NULL);
+
+	StartUpSP.s = IPS_IDLE ;
+	IDSetSwitch(&StartUpSP, NULL) ;
+
+	// ToDo reset all values
+
+	return;
+    }
+
+    // =======================================
+    // Tracking Mode
+    // =======================================
+    if (!strcmp (name, TrackModeSP.name))
+    {
+	if (checkPower(&TrackModeSP))
+	    return;
+
+	IUResetSwitch(&TrackModeSP);
+	IUUpdateSwitch(&TrackModeSP, states, names, n);
+	trackingMode = getOnSwitch(&TrackModeSP);
+	  
+	if ( ( err = selectAPTrackingMode(fd, trackingMode) < 0) )
+	{
+	    handleError(&TrackModeSP, err, "Setting tracking mode.");
+	    return;
+	}     
+	TrackModeSP.s = IPS_OK;
+	IDSetSwitch(&TrackModeSP, NULL);
+	if( trackingMode != 3) /* not zero */
+	{
+	    AbortSlewSP.s = IPS_IDLE;
+	    IDSetSwitch(&AbortSlewSP, NULL);
+	}
+	return;
+    }
+
+    // =======================================
+    // Swap Buttons
+    // =======================================
+    if (!strcmp(name, SwapSP.name))
+    {
+	int currentSwap ;
+
+	if (checkPower(&SwapSP))
+	    return;
+	
+	IUResetSwitch(&SwapSP);
+	IUUpdateSwitch(&SwapSP, states, names, n);
+	currentSwap = getOnSwitch(&SwapSP);
+
+	if(( err = swapAPButtons(fd, currentSwap) < 0) )
+	{
+	    handleError(&SwapSP, err, "Swapping buttons.");
+	    return;
+	}
+
+	SwapS[0].s= ISS_OFF ;
+	SwapS[1].s= ISS_OFF ;
+	SwapSP.s = IPS_OK;
+	IDSetSwitch(&SwapSP, NULL);
+	return ;
+    }
+
+    // =======================================
+    // Swap to rate
+    // =======================================
+    if (!strcmp (name, MoveToRateSP.name))
+    {
+	int moveToRate ;
+
+	if (checkPower(&MoveToRateSP))
+	    return;
+
+	IUResetSwitch(&MoveToRateSP);
+	IUUpdateSwitch(&MoveToRateSP, states, names, n);
+	moveToRate = getOnSwitch(&MoveToRateSP);
+	  
+	if ( ( err = selectAPMoveToRate(fd, moveToRate) < 0) )
+	{
+	    handleError(&MoveToRateSP, err, "Setting move to rate.");
+	    return;
+	}
+	MoveToRateSP.s = IPS_OK;
+	IDSetSwitch(&MoveToRateSP, NULL);
+	return;
+    }
+
+    // =======================================
+    // Slew Rate
+    // =======================================
+    if (!strcmp (name, SlewRateSP.name))
+    {
+	int slewRate ;
+	
+	if (checkPower(&SlewRateSP))
+	    return;
+
+	IUResetSwitch(&SlewRateSP);
+	IUUpdateSwitch(&SlewRateSP, states, names, n);
+	slewRate = getOnSwitch(&SlewRateSP);
+	  
+	if ( ( err = selectAPSlewRate(fd, slewRate) < 0) )
+	{
+	    handleError(&SlewRateSP, err, "Setting slew rate.");
+	    return;
+	}
+	  
+          
+	SlewRateSP.s = IPS_OK;
+	IDSetSwitch(&SlewRateSP, NULL);
+	return;
+    }
+
+    // =======================================
+    // Choose the appropriate sync command
+    // =======================================
+    if (!strcmp(name, SyncCMRSP.name))
+    {
+	int currentSync ;
+	if (checkPower(&SyncCMRSP))
+	    return;
+
+	IUResetSwitch(&SyncCMRSP);
+	IUUpdateSwitch(&SyncCMRSP, states, names, n);
+	currentSync = getOnSwitch(&SyncCMRSP);
+	SyncCMRSP.s = IPS_OK;
+	IDSetSwitch(&SyncCMRSP, NULL);
+	return ;
+    }
+
+    #if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H
+    // =======================================
+    // Set various transformations
+    // =======================================
+    if (!strcmp (name, ApparentToObservedSP.name))
+    {
+	int trans_to ;
+	if (checkPower(&ApparentToObservedSP))
+	    return;
+
+	IUResetSwitch(&ApparentToObservedSP);
+	IUUpdateSwitch(&ApparentToObservedSP, states, names, n);
+	trans_to = getOnSwitch(&ApparentToObservedSP);
+
+	ApparentToObservedSP.s = IPS_OK;
+	IDSetSwitch(&ApparentToObservedSP, "Transformation %d", trans_to);
+	return;
+    }
+    #endif
+    if (!strcmp (name, DomeControlSP.name))
+    {
+	if((DomeControlSP.s== IPS_OK) &&( DomeControlSP.sp[0].s== ISS_ON))
+	{
+    #ifdef INDI_DEBUG
+	    IDLog("Once in dome control mode no return is possible (INDI has no \"unsnoop\")\n") ;
+    #endif
+	    DomeControlSP.s= IPS_ALERT ;
+            IDSetSwitch(&DomeControlSP, "Once in dome control mode no return is possible (INDI has no \"unsnoop\")") ;
+	}
+	else
+	{
+	    int last_state= getOnSwitch(&DomeControlSP) ;
+	    IUResetSwitch(&DomeControlSP);
+	    IUUpdateSwitch(&DomeControlSP, states, names, n) ;
+	    DomeControlSP.s= IPS_OK ;
+	    IDSetSwitch(&DomeControlSP, NULL) ;
+
+	    if(( DomeControlSP.s== IPS_OK) &&( last_state== NOTDOMECONTROL)) /* dome control mode after mount init. */
+	    {
+		//ToDo compare that with other driver, not the best way
+                IDSnoopDevice( MasterAlarmODTP.tp[0].text, MasterAlarmODTP.tp[1].text);
+                MasterAlarmODTP.s= IPS_OK ;
+                IDSetText (&MasterAlarmODTP, "SNOOPing %s on device %s", MasterAlarmODTP.tp[1].text, MasterAlarmODTP.tp[0].text);
+
+                IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text);
+                ConnectionDCODTP.s= IPS_OK ;
+                IDSetText (&ConnectionDCODTP, "SNOOPing %s on device %s", ConnectionDCODTP.tp[1].text, ConnectionDCODTP.tp[0].text);
+                IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text);
+
+                IDSnoopDevice( ModeDCODTP.tp[0].text, ModeDCODTP.tp[1].text);
+                ModeDCODTP.s= IPS_OK ;
+                IDSetText (&ModeDCODTP, "SNOOPing %s on device %s", ModeDCODTP.tp[1].text, ModeDCODTP.tp[0].text);
+	    }
+	}
+	return;
+    }
+
+    LX200Generic::ISNewSwitch (dev, name, states, names,  n);
+ }
+void LX200AstroPhysics::ISSnoopDevice (XMLEle *root)
+{
+    int err ;
+    if (IUSnoopSwitch(root, &MasterAlarmSP) == 0)
+    {
+        //IDMessage( myapdev, "ISCollisionStatusS received new values %s: %d, %s: %d, %s: %d.", names[0], states[0],names[1], states[1],names[2], states[2]);
+	if( MasterAlarmS[1].s == ISS_ON) /* Approaching a critical situation */
+	{
+/* Stop if possible any motion */
+	    // ToDo
+	    abortSlew(fd);
+	    AbortSlewSP.s = IPS_OK;
+            IDSetSwitch(&AbortSlewSP, NULL);
+
+	    if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
+	    {
+		IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
+		return;
+	    }
+	    IUResetSwitch(&TrackModeSP);
+	    TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */
+	    TrackModeSP.sp[1].s= ISS_OFF ; /* solar */
+	    TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */
+	    TrackModeSP.sp[3].s= ISS_ON ;  /* zero */
+	    
+	    TrackModeSP.s = IPS_ALERT;
+	    IDSetSwitch(&TrackModeSP, "Device %s MasterAlarm OFF: approaching a critical situation, avoided by apmount, stopped motors, no tracking!", MasterAlarmODT[0].text);   
+	}
+	else if( MasterAlarmS[2].s == ISS_ON) /* a critical situation */
+	{
+
+/* If Master Alarm is on it is "too" late. So we do the same as under MasterAlarmS[1].s == ISS_ON*/
+/* The device setting up the Master Alarm should switch power off*/
+	    // ToDo
+	    abortSlew(fd);
+	    AbortSlewSP.s = IPS_OK;
+            IDSetSwitch(&AbortSlewSP, NULL);
+
+
+	    if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
+	    {
+		IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
+		return;
+	    }
+	    IUResetSwitch(&TrackModeSP);
+	    TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */
+	    TrackModeSP.sp[1].s= ISS_OFF ; /* solar */
+	    TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */
+	    TrackModeSP.sp[3].s= ISS_ON  ;  /* zero */
+
+	    TrackModeSP.s = IPS_ALERT;
+	    IDSetSwitch(&TrackModeSP, "Device %s MasterAlarm ON: critical situation avoided, stopped motors, no tracking!", MasterAlarmODT[0].text);
+	}
+	else if((MasterAlarmS[2].s == ISS_OFF) && (MasterAlarmS[1].s == ISS_OFF) && (MasterAlarmS[0].s == ISS_OFF))
+	{
+	    //ToDo make the mastar alarm indicator more visible!!
+	    TrackModeSP.s = IPS_OK;
+	    IDSetSwitch(&TrackModeSP, "MasterAlarm Status ok");
+	    // values obtained via ISPoll
+	    IDSetNumber(&EquatorialCoordsWNP, "Setting (sending) EquatorialCoordsRNP on reset MasterAlarm");
+	}
+	else
+	{
+	    if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
+	    {
+		IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
+		return;
+	    }
+	    IUResetSwitch(&TrackModeSP);
+	    TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */
+	    TrackModeSP.sp[1].s= ISS_OFF ; /* solar */
+	    TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */
+	    TrackModeSP.sp[3].s= ISS_ON  ;  /* zero */
+
+	    TrackModeSP.s = IPS_ALERT;
+	    TrackModeSP.s = IPS_ALERT;
+	    IDSetSwitch(&TrackModeSP, "Device %s MASTER ALARM Unknown Status", MasterAlarmODT[0].text);
+	}
+    }
+    else if (IUSnoopSwitch(root, &ConnectionDCSP) == 0)
+    {
+	if( ConnectionDCS[0].s != ISS_ON)
+	{
+	    // ToDo
+	    abortSlew(fd);
+	    AbortSlewSP.s = IPS_OK;
+            IDSetSwitch(&AbortSlewSP, NULL);
+
+
+	    if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */
+	    {
+		IDMessage( myapdev, "FAILED: Setting tracking mode ZERO.");
+		return;
+	    }
+	    IUResetSwitch(&TrackModeSP);
+	    TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */
+	    TrackModeSP.sp[1].s= ISS_OFF ; /* solar */
+	    TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */
+	    TrackModeSP.sp[3].s= ISS_ON ;  /* zero */
+
+	    TrackModeSP.s = IPS_ALERT;
+	    IDSetSwitch(&TrackModeSP, "Driver %s disconnected: critical situation avoided, stopped motors, no tracking!", MasterAlarmODT[0].text);
+	}
+    }
+    else if (IUSnoopSwitch(root, &ModeSP) == 0)
+    {
+	if( ModeS[1].s == ISS_ON) /* late dome control mode */
+	{
+	    getLX200RA( fd, &currentRA); 
+	    getLX200DEC(fd, &currentDEC);
+ 
+	    targetRA= currentRA ;
+	    targetDEC= currentDEC ;
+	    EquatorialCoordsWNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */
+	    IDSetNumber(&EquatorialCoordsWNP, "Setting (sending) EquatorialCoordsRNP on ModeS[1].s != ISS_ON");
+	    // sleep for 100 mseconds
+	    usleep(100000);
+	    EquatorialCoordsWNP.s = IPS_OK; 
+	    IDSetNumber(&EquatorialCoordsWNP, NULL) ;
+	}
+    }
+}
+bool LX200AstroPhysics::isMountInit(void)
+{
+    return (StartUpSP.s != IPS_IDLE);
+}
+
+void LX200AstroPhysics::ISPoll()
+{
+     int ret ;
+//     int ddd, mm ;
+     if (!isMountInit())
+	 return;
+//     #ifdef INDI_DEBUG
+//     getSiteLongitude(fd, &ddd, &mm) ;
+//     IDLog("longitude %d:%d\n", ddd, mm);
+//     getSiteLatitude(fd, &ddd, &mm) ;
+//     IDLog("latitude %d:%d\n", ddd, mm);
+//     getAPUTCOffset( fd, &APUTCOffsetN[0].value) ;
+//     IDLog("UTC offset %10.6f\n", APUTCOffsetN[0].value);
+//     #endif
+
+
+     //============================================================
+     // #1 Call LX200Generic ISPoll
+     //============================================================
+     LX200Generic::ISPoll();
+
+
+     //============================================================
+     // #2 Get Local Time
+     //============================================================
+     if(( ret= getLocalTime24( fd, &APLocalTimeN[0].value)) == 0)
+     {
+ 	 APLocalTimeNP.s = IPS_OK ;
+     }
+     else
+     {
+ 	 APLocalTimeNP.s = IPS_ALERT ;
+     }
+     IDSetNumber(&APLocalTimeNP, NULL);
+
+//     #ifdef INDI_DEBUG
+//     IDLog("localtime %f\n", APLocalTimeN[0].value) ;
+//     #endif
+
+     //============================================================
+     // #3 Get Sidereal Time
+     //============================================================
+     if(( ret= getSDTime( fd, &APSiderealTimeN[0].value)) == 0)
+     {
+ 	 APSiderealTimeNP.s = IPS_OK ;
+     }
+     else
+     {
+ 	 APSiderealTimeNP.s = IPS_ALERT ;
+     }
+     IDSetNumber(&APSiderealTimeNP, NULL);
+//     #ifdef INDI_DEBUG
+//     IDLog("siderealtime %f\n", APSiderealTimeN[0].value) ;
+//     #endif
+
+     //============================================================
+     // #4 Get UTC Offset
+     //============================================================
+     if(( ret= getAPUTCOffset( fd, &APUTCOffsetN[0].value)) == 0)
+     {
+ 	 APUTCOffsetNP.s = IPS_OK ;
+     }
+     else
+     {
+ 	 APUTCOffsetNP.s = IPS_ALERT ;
+     }
+     IDSetNumber(&APUTCOffsetNP, NULL);
+
+     //============================================================
+     // #5 
+     //============================================================
+     if(( ret= getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) == 0)
+     {
+	 DeclinationAxisTP.s = IPS_OK ;
+     }
+     else
+
+     {
+	 DeclinationAxisTP.s = IPS_ALERT ;
+     }
+     IDSetText(&DeclinationAxisTP, NULL) ;
+
+
+     /* LX200Generic should take care of this */
+     //getLX200RA(fd, &currentRA );
+     //getLX200DEC(fd, &currentDEC );
+     //EquatorialCoordsRNP.s = IPS_OK ;
+     //IDSetNumber (&EquatorialCoordsRNP, NULL);
+     
+   
+/* Calculate the hour angle */
+
+     HourangleCoordsNP.np[0].value= 180. /M_PI/15. * LDRAtoHA( 15.* currentRA /180. *M_PI, -geoNP.np[1].value/180. *M_PI);
+     HourangleCoordsNP.np[1].value= currentDEC;
+
+     HourangleCoordsNP.s = IPS_OK;
+     IDSetNumber(&HourangleCoordsNP, NULL);
+
+     getLX200Az(fd, &currentAZ);
+     getLX200Alt(fd, &currentALT);
+
+     /* The state of RNP is coupled to the WNP 
+     HorizontalCoordsRNP.s = IPS_OK ;
+     IDSetNumber (&HorizontalCoordsRNP, NULL);
+     */
+
+     // LX200generic has no  HorizontalCoords(R|W)NP
+     if( HorizontalCoordsWNP.s == IPS_BUSY) /* telescope is syncing or slewing */
+     {
+	 
+	 double dx = fabs ( targetAZ  - currentAZ);
+	 double dy = fabs ( targetALT  - currentALT);
+
+	 if (dx <= (SlewAccuracyNP.np[0].value/(60.0*15.0)) && (dy <= SlewAccuracyNP.np[1].value/60.0)) 
+	 {
+             #ifdef INDI_DEBUG
+	     IDLog("Slew completed.\n");
+             #endif
+	     HorizontalCoordsWNP.s = IPS_OK ;
+	     IDSetNumber(&HorizontalCoordsWNP, "Slew completed") ;
+	 }
+	 else
+	 {
+             #ifdef INDI_DEBUG
+	     IDLog("Slew in progress.\n");
+             #endif
+	 }
+     }
+     if(StartUpSP.s== IPS_OK) /* the dome controller needs to be informed even in case dc has been started long after lx200ap*/
+     {
+	 StartUpSP.s = IPS_OK ;
+	 IDSetSwitch(&StartUpSP, NULL) ;
+     }
+     else
+     {
+	 StartUpSP.s = IPS_ALERT ;
+	 IDSetSwitch(&StartUpSP, NULL) ;
+     }
+
+}
+int LX200AstroPhysics::setBasicDataPart0()
+{
+    int err ;
+#ifdef HAVE_NOVA_H
+    struct ln_date utm;
+    struct ln_zonedate ltm;
+#endif
+    if(setAPClearBuffer( fd) < 0)
+    {
+	handleError(&ConnectSP, err, "Clearing the buffer");
+	return -1;
+    }
+    if(setAPLongFormat( fd) < 0)
+    {
+	IDMessage( myapdev, "Setting long format failed") ;
+	return -1;
+    }
+    
+    // ToDo make a property
+    if(setAPBackLashCompensation(fd, 0,0,0) < 0)
+    {
+	handleError(&ConnectSP, err, "Setting back lash compensation");
+	return -1;
+    }
+#if defined HAVE_NOVA_H
+    ln_get_date_from_sys( &utm) ;
+    ln_date_to_zonedate(&utm, &ltm, 3600);
+
+    if((  err = setLocalTime(fd, ltm.hours, ltm.minutes, (int) ltm.seconds) < 0))
+    {
+	handleError(&ConnectSP, err, "Setting local time");
+	return -1;
+    }
+    if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) )
+    {
+	handleError(&ConnectSP, err, "Setting local date");
+	return -1;
+    }
+    #ifdef INDI_DEBUG
+    IDLog("UT time is: %04d/%02d/%02d T %02d:%02d:%02d\n", utm.years, utm.months, utm.days, utm.hours, utm.minutes, (int)utm.seconds);
+    IDLog("Local time is: %04d/%02d/%02d T %02d:%02d:%02d\n", ltm.years, ltm.months, ltm.days, ltm.hours, ltm.minutes, (int)ltm.seconds);
+    #endif
+
+    // ToDo: strange but true offset 22:56:07, -1:03:53 (valid for obs Vermes)
+    // Understand what happens with AP controller sidereal time, azimut coordinates
+    if((err = setAPUTCOffset( fd, -1.0647222)) < 0)
+    {
+        handleError(&ConnectSP, err,"Setting AP UTC offset") ;
+        return -1;
+    }
+#else
+    IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ;
+#endif
+
+    return 0 ;
+}
+int LX200AstroPhysics::setBasicDataPart1()
+{
+    int err ;
+
+    if((err = setAPUnPark( fd)) < 0)
+    {
+	handleError(&ConnectSP, err,"Unparking failed") ;
+	return -1;
+    }
+#ifdef INDI_DEBUG
+    IDLog("Unparking successful\n");
+#endif
+
+    if((err = setAPMotionStop( fd)) < 0)
+    {
+	handleError(&ConnectSP, err, "Stop motion (:Q#) failed, check the mount") ;
+	return -1;
+    }
+#ifdef INDI_DEBUG
+    IDLog("Stopped any motion (:Q#)\n");
+#endif
+
+    return 0 ;
+}
+void LX200AstroPhysics::connectTelescope()
+{
+    static int established= NOTESTABLISHED ;
+
+    switch (ConnectSP.sp[0].s)
+    {
+	case ISS_ON:  
+	
+	    if( ! established)
+	    {
+		if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
+		{
+		    ConnectSP.sp[0].s = ISS_OFF;
+		    ConnectSP.sp[1].s = ISS_ON;
+		    IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text);
+		    established= NOTESTABLISHED ;
+		    return;
+		}
+		if (check_lx200ap_connection(fd))
+		{   
+		    ConnectSP.sp[0].s = ISS_OFF;
+		    ConnectSP.sp[1].s = ISS_ON;
+		    IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline.");
+		    established= NOTESTABLISHED ;
+		    return;
+		}
+		established= ESTABLISHED ;
+		#ifdef INDI_DEBUG
+		IDLog("Telescope test successful\n");
+		#endif
+		// At this point e.g. no GEOGRAPHIC_COORD are available after the first client connects.
+		// Postpone set up of the telescope
+		// NO setBasicData() ;
+
+		// ToDo what is that *((int *) UTCOffsetN[0].aux0) = 0;
+                // Jasem: This is just a way to know if the client has init UTC Offset, and if he did, then we set aux0 to 1, otherwise it stays at 0. When
+                // the client tries to change UTC, but has not set UTFOffset yet (that is, aux0 = 0) then we can tell him to set the UTCOffset first. Btw,
+		// the UTF & UTFOffset will be merged in one property for INDI v0.6
+		ConnectSP.s = IPS_OK;
+		IDSetSwitch (&ConnectSP, "Telescope is online");
+	    }
+	    else
+	    {
+		ConnectSP.s = IPS_OK;
+		IDSetSwitch (&ConnectSP, "Connection already established.");
+	    }
+	    break;
+
+	case ISS_OFF:
+	    ConnectSP.sp[0].s = ISS_OFF;
+	    ConnectSP.sp[1].s = ISS_ON;
+	    ConnectSP.s = IPS_IDLE;
+	    IDSetSwitch (&ConnectSP, "Telescope is offline.");
+	    if (setAPPark(fd) < 0)
+	    {
+		ParkSP.s = IPS_ALERT;
+		IDSetSwitch(&ParkSP, "Parking Failed.");
+	    return;
+	    }
+
+	    ParkSP.s = IPS_OK;
+	    IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting...");
+
+	    tty_disconnect(fd);
+	    established= NOTESTABLISHED ;
+#ifdef INDI_DEBUG
+	    IDLog("The telescope is parked. Turn off the telescope. Disconnected.\n");
+#endif
+	    break;
+    }
+}
+// taken from lx200_16
+void LX200AstroPhysics::handleAltAzSlew()
+{
+    int i=0;
+    char altStr[64], azStr[64];
+
+    if (HorizontalCoordsWNP.s == IPS_BUSY)
+    {
+	abortSlew(fd);
+	AbortSlewSP.s = IPS_OK;
+	IDSetSwitch(&AbortSlewSP, NULL);
+
+	// sleep for 100 mseconds
+	usleep(100000);
+    }
+// ToDo is it ok ?
+//    if ((i = slewToAltAz(fd)))
+    if ((i = Slew(fd)))
+    {
+	HorizontalCoordsWNP.s = IPS_ALERT;
+	IDSetNumber(&HorizontalCoordsWNP, "Slew is not possible.");
+	return;
+    }
+
+    HorizontalCoordsWNP.s = IPS_OK;
+    fs_sexa(azStr, targetAZ, 2, 3600);
+    fs_sexa(altStr, targetALT, 2, 3600);
+
+    IDSetNumber(&HorizontalCoordsWNP, "Slewing to Alt %s - Az %s", altStr, azStr);
+    return;
+}
+void LX200AstroPhysics::handleEqCoordSet()
+{
+    int sync ;
+    int  err;
+    char syncString[256];
+    char RAStr[32], DecStr[32];
+    double dx, dy;
+    int syncOK= 0 ;
+    double targetHA ;
+
+#ifdef INDI_DEBUG
+    IDLog("In Handle AP EQ Coord Set(), switch %d\n", getOnSwitch(&OnCoordSetSP));
+#endif
+    switch (getOnSwitch(&OnCoordSetSP))
+    {
+	// Slew
+	case LX200_TRACK:
+	    lastSet = LX200_TRACK;
+	    if (EquatorialCoordsWNP.s == IPS_BUSY)
+	    {
+#ifdef INDI_DEBUG
+		IDLog("Aborting Track\n");
+#endif
+                // ToDo
+		abortSlew(fd);
+		AbortSlewSP.s = IPS_OK;
+		IDSetSwitch(&AbortSlewSP, NULL);
+
+		// sleep for 100 mseconds
+		usleep(100000);
+	    }
+	    if ((err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */
+	    {
+		slewError(err);
+		// ToDo handle that with the handleError function
+		return ;
+	    }
+	    EquatorialCoordsWNP.s = IPS_BUSY;
+	    fs_sexa(RAStr,  targetRA, 2, 3600);
+	    fs_sexa(DecStr, targetDEC, 2, 3600);
+	    IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
+#ifdef INDI_DEBUG
+	    IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
+#endif
+	    break;
+
+
+	    // Sync
+	case LX200_SYNC:
+
+	    lastSet = LX200_SYNC;
+
+/* Astro-Physics has two sync options. In order that no collision occurs, the SYNCCMR */
+/* variant behaves for now identical like SYNCCM. Later this feature will be enabled.*/ 
+/* Calculate the hour angle of the target */
+
+	    targetHA= 180. /M_PI/15. * LDRAtoHA( 15.*  targetRA/180. *M_PI, -geoNP.np[1].value/180. *M_PI);
+
+	    if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR)
+	    {
+		if (!strcmp("West", DeclinationAxisT[0].text))
+		{
+		    if(( targetHA > 12.0) && ( targetHA <= 24.0))
+		    {
+			syncOK= 1 ;
+		    }
+		    else
+		    {
+			syncOK= 0 ;
+		    }
+		}
+		else if (!strcmp("East", DeclinationAxisT[0].text))
+		{
+		    if(( targetHA >= 0.0) && ( targetHA <= 12.0))
+		    {
+			syncOK= 1 ;
+		    }
+		    else
+		    {
+			syncOK= 0 ;
+		    }
+		}
+		else
+		{
+#ifdef INDI_DEBUG
+		    IDLog("handleEqCoordSet(): SYNC NOK not East or West\n") ;
+#endif
+		    return ;
+		}
+	    }
+	    else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCM)
+	    {
+		syncOK = 1 ;
+	    }
+	    else
+	    {
+#ifdef INDI_DEBUG
+		IDLog("handleEqCoordSet(): SYNC NOK not SYNCCM or SYNCCMR\n") ;
+#endif
+		return ;
+	    }
+	    if( syncOK == 1)
+	    {
+		if( (sync=getOnSwitch(&SyncCMRSP))==SYNCCM)
+		{
+		    if ( ( err = APSyncCM(fd, syncString) < 0) )
+		    {
+			EquatorialCoordsWNP.s = IPS_ALERT ;
+			IDSetNumber( &EquatorialCoordsWNP , "Synchronization failed.");
+			// ToDo handle with handleError function
+			return ;
+		    }
+		}
+		else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR)
+		{
+		    if ( ( err = APSyncCMR(fd, syncString) < 0) )
+		    {
+			EquatorialCoordsWNP.s = IPS_ALERT ;
+			IDSetNumber( &EquatorialCoordsWNP, "Synchronization failed.");
+			// ToDo handle with handleError function
+			return ;
+		    }
+		}
+		else
+		{
+		    EquatorialCoordsWNP.s = IPS_ALERT ;
+		    IDSetNumber( &EquatorialCoordsWNP , "SYNC NOK no valid SYNCCM, SYNCCMR");
+#ifdef INDI_DEBUG
+		    IDLog("SYNC NOK no valid SYNCCM, SYNCCMR\n") ;
+#endif
+		    return ;
+		}
+/* get the property DeclinationAxisTP first */
+		if(( err = getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) < 0)
+		{
+		    //ToDo handleErr
+		    DeclinationAxisTP.s = IPS_ALERT ;
+		    IDSetText(&DeclinationAxisTP, "Declination axis undefined") ;  
+		    return ;
+		}
+
+		DeclinationAxisTP.s = IPS_OK ;
+#ifdef INDI_DEBUG
+		IDLog("Declination axis is on the %s side\n", DeclinationAxisT[0].text) ;
+#endif
+		IDSetText(&DeclinationAxisTP, NULL) ; 
+
+                getLX200RA( fd, &currentRA); 
+                getLX200DEC(fd, &currentDEC);
+// The mount executed the sync command, now read back the values, make a IDSet in order the dome controller
+// is aware of the new target
+                targetRA= currentRA ;
+                targetDEC= currentDEC ;
+                EquatorialCoordsWNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */
+                IDSetNumber(&EquatorialCoordsWNP,  "EquatorialCoordsWNP.s = IPS_BUSY after SYNC");
+	    }
+	    else
+	    {
+#ifdef INDI_DEBUG
+		IDLog("Synchronization not allowed\n") ;
+#endif
+
+		EquatorialCoordsWNP.s = IPS_ALERT;
+		IDSetNumber(&EquatorialCoordsWNP,  "Synchronization not allowed" );
+
+#ifdef INDI_DEBUG
+                    IDLog("Telescope is on the wrong side targetHA was %f\n", targetHA) ;
+#endif
+		DeclinationAxisTP.s = IPS_ALERT ;
+		IDSetText(&DeclinationAxisTP, "Telescope is on the wrong side targetHA was %f", targetHA) ;
+
+		return ;
+	    }
+#ifdef INDI_DEBUG
+	    IDLog("Synchronization successful >%s<\n", syncString);
+#endif
+	    EquatorialCoordsWNP.s = IPS_OK; /* see above for dome controller dc */
+	    IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful, EquatorialCoordsWNP.s = IPS_OK after SYNC");
+	    break;
+    }
+   return ;
+}
+
+// ToDo Not yet used
+void LX200AstroPhysics::handleAZCoordSet()
+{
+    int  err;
+    char AZStr[32], AltStr[32];
+
+    switch (getOnSwitch(&OnCoordSetSP))
+    {
+	// Slew
+	case LX200_TRACK:
+	    lastSet = LX200_TRACK;
+	    if (HorizontalCoordsWNP.s == IPS_BUSY)
+	    {
+#ifdef INDI_DEBUG
+		IDLog("Aboring Slew\n");
+#endif
+		// ToDo
+		abortSlew(fd);
+		AbortSlewSP.s = IPS_OK;
+		IDSetSwitch(&AbortSlewSP, NULL);
+		// sleep for 100 mseconds
+		usleep(100000);
+	    }
+
+	    if ((err = Slew(fd)))
+	    {
+		slewError(err);
+		//ToDo handle it
+
+		return ;
+	    }
+
+	    HorizontalCoordsWNP.s = IPS_BUSY;
+	    fs_sexa(AZStr, targetAZ, 2, 3600);
+	    fs_sexa(AltStr, targetALT, 2, 3600);
+	    IDSetNumber(&HorizontalCoordsWNP, "Slewing to AZ %s - Alt %s", AZStr, AltStr);
+#ifdef INDI_DEBUG
+	    IDLog("Slewing to AZ %s - Alt %s\n", AZStr, AltStr);
+#endif
+	    break;
+
+	    // Sync
+	    /* ToDo DO SYNC */
+	case LX200_SYNC:
+	    IDMessage( myapdev, "Sync not supported in ALT/AZ mode") ;
+
+	    break;
+    }
+}
+/*********Library Section**************/
+/*********Library Section**************/
+/*********Library Section**************/
+/*********Library Section**************/
+
+double LDRAtoHA( double RA, double longitude)
+{
+#ifdef HAVE_NOVA_H
+    double HA ;
+    double JD ;
+    double theta_0= 0. ;
+    JD=  ln_get_julian_from_sys() ;
+
+//    #ifdef INDI_DEBUG
+//    IDLog("LDRAtoHA: JD %f\n", JD);
+//    #endif
+
+    theta_0= 15. * ln_get_mean_sidereal_time( JD) ;
+//    #ifdef INDI_DEBUG
+//    IDLog("LDRAtoHA:1 theta_0 %f\n", theta_0);
+//    #endif
+    theta_0= fmod( theta_0, 360.) ;
+
+    theta_0=  theta_0 /180. * M_PI ;
+
+    HA =  fmod(theta_0 - longitude - RA,  2. * M_PI) ;
+
+    if( HA < 0.)
+    {
+	HA += 2. * M_PI ;
+    }
+    return HA ;
+#else
+    IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ;
+    return 0 ;
+#endif
+
+} 
+// Transformation from apparent to various coordinate systems 
+int LDAppToX( int trans_to, double *star_cat, double tjd, double *loc, double *hxt, double *star_trans)
+{
+#if defined HAVE_NOVASCC_H
+    short int error = 0;
+
+/* 'deltat' is the difference in time scales, TT - UT1. */
+
+    double deltat = 60.0;
+    double gst ;
+
+/* Set x,y in case where sub arcsec precission is required */
+
+    double x=0. ;
+    double y=0. ;
+    short int ref_option ;
+
+
+    double ra_ar, dec_ar;            /* apparent and refracted EQ coordinate system */
+    double az_ar, zd_ar ;    /* apparent and refracted, AltAz coordinate system */
+    double ra_art, dec_art ; /* apparent, refracted and telescope EQ coordinate system */
+
+    double ha_ar ;
+    double ha_art ;
+
+    cat_entry star   = {"FK5", "NONAME", 0, star_cat[0], star_cat[1], 0., 0., 0., 0.};
+
+    site_info geo_loc= {loc[0], loc[1], loc[2], loc[3], loc[4]} ;
+
+    /* A structure containing the body designation for Earth.*/
+
+    body earth ;
+
+    /* Set up the structure containing the body designation for Earth. */
+
+    if ((error = set_body (0,3,"Earth", &earth)))
+    {
+	IDMessage( myapdev, "LDAppToX: Error %d from set_body.\n", error);
+        return -1;
+    }
+    switch (trans_to)
+    {
+        case ATA:  /* identity */
+
+            star_trans[0]= star.ra ;
+            star_trans[1]= star.dec ;
+            break ;
+
+        case ATR: /* T4, apparent to refracted */
+
+/* Alt Azimut refraction */
+
+            ref_option= 2 ;
+
+/* Set x,y in case where sub arcsec precission is required */
+
+            equ2hor(tjd, deltat, x, y, &geo_loc, star.ra, star.dec, ref_option, &zd_ar, &az_ar, &ra_ar, &dec_ar) ;
+
+            if(ra_ar <0.)
+            {
+                ra_ar += 24. ;
+            }
+
+            star_trans[0]= ra_ar ;
+            star_trans[1]= dec_ar ;
+
+            break ;
+
+        case ARTT: /* T4, apparent, refracted to telescope */
+
+/* Alt Azimut refraction */
+
+            ref_option= 2 ;
+
+/* Set x,y in case where sub arcsec precission is required */
+
+            equ2hor(tjd, deltat, x, y, &geo_loc, star.ra, star.dec, ref_option, &zd_ar, &az_ar, &ra_ar, &dec_ar) ;
+
+/* Calculate the apparent refracted hour angle  */
+
+            ha_ar= (gst + geo_loc.longitude/180. * 12. - ra_ar) ;
+
+            if( ha_ar < 0.)
+            {
+                ha_ar += 24. ;
+            }
+/* Equatorial system of the telescope, these are ra_art,  dec_art needed for the setting */
+/* To be defined: sign of rotation   theta= -7.5 ; */
+/* The values of hxt are defined in the local hour system, ha [hour]*/
+
+            if(( error= LDEqToEqT( ha_ar, dec_ar, hxt, &ha_art, &dec_art)) != 0)
+            {
+                IDMessage( myapdev, "LDAppToX: \nError in calculation\n\n");
+                return -1 ;
+            }
+            ra_art = -ha_art + gst  + geo_loc.longitude/180. * 12. ;
+
+            if(ra_art <0.)
+            {
+                ra_art += 24. ;
+            }
+
+            star_trans[0]= ra_art ;
+            star_trans[1]= dec_art ;
+
+            break ;
+        case ARTTO: /* T5, apparent, refracted, telescope to observed*/
+            IDMessage( myapdev, "LDAppToX: Not yet implemented, exiting...\n") ;
+            return -1;
+            break ;
+        default:
+            IDMessage(myapdev, "LDAppToX: No default, exiting\n") ;
+            return -1;
+    }
+    return 0;
+#elif defined HAVE_NOVA_H
+    IDMessage( myapdev, "Only identity transformation is supported without HAVE_NOVASCC_H") ;
+    star_trans[0]= star_cat[0];
+    star_trans[1]= star_cat[1];
+    return 0 ;
+#else
+    IDMessage( myapdev, "Install libnova to use this feature") ; // we never get here
+    return 0 ;
+#endif
+}
+
+// Trans form to the ideal telescope coordinate system (no mount defects)
+int LDEqToEqT( double ra_h, double dec_d, double *hxt, double *rat_h, double *dect_d)
+{
+    int res ;
+    int i,j;
+    double ra = ra_h / 12. * M_PI ; /* novas-c unit is hour */
+    double dec= dec_d/180. * M_PI ;
+
+    double theta= hxt[0]/180. * M_PI ;
+    double gamma= hxt[1]/180. * M_PI ;
+
+    double unit_vector_in[3]= {cos(dec)*cos(ra), cos(dec)*sin(ra), sin(dec)} ;
+    double unit_vector_rot[3]= {0.,0.,0.} ;
+    double unit_vector_tmp[3]= {0.,0.,0.} ;
+    double rat  ;
+    double dect  ;
+
+    /* theta rotation around polar axis, gamma around y axis */
+    double rotation[3][3]=
+        {
+            {cos(gamma)*cos(theta),-(cos(gamma)*sin(theta)),-sin(gamma)},
+            {sin(theta),cos(theta),0},
+            {cos(theta)*sin(gamma),-(sin(gamma)*sin(theta)), cos(gamma)}
+        } ;
+
+
+    /* minus theta rotation around telescope polar axis */
+
+    /* Despite the above matrix is correct, no body has a telescope */
+    /* with fixed setting circles in RA - or a telescope is usually */
+    /* calibrated in RA/HA by choosing one star. The matrix below */
+    /* takes that into account */
+
+    double rotation_minus_theta[3][3]=
+            {
+                { cos(theta), sin(theta), 0.},
+                {-sin(theta), cos(theta), 0.},
+                {         0.,         0., 1.}
+            } ;
+
+    unit_vector_in[0]= cos(dec)*cos(ra) ;
+    unit_vector_in[1]= cos(dec)*sin(ra) ;
+    unit_vector_in[2]= sin(dec) ;
+
+    if( gamma < 0 )
+    {
+        IDMessage(myapdev, "LDEqToEqT: gamma is the distance from the celestial pole and always positive\n") ;
+        return -1 ;
+    }
+    for( i=0; i < 3 ; i++)
+    {
+        for( j=0; j < 3 ; j++)
+        {
+            unit_vector_tmp[i] += rotation[i][j] *  unit_vector_in[j] ;
+        }
+    }
+
+    for( i=0; i < 3 ; i++)
+    {
+        for( j=0; j < 3 ; j++)
+        {
+            unit_vector_rot[i] += rotation_minus_theta[i][j] *  unit_vector_tmp[j] ;
+        }
+    }
+
+    if(( res= LDCartToSph( unit_vector_rot, &rat, &dect))!= 0)
+    {
+        return -1 ;
+    }
+    else
+    {
+        *rat_h = rat /M_PI * 12. ;
+        *dect_d= dect/M_PI * 180. ;
+        return 0 ;
+    }
+}
+int LDCartToSph( double *vec, double *ra, double *dec)
+{
+
+    if( vec[0] !=0.)
+    {
+        *ra = atan2( vec[1], vec[0]) ;
+    }
+    else
+    {
+        return -1 ;
+    }
+    *dec= asin( vec[2]) ;
+    return 0 ;
+}
Index: /BAORadio/libindi/v1/drivers/telescope/lx200ap.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200ap.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200ap.h	(revision 500)
@@ -0,0 +1,72 @@
+/*
+    LX200 Astro-Physics INDI driver
+
+    Copyright (C) 2007 Markus Wildi
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef LX200ASTROPHYSICS_H
+#define LX200ASTROPHYSICS_H
+
+#include "lx200generic.h"
+/* thisDevice is not defined with the global section property definitions.*/
+/* So I use this macro throught the lx200ap.cpp */
+/* even one can use thisDevice e.g. in function call like IDMessage( thisDevice,...)*/
+/* That may collide with what is defined in lx200generic.cpp */
+#define myapdev "LX200 Astro-Physics"
+
+#define DOMECONTROL 0
+#define NOTDOMECONTROL  1
+
+#define SYNCCM  0
+#define SYNCCMR 1
+
+#define NOTESTABLISHED 0 
+#define    ESTABLISHED 1 
+#define MOUNTNOTINITIALIZED 0 
+#define MOUNTINITIALIZED 1 
+
+class LX200AstroPhysics : public LX200Generic
+{
+ public:
+  LX200AstroPhysics();
+  ~LX200AstroPhysics() {}
+
+ void ISGetProperties (const char *dev);
+ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ void ISSnoopDevice (XMLEle *root) ;
+ void ISPoll ();
+ int  setBasicDataPart0();
+ int  setBasicDataPart1();
+ void connectTelescope();
+ void setupTelescope();
+ void handleAltAzSlew();
+ void handleAZCoordSet() ;
+ void handleEqCoordSet() ;
+ void ISInit() ;
+ bool isMountInit(void) ;
+ private:
+
+ enum LX200_STATUS { LX200_SLEW, LX200_TRACK, LX200_SYNC, LX200_PARK };
+
+};
+
+void changeLX200AstroPhysicsDeviceName(const char *newName);
+#endif
+ 
Index: /BAORadio/libindi/v1/drivers/telescope/lx200apdriver.c
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200apdriver.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200apdriver.c	(revision 500)
@@ -0,0 +1,555 @@
+#if 0
+    LX200 Astro-Physics Driver
+    Copyright (C) 2007 Markus Wildi
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+/*ToDo: compare the routes with the new ones from lx200driver.c r111 */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "indicom.h"
+#include "indidevapi.h"
+#include "lx200driver.h"
+#include "lx200apdriver.h"
+
+#ifndef _WIN32
+#include <termios.h>
+#endif
+
+#define LX200_TIMEOUT	5		/* FD timeout in seconds */
+int check_lx200ap_connection(int fd)
+{
+
+  int i=0;
+/*  char ack[1] = { (char) 0x06 }; does not work for AP moung */
+  char temp_string[64];
+  int error_type;
+  int nbytes_write=0;
+  int nbytes_read=0;
+
+  #ifdef INDI_DEBUG
+  IDLog("Testing telescope's connection using #:GG#...\n");
+  #endif
+
+  if (fd <= 0)
+  {
+      #ifdef INDI_DEBUG
+      IDLog("check_lx200ap_connection: not a valid file descriptor received\n");
+      #endif
+      return -1;
+  }
+  for (i=0; i < 2; i++)
+  {
+      if ( (error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK)
+      {
+	  #ifdef INDI_DEBUG
+	  IDLog("check_lx200ap_connection: unsuccessful write to telescope, %d\n", nbytes_write);
+          #endif
+
+	  return error_type;
+      }
+      error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read) ;
+      tcflush(fd, TCIFLUSH);
+      if (nbytes_read > 1)
+      {
+	  temp_string[ nbytes_read -1] = '\0';
+	  #ifdef INDI_DEBUG
+	  IDLog("check_lx200ap_connection: received bytes %d, [%s]\n", nbytes_write, temp_string);
+          #endif
+	  return 0;
+      }
+    usleep(50000);
+  }
+  
+  #ifdef INDI_DEBUG
+  IDLog("check_lx200ap_connection: wrote, but nothing received\n");
+  #endif
+  return -1;
+}
+int getAPUTCOffset(int fd, double *value)
+{
+    int error_type;
+    int nbytes_write=0;
+    int nbytes_read=0;
+
+    char temp_string[16];
+
+    if ( (error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK)
+	return error_type;
+
+    if(( error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK)
+    {
+	#ifdef INDI_DEBUG
+	IDLog("getAPUTCOffset: saying good bye %d, %d\n", error_type, nbytes_read);
+        #endif
+
+	return error_type ;
+    }
+    tcflush(fd, TCIFLUSH);
+
+/* Negative offsets, see AP keypad manual p. 77 */
+    if((temp_string[0]== 'A') || ((temp_string[0]== '0')&&(temp_string[1]== '0')) ||(temp_string[0]== '@'))
+    {
+	int i ;
+	for( i=nbytes_read; i > 0; i--)
+	{
+	    temp_string[i]= temp_string[i-1] ; 
+	}
+	temp_string[0] = '-' ;
+	temp_string[nbytes_read + 1] = '\0' ;
+
+	if( temp_string[1]== 'A') 
+	{
+	    temp_string[1]= '0' ;
+	    switch (temp_string[2])
+	    {
+		case '5':
+		    
+		    temp_string[2]= '1' ;
+		    break ;
+		case '4':
+		    
+		    temp_string[2]= '2' ;
+		    break ;
+		case '3':
+		    
+		    temp_string[2]= '3' ;
+		    break ;
+		case '2':
+		    
+		    temp_string[2]= '4' ;
+		    break ;
+		case '1':
+		    
+		    temp_string[2]= '5' ;
+		    break ;
+		default:
+		    #ifdef INDI_DEBUG
+		    IDLog("getAPUTCOffset: string not handled %s\n", temp_string);
+                    #endif
+		    return -1 ;
+		    break ;
+	    }
+	}    
+	else if( temp_string[1]== '0')
+	{
+	    temp_string[1]= '0' ;
+	    temp_string[2]= '6' ;
+                   #ifdef INDI_DEBUG
+	    IDLog("getAPUTCOffset: done here %s\n", temp_string);
+                    #endif
+
+	}
+	else if( temp_string[1]== '@')
+	{
+	    temp_string[1]= '0' ;
+	    switch (temp_string[2])
+	    {
+		case '9':
+		    
+		    temp_string[2]= '7' ;
+		    break ;
+		case '8':
+		    
+		    temp_string[2]= '8' ;
+		    break ;
+		case '7':
+		    
+		    temp_string[2]= '9' ;
+		    break ;
+		case '6':
+		    
+		    temp_string[2]= '0' ;
+		    break ;
+		case '5':
+		    temp_string[1]= '1' ;
+		    temp_string[2]= '1' ;
+		    break ;
+		case '4':
+		    
+		    temp_string[1]= '1' ;
+		    temp_string[2]= '2' ;
+		    break ;
+		default:
+		    #ifdef INDI_DEBUG
+		    IDLog("getAPUTCOffset: string not handled %s\n", temp_string);
+                    #endif
+		    return -1 ;
+		    break;
+	    }    
+	}
+	else
+	{
+	    #ifdef INDI_DEBUG
+	    IDLog("getAPUTCOffset: string not handled %s\n", temp_string);
+            #endif
+	}
+    }
+    else
+    {
+	temp_string[nbytes_read - 1] = '\0' ;
+    }
+/*    #ifdef INDI_DEBUG
+      IDLog("getAPUTCOffset: received string %s\n", temp_string);
+      #endif
+*/
+    if (f_scansexa(temp_string, value))
+    {
+	fprintf(stderr, "getAPUTCOffset: unable to process [%s]\n", temp_string);
+	return -1;
+    }
+    return 0;
+}
+int setAPObjectAZ(int fd, double az)
+{
+    int h, m, s;
+    char temp_string[16];
+
+    getSexComponents(az, &h, &m, &s);
+
+    snprintf(temp_string, sizeof( temp_string ), "#:Sz %03d*%02d:%02d#", h, m, s);
+    #ifdef INDI_DEBUG
+    IDLog("setAPObjectAZ: Set Object AZ String %s\n", temp_string);
+    #endif
+
+    return (setStandardProcedure(fd, temp_string));
+}
+
+/* wildi Valid set Values are positive, add error condition */
+
+int setAPObjectAlt(int fd, double alt)
+{
+    int d, m, s;
+    char temp_string[16];
+    
+    getSexComponents(alt, &d, &m, &s);
+
+    /* case with negative zero */
+    if (!d && alt < 0)
+    {
+	snprintf(temp_string, sizeof( temp_string ), "#:Sa -%02d*%02d:%02d#", d, m, s) ;
+    }
+    else
+    {
+	snprintf(temp_string, sizeof( temp_string ), "#:Sa %+02d*%02d:%02d#", d, m, s) ;
+    }	
+
+    #ifdef INDI_DEBUG
+    IDLog("setAPObjectAlt: Set Object Alt String %s\n", temp_string);
+    #endif
+    return (setStandardProcedure(fd, temp_string));
+}
+int setAPUTCOffset(int fd, double hours)
+{
+    int h, m, s ;
+
+    char temp_string[16];
+/* To avoid the peculiar output format of AP controller, see p. 77 key pad manual */
+    if( hours < 0.)
+    {
+	hours += 24. ;
+    }
+
+    getSexComponents(hours, &h, &m, &s);
+    
+    snprintf(temp_string, sizeof( temp_string ), "#:SG %+03d:%02d:%02d#", h, m, s);
+    #ifdef INDI_DEBUG
+    IDLog("setAPUTCOffset: %s\n", temp_string);
+    #endif
+
+
+    return (setStandardProcedure(fd, temp_string));
+}
+int APSyncCM(int fd, char *matchedObject)
+{
+    int error_type;
+    int nbytes_write=0;
+    int nbytes_read=0;
+
+    #ifdef INDI_DEBUG
+    IDLog("APSyncCM\n");
+    #endif
+    if ( (error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK)
+	return error_type ;
+  
+    if(( error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK)
+	return error_type ;
+   
+    matchedObject[nbytes_read-1] = '\0';
+  
+    /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
+    usleep(10000);
+  
+    tcflush(fd, TCIFLUSH);
+
+    return 0;
+}
+int APSyncCMR(int fd, char *matchedObject)
+{
+    int error_type;
+    int nbytes_write=0;
+    int nbytes_read=0;
+    
+    #ifdef INDI_DEBUG
+    IDLog("APSyncCMR\n");
+    #endif
+    if ( (error_type = tty_write_string(fd, "#:CMR#", &nbytes_write)) != TTY_OK)
+	return error_type;
+ 
+    /* read_ret = portRead(matchedObject, -1, LX200_TIMEOUT); */
+    if(( error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read))  != TTY_OK)
+	return error_type ;
+
+    matchedObject[nbytes_read-1] = '\0';
+  
+    /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
+    usleep(10000);
+  
+    tcflush(fd, TCIFLUSH);
+
+    return 0;
+}
+int selectAPMoveToRate(int fd, int moveToRate)
+{
+    int error_type;
+    int nbytes_write=0;
+
+    switch (moveToRate)
+    {
+	/* 1200x */
+	case 0:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPMoveToRate: Setting move to rate to 1200x.\n");
+	    #endif
+	    if ( (error_type = tty_write_string(fd, "#:RC3#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+    
+	    /* 600x */
+	case 1:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPMoveToRate: Setting move to rate to 600x.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RC2#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+
+	    /* 64x */
+	case 2:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPMoveToRate: Setting move to rate to 64x.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RC1#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+	    /* 12x*/
+	case 3:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPMoveToRate: Setting move to rate to 12x.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RC0#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+
+	default:
+	    return -1;
+	    break;
+   }
+   return 0;
+}
+int selectAPSlewRate(int fd, int slewRate)
+{
+    int error_type;
+    int nbytes_write=0;
+    switch (slewRate)
+    {
+	/* 1200x */
+	case 0:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPSlewRate: Setting slew rate to 1200x.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RS2#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+    
+	    /* 900x */
+	case 1:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPSlewRate: Setting slew rate to 900x.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RS1#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+
+	    /* 600x */
+	case 2:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPSlewRate: Setting slew rate to 600x.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RS0#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+
+	default:
+	    return -1;
+	    break;
+    }
+    return 0;
+}
+int selectAPTrackingMode(int fd, int trackMode)
+{
+    int error_type;
+    int nbytes_write=0;
+
+    switch (trackMode)
+    {
+	/* Lunar */
+	case 0:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPTrackingMode: Setting tracking mode to lunar.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RT0#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+    
+	    /* Solar */
+	case 1:
+            #ifdef INDI_DEBUG
+	    IDLog("selectAPTrackingMode: Setting tracking mode to solar.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RT1#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+
+	    /* Sidereal */
+	case 2:
+            #ifdef INDI_DEBUG
+            IDLog("selectAPTrackingMode: Setting tracking mode to sidereal.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RT2#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+
+	    /* Zero */
+	case 3:
+            #ifdef INDI_DEBUG
+            IDLog("selectAPTrackingMode: Setting tracking mode to zero.\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:RT9#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+ 
+	default:
+	    return -1;
+	    break;
+    }
+    return 0;
+}
+int swapAPButtons(int fd, int currentSwap)
+{
+    int error_type;
+    int nbytes_write=0;
+
+    switch (currentSwap)
+    {
+	case 0:
+            #ifdef INDI_DEBUG
+            IDLog("#:NS#\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:NS#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+	    
+	case 1:
+            #ifdef INDI_DEBUG
+            IDLog("#:EW#\n");
+            #endif
+	    if ( (error_type = tty_write_string(fd, "#:EW#", &nbytes_write)) != TTY_OK)
+		return error_type;
+	    break;
+
+	default:
+	    return -1;
+	    break;
+    }
+    return 0;
+}
+int setAPObjectRA(int fd, double ra)
+{
+/*ToDo AP accepts "#:Sr %02d:%02d:%02d.%1d#"*/
+ int h, m, s;
+ char temp_string[16];
+
+ getSexComponents(ra, &h, &m, &s);
+
+ snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d:%02d#", h, m, s);
+
+ #ifdef INDI_DEBUG
+ IDLog("setAPObjectRA: Set Object RA String %s, %f\n", temp_string, ra);
+ #endif
+ return (setStandardProcedure(fd, temp_string));
+}
+
+int setAPObjectDEC(int fd, double dec)
+{
+  int d, m, s;
+  char temp_string[16];
+
+  getSexComponents(dec, &d, &m, &s);
+  /* case with negative zero */
+  if (!d && dec < 0)
+  {
+      snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d*%02d:%02d#", d, m, s);
+  }
+  else
+  {
+      snprintf(temp_string, sizeof( temp_string ),   "#:Sd %+03d*%02d:%02d#", d, m, s);
+  }
+  #ifdef INDI_DEBUG
+  IDLog("setAPObjectDEC: Set Object DEC String %s\n", temp_string) ;
+  #endif
+  return (setStandardProcedure(fd, temp_string));
+}
+int setAPSiteLongitude(int fd, double Long)
+{
+   int d, m, s;
+   char temp_string[32];
+
+   getSexComponents(Long, &d, &m, &s);
+   snprintf(temp_string, sizeof( temp_string ), "#:Sg %03d*%02d:%02d#", d, m, s);
+   return (setStandardProcedure(fd, temp_string));
+}
+
+int setAPSiteLatitude(int fd, double Lat)
+{
+   int d, m, s;
+   char temp_string[32];
+
+   getSexComponents(Lat, &d, &m, &s);
+   snprintf(temp_string, sizeof( temp_string ), "#:St %+03d*%02d:%02d#", d, m, s);
+   return (setStandardProcedure(fd, temp_string));
+}
Index: /BAORadio/libindi/v1/drivers/telescope/lx200apdriver.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200apdriver.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200apdriver.h	(revision 500)
@@ -0,0 +1,58 @@
+/*
+    LX200 AP Driver
+    Copyright (C) 2007 Markus Wildi
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef LX200APDRIVER_H
+#define LX200APDRIVER_H
+#endif
+
+#define getAPDeclinationAxis(fd, x)           getCommandString(fd, x, "#:pS#")
+#define getAPVersionNumber(fd, x)             getCommandString(fd, x, "#:V#")
+#define setAPPark( fd)                        write(fd, "#:KA", 4)
+#define setAPUnPark( fd)                      write(fd, "#:PO", 4)
+#define setAPLongFormat( fd)                  write(fd, "#:U", 3)
+#define setAPClearBuffer( fd)                 write(fd, "#", 1) /* AP key pad manual startup sequence */
+#define setAPBackLashCompensation(fd, x,y,z)  setCommandXYZ(fd, x,y,z, "#:Br")
+#define setAPMotionStop( fd)                  write(fd, "#:Q", 3)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int check_lx200ap_connection(int fd) ;
+int initializeAPmount(int fd) ;
+int getAPUTCOffset (int fd, double *value) ;
+int setAPObjectAZ(int fd, double az);
+int setAPObjectAlt(int fd, double alt);
+int setAPUTCOffset(int fd, double hours) ;
+int setAPSlewMode(int fd, int slewMode) ;
+int APSyncCM(int fd, char *matchedObject) ;
+int APSyncCMR(int fd, char *matchedObject) ;
+int selectAPMoveToRate(int fd, int moveToRate) ;
+int selectAPSlewRate(int fd, int slewRate) ;
+int selectAPTrackingMode(int fd, int trackMode) ;
+int swapAPButtons(int fd, int currentSwap) ;
+int setAPObjectRA(int fd, double ra) ;
+int setAPObjectDEC(int fd, double dec) ;
+int setAPSiteLongitude(int fd, double Long) ;
+int setAPSiteLatitude(int fd, double Lat) ;
+
+#ifdef __cplusplus
+}
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/lx200aplib.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200aplib.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200aplib.h	(revision 500)
@@ -0,0 +1,37 @@
+/*
+    LX200 AP Driver
+    Copyright (C) 2007 Markus Wildi
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <config.h>
+
+#include <math.h>
+
+#ifdef HAVE_NOVA_H
+#include <libnova.h>
+#endif
+
+#define ATA    0
+#define ATR    1
+#define ARTT   2
+#define ARTTO  3 /* not yet there, requires a pointing model */
+
+double LDRAtoHA( double RA, double longitude) ;
+int LDEqToEqT( double ra_h, double dec_d, double *hxt, double *rat_h, double *dect_d);
+int LDCartToSph( double *vec, double *ra, double *dec) ;
+int LDAppToX( int trans_to, double *star_cat, double tjd, double *loc, double *hxt, double *star_trans) ;
Index: /BAORadio/libindi/v1/drivers/telescope/lx200autostar.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200autostar.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200autostar.cpp	(revision 500)
@@ -0,0 +1,262 @@
+/*
+    LX200 Autostar
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "lx200autostar.h"
+#include "lx200driver.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define BASIC_GROUP   "Main Control"
+#define FIRMWARE_GROUP "Firmware data"
+#define FOCUS_GROUP   "Focus Control"
+
+
+extern LX200Generic *telescope;
+extern int MaxReticleFlashRate;
+extern ITextVectorProperty TimeTP;
+extern INumberVectorProperty SDTimeNP;
+extern INumberVectorProperty EquatorialCoordsWNP;
+extern INumberVectorProperty EquatorialCoordsRNP;
+extern INumberVectorProperty FocusTimerNP;
+extern ISwitchVectorProperty ConnectSP;
+extern ISwitchVectorProperty FocusMotionSP;
+extern ISwitchVectorProperty AbortSlewSP;
+extern ISwitchVectorProperty MovementNSSP;
+extern ISwitchVectorProperty MovementWESP;
+
+
+static IText   VersionT[] ={{ "Date", "", 0, 0, 0, 0} ,
+			   { "Time", "", 0, 0, 0, 0} ,
+			   { "Number", "", 0, 0, 0 ,0} ,
+			   { "Full", "", 0, 0, 0, 0} ,
+			   { "Name", "" ,0 ,0 ,0 ,0}};
+
+static ITextVectorProperty VersionInfo = {mydev, "Firmware Info", "", FIRMWARE_GROUP, IP_RO, 0, IPS_IDLE, VersionT, NARRAY(VersionT), "" ,0};
+
+// Focus Control
+static INumber	FocusSpeedN[]	 = {{"SPEED", "Speed", "%0.f", 0.0, 4.0, 1.0, 0.0, 0, 0, 0}};
+static INumberVectorProperty	FocusSpeedNP  = {mydev, "FOCUS_SPEED", "Speed", FOCUS_GROUP, IP_RW, 0, IPS_IDLE, FocusSpeedN, NARRAY(FocusSpeedN), "", 0};
+
+/********************************************
+ Property: Park telescope to HOME
+*********************************************/
+static ISwitch ParkS[]		 	= { {"PARK", "Park", ISS_OFF, 0, 0} };
+ISwitchVectorProperty ParkSP		= {mydev, "TELESCOPE_PARK", "Park Scope", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, ParkS, NARRAY(ParkS), "", 0 };
+
+
+void changeLX200AutostarDeviceName(const char *newName)
+{
+  strcpy(VersionInfo.device, newName);
+  strcpy(FocusSpeedNP.device, newName);
+  strcpy(ParkSP.device, newName);
+}
+
+LX200Autostar::LX200Autostar() : LX200Generic()
+{
+
+}
+
+void LX200Autostar::ISGetProperties (const char *dev)
+{
+
+if (dev && strcmp (thisDevice, dev))
+    return;
+
+    LX200Generic::ISGetProperties(dev);
+
+    IDDefSwitch (&ParkSP, NULL);
+    IDDefText   (&VersionInfo, NULL);
+    IDDefNumber (&FocusSpeedNP, NULL);
+
+    // For Autostar, we have a different focus speed method
+    // Therefore, we don't need the classical one
+    IDDelete(thisDevice, "FOCUS_MODE", NULL);
+
+}
+
+void LX200Autostar::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+        // ignore if not ours //
+	if (strcmp (dev, thisDevice))
+	    return;
+
+	// suppress warning
+	n=n;
+
+  LX200Generic::ISNewText (dev, name, texts, names, n);
+
+}
+
+
+void LX200Autostar::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+        // ignore if not ours
+	if (strcmp (dev, thisDevice))
+	    return;
+
+        // Focus speed
+	if (!strcmp (name, FocusSpeedNP.name))
+	{
+	  if (checkPower(&FocusSpeedNP))
+	   return;
+
+	  if (IUUpdateNumber(&FocusSpeedNP, values, names, n) < 0)
+		return;
+
+	  setGPSFocuserSpeed(fd,  ( (int) FocusSpeedN[0].value));
+	  FocusSpeedNP.s = IPS_OK;
+	  IDSetNumber(&FocusSpeedNP, NULL);
+	  return;
+	}
+
+    LX200Generic::ISNewNumber (dev, name, values, names, n);
+}
+
+ void LX200Autostar::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+ {
+   int index=0, err=0;
+ 
+   if (!strcmp(name, ParkSP.name))
+   {
+	  if (checkPower(&ParkSP))
+	    return;
+           
+   	  if (EquatorialCoordsWNP.s == IPS_BUSY)
+	  {
+	     if (abortSlew(fd) < 0)
+	     {
+		AbortSlewSP.s = IPS_ALERT;
+		IDSetSwitch(&AbortSlewSP, NULL);
+                slewError(err);
+		return;
+	     }
+
+	     AbortSlewSP.s = IPS_OK;
+	     EquatorialCoordsWNP.s       = IPS_IDLE;
+             IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+	     IDSetNumber(&EquatorialCoordsWNP, NULL);
+
+	     if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
+	     {
+		MovementNSSP.s  = MovementWESP.s =  IPS_IDLE; 
+		EquatorialCoordsWNP.s       = IPS_IDLE;
+		IUResetSwitch(&MovementNSSP);
+		IUResetSwitch(&MovementWESP);
+		IUResetSwitch(&AbortSlewSP);
+
+		IDSetSwitch(&MovementNSSP, NULL);
+		IDSetSwitch(&MovementWESP, NULL);
+	      }
+
+	     // sleep for 200 mseconds
+	     usleep(200000);
+	  }
+
+	  if (slewToPark(fd) < 0)
+	  {
+		ParkSP.s = IPS_ALERT;
+		IDSetSwitch(&ParkSP, "Parking Failed.");
+		return;
+	  }
+
+	  ParkSP.s = IPS_OK;
+	  ConnectSP.s   = IPS_IDLE;
+	  ConnectSP.sp[0].s = ISS_OFF;
+	  ConnectSP.sp[1].s = ISS_ON;
+	  tty_disconnect(fd);
+	  IDSetSwitch(&ParkSP, "The telescope is slewing to park position. Turn off the telescope after park is complete. Disconnecting...");
+	  IDSetSwitch(&ConnectSP, NULL);
+	  return;
+    }
+
+        // Focus Motion
+	if (!strcmp (name, FocusMotionSP.name))
+	{
+	  if (checkPower(&FocusMotionSP))
+	   return;
+
+	  IUResetSwitch(&FocusMotionSP);
+	  
+	  // If speed is "halt"
+	  if (FocusSpeedN[0].value == 0)
+	  {
+	    FocusMotionSP.s = IPS_IDLE;
+	    IDSetSwitch(&FocusMotionSP, NULL);
+	    return;
+	  }
+	  
+	  IUUpdateSwitch(&FocusMotionSP, states, names, n);
+	  index = getOnSwitch(&FocusMotionSP);
+	  
+	  
+	  if ( ( err = setFocuserMotion(fd, index) < 0) )
+	  {
+	     handleError(&FocusMotionSP, err, "Setting focuser speed");
+             return;
+	  }
+	  
+	  FocusMotionSP.s = IPS_BUSY;
+	  
+	  // with a timer 
+	if (FocusTimerNP.np[0].value > 0)  
+	{
+	     FocusTimerNP.s  = IPS_BUSY;
+	     IDLog("Starting Focus Timer BUSY\n");
+	     IEAddTimer(50, LX200Generic::updateFocusTimer, this);
+	}
+	  
+	  IDSetSwitch(&FocusMotionSP, NULL);
+	  return;
+	}
+
+   LX200Generic::ISNewSwitch (dev, name, states, names,  n);
+
+ }
+
+ void LX200Autostar::ISPoll ()
+ {
+
+      LX200Generic::ISPoll();
+
+ }
+
+ void LX200Autostar::getBasicData()
+ {
+
+   VersionInfo.tp[0].text = new char[64];
+   getVersionDate(fd, VersionInfo.tp[0].text);
+   VersionInfo.tp[1].text = new char[64];
+   getVersionTime(fd, VersionInfo.tp[1].text);
+   VersionInfo.tp[2].text = new char[64];
+   getVersionNumber(fd, VersionInfo.tp[2].text);
+   VersionInfo.tp[3].text = new char[128];
+   getFullVersion(fd, VersionInfo.tp[3].text);
+   VersionInfo.tp[4].text = new char[128];
+   getProductName(fd, VersionInfo.tp[4].text);
+
+   IDSetText(&VersionInfo, NULL);
+   
+   // process parent
+   LX200Generic::getBasicData();
+
+ }
Index: /BAORadio/libindi/v1/drivers/telescope/lx200autostar.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200autostar.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200autostar.h	(revision 500)
@@ -0,0 +1,45 @@
+/*
+    LX200 Autostar
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef LX200AUTOSTAR_H
+#define LX200AUTOSTAR_H
+
+#include "lx200generic.h"
+
+class LX200Autostar : public LX200Generic
+{
+ public:
+  LX200Autostar();
+  ~LX200Autostar() {}
+
+ void ISGetProperties (const char *dev);
+ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ void ISPoll ();
+ void getBasicData();
+
+
+};
+
+void changeLX200AutostarDeviceName(const char *newName);
+
+#endif
+ 
Index: /BAORadio/libindi/v1/drivers/telescope/lx200basic.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200basic.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200basic.cpp	(revision 500)
@@ -0,0 +1,902 @@
+#if 0
+    LX200 Basic Driver
+    Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <memory>
+
+#include <config.h>
+
+/* INDI Common Library Routines */
+#include "indicom.h"
+
+/* LX200 Command Set */
+#include "lx200driver.h"
+
+/* Our driver header */
+#include "lx200basic.h"
+
+using namespace std;
+
+/* Our telescope auto pointer */
+auto_ptr<LX200Basic> telescope(0);
+
+const int POLLMS = 1000;				// Period of update, 1 second.
+const char *mydev = "LX200 Basic";			// Name of our device.
+
+const char *BASIC_GROUP    = "Main Control";		// Main Group
+const char *OPTIONS_GROUP  = "Options";			// Options Group
+
+/* Handy Macros */
+#define currentRA	EquatorialCoordsRN[0].value
+#define currentDEC	EquatorialCoordsRN[1].value
+#define targetRA	EquatorialCoordsWN[0].value
+#define targetDEC	EquatorialCoordsWN[1].value
+
+static void ISPoll(void *);
+static void retry_connection(void *);
+
+/**************************************************************************************
+** Send client definitions of all properties.
+***************************************************************************************/
+void ISInit()
+{
+ static int isInit=0;
+
+ if (isInit)
+  return;
+
+ if (telescope.get() == 0) telescope.reset(new LX200Basic());
+
+ isInit = 1;
+ 
+ IEAddTimer (POLLMS, ISPoll, NULL);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void ISGetProperties (const char *dev)
+{
+ ISInit(); 
+ telescope->ISGetProperties(dev);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+ ISInit();
+ telescope->ISNewSwitch(dev, name, states, names, n);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+ ISInit();
+ telescope->ISNewText(dev, name, texts, names, n);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+ ISInit();
+ telescope->ISNewNumber(dev, name, values, names, n);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void ISPoll (void *p)
+{
+ INDI_UNUSED(p);
+
+ telescope->ISPoll(); 
+ IEAddTimer (POLLMS, ISPoll, NULL);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+/**************************************************************************************
+** LX200 Basic constructor
+***************************************************************************************/
+LX200Basic::LX200Basic()
+{
+   init_properties();
+
+   lastSet        = -1;
+   fd             = -1;
+   simulation     = false;
+   lastRA 	  = 0;
+   lastDEC	  = 0;
+   currentSet     = 0;
+
+   IDLog("Initilizing from LX200 Basic device...\n");
+   IDLog("Driver Version: 2007-09-28\n");
+ 
+   //enableSimulation(true);  
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+LX200Basic::~LX200Basic()
+{
+
+}
+
+/**************************************************************************************
+** Initialize all properties & set default values.
+***************************************************************************************/
+void LX200Basic::init_properties()
+{
+    // Connection
+    IUFillSwitch(&ConnectS[0], "CONNECT", "Connect", ISS_OFF);
+    IUFillSwitch(&ConnectS[1], "DISCONNECT", "Disconnect", ISS_ON);
+    IUFillSwitchVector(&ConnectSP, ConnectS, NARRAY(ConnectS), mydev, "CONNECTION", "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+
+    // Coord Set
+    IUFillSwitch(&OnCoordSetS[0], "SLEW", "Slew", ISS_ON);
+    IUFillSwitch(&OnCoordSetS[1], "TRACK", "Track", ISS_OFF);
+    IUFillSwitch(&OnCoordSetS[2], "SYNC", "Sync", ISS_OFF);
+    IUFillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+
+    // Abort
+    IUFillSwitch(&AbortSlewS[0], "ABORT", "Abort", ISS_OFF);
+    IUFillSwitchVector(&AbortSlewSP, AbortSlewS, NARRAY(AbortSlewS), mydev, "ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
+
+    // Port
+    IUFillText(&PortT[0], "PORT", "Port", "/dev/ttyS0");
+    IUFillTextVector(&PortTP, PortT, NARRAY(PortT), mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
+
+    // Object Name
+    IUFillText(&ObjectT[0], "OBJECT_NAME", "Name", "--");
+    IUFillTextVector(&ObjectTP, ObjectT, NARRAY(ObjectT), mydev, "OBJECT_INFO", "Object", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
+
+    // Equatorial Coords - SET
+    IUFillNumber(&EquatorialCoordsWN[0], "RA", "RA  H:M:S", "%10.6m",  0., 24., 0., 0.);
+    IUFillNumber(&EquatorialCoordsWN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.);
+    IUFillNumberVector(&EquatorialCoordsWNP, EquatorialCoordsWN, NARRAY(EquatorialCoordsWN), mydev, "EQUATORIAL_EOD_COORD_REQUEST" , "Equatorial JNow", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
+
+    // Equatorial Coords - READ
+    IUFillNumber(&EquatorialCoordsRN[0], "RA", "RA  H:M:S", "%10.6m",  0., 24., 0., 0.);
+    IUFillNumber(&EquatorialCoordsRN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.);
+    IUFillNumberVector(&EquatorialCoordsRNP, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), mydev, "EQUATORIAL_EOD_COORD" , "Equatorial JNow", BASIC_GROUP, IP_RO, 0, IPS_IDLE);
+
+    // Slew threshold
+    IUFillNumber(&SlewAccuracyN[0], "SlewRA",  "RA (arcmin)", "%10.6m",  0., 60., 1., 3.0);
+    IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0);
+    IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), mydev, "Slew Accuracy", "", OPTIONS_GROUP, IP_RW, 0, IPS_IDLE);
+
+    // Track threshold
+    IUFillNumber(&TrackAccuracyN[0], "TrackRA", "RA (arcmin)", "%10.6m",  0., 60., 1., 3.0);
+    IUFillNumber(&TrackAccuracyN[1], "TrackDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0);
+    IUFillNumberVector(&TrackAccuracyNP, TrackAccuracyN, NARRAY(TrackAccuracyN), mydev, "Tracking Accuracy", "", OPTIONS_GROUP, IP_RW, 0, IPS_IDLE);
+}
+
+/**************************************************************************************
+** Define LX200 Basic properties to clients.
+***************************************************************************************/
+void LX200Basic::ISGetProperties(const char *dev)
+{
+
+ if (dev && strcmp (mydev, dev))
+    return;
+
+  // Main Control
+  IDDefSwitch(&ConnectSP, NULL);
+  IDDefText(&PortTP, NULL);
+  IDDefText(&ObjectTP, NULL);
+  IDDefNumber(&EquatorialCoordsWNP, NULL);
+  IDDefNumber(&EquatorialCoordsRNP, NULL);
+  IDDefSwitch(&OnCoordSetSP, NULL);
+  IDDefSwitch(&AbortSlewSP, NULL);
+
+  // Options
+  IDDefNumber(&SlewAccuracyNP, NULL);
+  IDDefNumber(&TrackAccuracyNP, NULL);
+  
+}
+
+/**************************************************************************************
+** Process Text properties
+***************************************************************************************/
+void LX200Basic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	// Ignore if not ours 
+	if (strcmp (dev, mydev))
+	    return;
+
+	// ===================================
+	// Port Name
+	// ===================================
+	if (!strcmp(name, PortTP.name) )
+	{
+	  if (IUUpdateText(&PortTP, texts, names, n) < 0)
+		return;
+
+	  PortTP.s = IPS_OK;
+	  IDSetText (&PortTP, NULL);
+	  return;
+	}
+
+	if (is_connected() == false)
+        {
+		IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands.");
+		reset_all_properties();
+		return;
+	}
+
+       // ===================================
+       // Object Name
+       // ===================================
+       if (!strcmp (name, ObjectTP.name))
+       {
+
+	  if (IUUpdateText(&ObjectTP, texts, names, n) < 0)
+		return;
+
+          ObjectTP.s = IPS_OK;
+          IDSetText(&ObjectTP, NULL);
+          return;
+       }
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+	
+	// Ignore if not ours
+	if (strcmp (dev, mydev))
+	    return;
+
+	if (is_connected() == false)
+        {
+		IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands.");
+		reset_all_properties();
+		return;
+	}
+
+	// ===================================
+        // Equatorial Coords
+	// ===================================
+	if (!strcmp (name, EquatorialCoordsWNP.name))
+	{
+	  int i=0, nset=0, error_code=0;
+	  double newRA =0, newDEC =0;
+
+	    for (nset = i = 0; i < n; i++)
+	    {
+		INumber *eqp = IUFindNumber (&EquatorialCoordsWNP, names[i]);
+		if (eqp == &EquatorialCoordsWN[0])
+		{
+                    newRA = values[i];
+		    nset += newRA >= 0 && newRA <= 24.0;
+		} else if (eqp == &EquatorialCoordsWN[1])
+		{
+		    newDEC = values[i];
+		    nset += newDEC >= -90.0 && newDEC <= 90.0;
+		}
+	    }
+
+	  if (nset == 2)
+	  {
+	   char RAStr[32], DecStr[32];
+
+	   fs_sexa(RAStr, newRA, 2, 3600);
+	   fs_sexa(DecStr, newDEC, 2, 3600);
+	  
+           #ifdef INDI_DEBUG
+	   IDLog("We received JNow RA %g - DEC %g\n", newRA, newDEC);
+	   IDLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr);
+           #endif
+	   
+	   if ( (error_code = setObjectRA(fd, newRA)) < 0 || ( error_code = setObjectDEC(fd, newDEC)) < 0)
+	   {
+	     handle_error(&EquatorialCoordsWNP, error_code, "Setting RA/DEC");
+	     return;
+	   } 
+	   
+	   targetRA  = newRA;
+	   targetDEC = newDEC;
+	   
+	   if (process_coords() == false)
+	   {
+	     EquatorialCoordsWNP.s = IPS_ALERT;
+	     IDSetNumber(&EquatorialCoordsWNP, NULL);
+	     
+	   }
+	} // end nset
+	else
+	{
+		EquatorialCoordsWNP.s = IPS_ALERT;
+		IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid");
+	}
+
+	    return;
+     } /* end EquatorialCoordsWNP */
+
+	// ===================================
+        // Update tracking precision limits
+	// ===================================
+	if (!strcmp (name, TrackAccuracyNP.name))
+	{
+		if (IUUpdateNumber(&TrackAccuracyNP, values, names, n) < 0)
+			return;
+
+		TrackAccuracyNP.s = IPS_OK;
+
+		if (TrackAccuracyN[0].value < 3 || TrackAccuracyN[1].value < 3)
+			IDSetNumber(&TrackAccuracyNP, "Warning: Setting the tracking accuracy too low may result in a dead lock");
+		else
+			IDSetNumber(&TrackAccuracyNP, NULL);
+		return;
+	}
+
+	// ===================================
+        // Update slew precision limit
+	// ===================================
+	if (!strcmp(name, SlewAccuracyNP.name))
+	{
+		if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0)
+			return;
+		
+		SlewAccuracyNP.s = IPS_OK;
+
+		if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3)
+			IDSetNumber(&TrackAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock");
+
+		IDSetNumber(&SlewAccuracyNP, NULL);
+		return;
+		
+
+	}
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	// ignore if not ours //
+	if (strcmp (mydev, dev))
+	    return;
+
+	// ===================================
+        // Connect Switch
+	// ===================================
+	if (!strcmp (name, ConnectSP.name))
+	{
+	    if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0)
+		return;
+
+   	    connect_telescope();
+	    return;
+	}
+
+	if (is_connected() == false)
+        {
+		IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands.");
+		reset_all_properties();
+		return;
+	}
+
+	// ===================================
+        // Coordinate Set
+	// ===================================
+	if (!strcmp(name, OnCoordSetSP.name))
+	{
+	   if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0)
+		return;
+
+	  currentSet = get_switch_index(&OnCoordSetSP);
+	  OnCoordSetSP.s = IPS_OK;
+	  IDSetSwitch(&OnCoordSetSP, NULL);
+	}
+	  
+	// ===================================
+        // Abort slew
+	// ===================================
+	if (!strcmp (name, AbortSlewSP.name))
+	{
+
+	  IUResetSwitch(&AbortSlewSP);
+	  abortSlew(fd);
+
+	    if (EquatorialCoordsWNP.s == IPS_BUSY)
+	    {
+		AbortSlewSP.s = IPS_OK;
+		EquatorialCoordsWNP.s       = IPS_IDLE;
+                EquatorialCoordsRNP.s       = IPS_IDLE;
+		IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+		IDSetNumber(&EquatorialCoordsWNP, NULL);
+		IDSetNumber(&EquatorialCoordsRNP, NULL);
+            }
+
+	    return;
+	}
+
+}
+
+/**************************************************************************************
+** Retry connecting to the telescope on error. Give up if there is no hope.
+***************************************************************************************/
+void LX200Basic::handle_error(INumberVectorProperty *nvp, int err, const char *msg)
+{
+  
+  nvp->s = IPS_ALERT;
+  
+  /* First check to see if the telescope is connected */
+    if (check_lx200_connection(fd))
+    {
+      /* The telescope is off locally */
+      ConnectS[0].s = ISS_OFF;
+      ConnectS[1].s = ISS_ON;
+      ConnectSP.s = IPS_BUSY;
+      IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
+      
+      IDSetNumber(nvp, NULL);
+      IEAddTimer(10000, retry_connection, &fd);
+      return;
+    }
+    
+   /* If the error is a time out, then the device doesn't support this property */
+      if (err == -2)
+      {
+       nvp->s = IPS_ALERT;
+       IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
+      }
+      else
+    /* Changing property failed, user should retry. */
+       IDSetNumber( nvp , "%s failed.", msg);
+       
+       fault = true;
+}
+
+/**************************************************************************************
+** Set all properties to idle and reset most switches to clean state.
+***************************************************************************************/
+void LX200Basic::reset_all_properties()
+{
+    ConnectSP.s			= IPS_IDLE;
+    OnCoordSetSP.s		= IPS_IDLE; 
+    AbortSlewSP.s		= IPS_IDLE;
+    PortTP.s			= IPS_IDLE;
+    ObjectTP.s			= IPS_IDLE;
+    EquatorialCoordsWNP.s	= IPS_IDLE;
+    EquatorialCoordsRNP.s	= IPS_IDLE;
+    SlewAccuracyNP.s		= IPS_IDLE;
+    TrackAccuracyNP.s		= IPS_IDLE;
+
+    IUResetSwitch(&OnCoordSetSP);
+    IUResetSwitch(&AbortSlewSP);
+
+    OnCoordSetS[0].s = ISS_ON;
+    ConnectS[0].s = ISS_OFF;
+    ConnectS[1].s = ISS_ON;
+
+    IDSetSwitch(&ConnectSP, NULL);
+    IDSetSwitch(&OnCoordSetSP, NULL);
+    IDSetSwitch(&AbortSlewSP, NULL);
+    IDSetText(&PortTP, NULL);
+    IDSetText(&ObjectTP, NULL);
+    IDSetNumber(&EquatorialCoordsWNP, NULL);
+    IDSetNumber(&EquatorialCoordsRNP, NULL);
+    IDSetNumber(&SlewAccuracyNP, NULL);
+    IDSetNumber(&TrackAccuracyNP, NULL);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::correct_fault()
+{
+  fault = false;
+  IDMessage(mydev, "Telescope is online.");
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LX200Basic::is_connected()
+{
+  if (simulation) return true;
+  
+  return (ConnectSP.sp[0].s == ISS_ON);
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+static void retry_connection(void * p)
+{
+  int fd = *((int *) p);
+
+  if (check_lx200_connection(fd))
+	telescope->connection_lost();
+  else
+	telescope->connection_resumed();
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::ISPoll()
+{	
+	if (is_connected() == false)
+	 return;
+
+        double dx, dy;
+	int error_code=0;
+
+	switch (EquatorialCoordsWNP.s)
+	{
+		case IPS_IDLE:
+		getLX200RA(fd, &currentRA);
+		getLX200DEC(fd, &currentDEC);
+	
+		// Only update values if there are some interesting changes
+	        if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01)
+		{
+	        	lastRA = currentRA;
+			lastDEC = currentDEC;
+			IDSetNumber (&EquatorialCoordsRNP, NULL);
+		}
+        	break;
+
+        	case IPS_BUSY:
+	    	getLX200RA(fd, &currentRA);
+		getLX200DEC(fd, &currentDEC);
+	    	dx = targetRA - currentRA;
+	    	dy = targetDEC - currentDEC;
+
+	    	// Wait until acknowledged or within threshold
+	    	if ( fabs(dx) <= (SlewAccuracyN[0].value/(900.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0))
+	    	{
+		        lastRA  = currentRA;
+		        lastDEC = currentDEC;
+	       		IUResetSwitch(&OnCoordSetSP);
+	       		OnCoordSetSP.s = IPS_OK;
+	       		EquatorialCoordsWNP.s = IPS_OK;
+			EquatorialCoordsRNP.s = IPS_OK;
+	       		IDSetNumber (&EquatorialCoordsWNP, NULL);
+			IDSetNumber (&EquatorialCoordsRNP, NULL);
+
+			switch (currentSet)
+			{
+		  		case LX200_SLEW:
+		  		OnCoordSetSP.sp[LX200_SLEW].s = ISS_ON;
+		  		IDSetSwitch (&OnCoordSetSP, "Slew is complete.");
+		  		break;
+		  
+		  		case LX200_TRACK:
+		  		OnCoordSetSP.sp[LX200_TRACK].s = ISS_ON;
+		  		IDSetSwitch (&OnCoordSetSP, "Slew is complete. Tracking...");
+				break;
+		  
+		  		case LX200_SYNC:
+		  		break;
+			}
+		  
+	    	}
+		else
+			IDSetNumber (&EquatorialCoordsRNP, NULL);
+	    	break;
+
+		case IPS_OK:
+	  
+		if ( (error_code = getLX200RA(fd, &currentRA)) < 0 || (error_code = getLX200DEC(fd, &currentDEC)) < 0)
+		{
+	  		handle_error(&EquatorialCoordsRNP, error_code, "Getting RA/DEC");
+	  		return;
+		}
+	
+		if (fault == true)
+	  		correct_fault();
+	
+		if ( (currentRA != lastRA) || (currentDEC != lastDEC))
+		{
+		  	lastRA  = currentRA;
+			lastDEC = currentDEC;
+			IDSetNumber (&EquatorialCoordsRNP, NULL);
+		}
+        	break;
+
+		case IPS_ALERT:
+	    	break;
+	}
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+bool LX200Basic::process_coords()
+{
+
+  int  error_code;
+  char syncString[256];
+  char RAStr[32], DecStr[32];
+  double dx, dy;
+  
+  switch (currentSet)
+  {
+
+    // Slew
+    case LX200_SLEW:
+          lastSet = LX200_SLEW;
+	  if (EquatorialCoordsWNP.s == IPS_BUSY)
+	  {
+	     IDLog("Aboring Slew\n");
+	     abortSlew(fd);
+
+	     // sleep for 100 mseconds
+	     usleep(100000);
+	  }
+
+	  if ((error_code = Slew(fd)))
+	  {
+	    slew_error(error_code);
+	    return false;
+	  }
+
+	  EquatorialCoordsWNP.s = IPS_BUSY;
+	  EquatorialCoordsRNP.s = IPS_BUSY;
+	  fs_sexa(RAStr, targetRA, 2, 3600);
+	  fs_sexa(DecStr, targetDEC, 2, 3600);
+	  IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
+	  IDSetNumber(&EquatorialCoordsRNP, NULL);
+	  IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
+	  break;
+
+     // Track
+     case LX200_TRACK:
+          //IDLog("We're in LX200_TRACK\n");
+          if (EquatorialCoordsWNP.s == IPS_BUSY)
+	  {
+	     IDLog("Aboring Slew\n");
+	     abortSlew(fd);
+
+	     // sleep for 200 mseconds
+	     usleep(200000);
+	  }
+
+	  dx = fabs ( targetRA - currentRA );
+	  dy = fabs (targetDEC - currentDEC);
+
+	  if (dx >= (TrackAccuracyN[0].value/(60.0*15.0)) || (dy >= TrackAccuracyN[1].value/60.0)) 
+	  {
+          	if ((error_code = Slew(fd)))
+	  	{
+	    		slew_error(error_code);
+	    		return false;
+	  	}
+
+		fs_sexa(RAStr, targetRA, 2, 3600);
+	        fs_sexa(DecStr, targetDEC, 2, 3600);
+		EquatorialCoordsWNP.s = IPS_BUSY;
+		EquatorialCoordsRNP.s = IPS_BUSY;
+		IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
+		IDSetNumber(&EquatorialCoordsRNP, NULL);
+		IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
+	  }
+	  else
+	  {
+	    //IDLog("Tracking called, but tracking threshold not reached yet.\n");
+	    EquatorialCoordsWNP.s = IPS_OK;
+	    EquatorialCoordsRNP.s = IPS_OK;
+
+	    if (lastSet != LX200_TRACK)
+	      IDSetNumber(&EquatorialCoordsWNP, "Tracking...");
+	    else
+	      IDSetNumber(&EquatorialCoordsWNP, NULL);
+
+	    IDSetNumber(&EquatorialCoordsRNP, NULL);
+	  }
+	  lastSet = LX200_TRACK;
+      break;
+
+    // Sync
+    case LX200_SYNC:
+          lastSet = LX200_SYNC;
+	  EquatorialCoordsWNP.s = IPS_IDLE;
+	   
+	  if ( ( error_code = Sync(fd, syncString) < 0) )
+	  {
+	        IDSetNumber( &EquatorialCoordsWNP , "Synchronization failed.");
+		return false;
+	  }
+
+	  EquatorialCoordsWNP.s = IPS_OK;
+	  EquatorialCoordsRNP.s = IPS_OK;
+	  IDSetNumber(&EquatorialCoordsRNP, NULL);
+	  IDLog("Synchronization successful %s\n", syncString);
+	  IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful.");
+	  break;
+    }
+
+   return true;
+
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+int LX200Basic::get_switch_index(ISwitchVectorProperty *sp)
+{
+ for (int i=0; i < sp->nsp ; i++)
+     if (sp->sp[i].s == ISS_ON)
+      return i;
+
+ return -1;
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::connect_telescope()
+{
+     switch (ConnectSP.sp[0].s)
+     {
+      case ISS_ON:  
+	
+        if (simulation)
+	{
+	  ConnectSP.s = IPS_OK;
+	  IDSetSwitch (&ConnectSP, "Simulated telescope is online.");
+	  return;
+	}
+	
+         if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
+	 {
+	   ConnectS[0].s = ISS_OFF;
+	   ConnectS[1].s = ISS_ON;
+	   IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH read and write permission to the port.", PortT[0].text);
+	   return;
+	 }
+
+	 if (check_lx200_connection(fd))
+	 {   
+	   ConnectS[0].s = ISS_OFF;
+	   ConnectS[1].s = ISS_ON;
+	   IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline.");
+	   return;
+	 }
+
+	ConnectSP.s = IPS_OK;
+	IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data...");
+	get_initial_data();
+	break;
+
+     case ISS_OFF:
+         ConnectS[0].s = ISS_OFF;
+	 ConnectS[1].s = ISS_ON;
+         ConnectSP.s = IPS_IDLE;
+	 if (simulation)
+         {
+	    IDSetSwitch (&ConnectSP, "Simulated Telescope is offline.");
+	    return;
+         }
+         IDSetSwitch (&ConnectSP, "Telescope is offline.");
+	 IDLog("Telescope is offline.");
+         
+	 tty_disconnect(fd);
+	 break;
+    }
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::get_initial_data()
+{
+
+  // Make sure short
+  checkLX200Format(fd);
+
+  // Get current RA/DEC
+  getLX200RA(fd, &currentRA);
+  getLX200DEC(fd, &currentDEC);
+
+  IDSetNumber (&EquatorialCoordsRNP, NULL);  
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::slew_error(int slewCode)
+{
+    OnCoordSetSP.s = IPS_IDLE;
+
+    if (slewCode == 1)
+	IDSetSwitch (&OnCoordSetSP, "Object below horizon.");
+    else if (slewCode == 2)
+	IDSetSwitch (&OnCoordSetSP, "Object below the minimum elevation limit.");
+    else
+        IDSetSwitch (&OnCoordSetSP, "Slew failed.");
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::enable_simulation(bool enable)
+{
+   simulation = enable;
+   
+   if (simulation)
+     IDLog("Warning: Simulation is activated.\n");
+   else
+     IDLog("Simulation is disabled.\n");
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::connection_lost()
+{
+    ConnectSP.s = IPS_IDLE;
+    IDSetSwitch(&ConnectSP, "The connection to the telescope is lost.");
+    return;
+ 
+}
+
+/**************************************************************************************
+**
+***************************************************************************************/
+void LX200Basic::connection_resumed()
+{
+  ConnectS[0].s = ISS_ON;
+  ConnectS[1].s = ISS_OFF;
+  ConnectSP.s = IPS_OK;
+   
+  IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed.");
+}
Index: /BAORadio/libindi/v1/drivers/telescope/lx200basic.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200basic.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200basic.h	(revision 500)
@@ -0,0 +1,117 @@
+/*
+    LX200 Basic Driver
+    Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef LX200BASIC_H
+#define LX200BASIC_H
+
+#include "indidevapi.h"
+#include "indicom.h"
+
+class LX200Basic
+{
+ public:
+ LX200Basic();
+ ~LX200Basic();
+
+ void ISGetProperties (const char *dev);
+ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ void ISPoll ();
+
+ void connection_lost();
+ void connection_resumed();
+
+private:
+
+  enum LX200_STATUS { LX200_SLEW, LX200_TRACK, LX200_SYNC, LX200_PARK };
+
+  /* Switches */
+  ISwitch ConnectS[2];
+  ISwitch OnCoordSetS[3];
+  ISwitch AbortSlewS[1];
+  
+  /* Texts */
+  IText PortT[1];
+  IText ObjectT[1];
+
+  /* Numbers */
+  INumber EquatorialCoordsRN[2];
+  INumber EquatorialCoordsWN[2];
+  INumber SlewAccuracyN[2];
+  INumber TrackAccuracyN[2];
+  
+  /* Switch Vectors */
+  ISwitchVectorProperty ConnectSP;
+  ISwitchVectorProperty OnCoordSetSP;
+  ISwitchVectorProperty AbortSlewSP;
+  
+   /* Number Vectors */
+  INumberVectorProperty EquatorialCoordsRNP;
+  INumberVectorProperty EquatorialCoordsWNP;
+  INumberVectorProperty SlewAccuracyNP;
+  INumberVectorProperty TrackAccuracyNP;
+  
+  /* Text Vectors */
+  ITextVectorProperty PortTP;
+  ITextVectorProperty ObjectTP;
+
+ /*******************************************************/
+ /* Connection Routines
+ ********************************************************/
+ void init_properties();
+ void get_initial_data();
+ void connect_telescope();
+ bool is_connected(void);
+ 
+ /*******************************************************/
+ /* Misc routines
+ ********************************************************/
+ bool process_coords();
+ int get_switch_index(ISwitchVectorProperty *sp);
+
+ /*******************************************************/
+ /* Simulation Routines
+ ********************************************************/
+ void enable_simulation(bool enable);
+ 
+ /*******************************************************/
+ /* Error handling routines
+ ********************************************************/
+ void slew_error(int slewCode);
+ void reset_all_properties();
+ void handle_error(INumberVectorProperty *nvp, int err, const char *msg);
+ void correct_fault();
+
+ protected:
+
+  double JD;				/* Julian Date */
+  double lastRA;
+  double lastDEC;
+  bool   simulation;
+  bool   fault;
+  int    fd;				/* Telescope tty file descriptor */
+
+  int currentSet;
+  int lastSet;
+
+};
+
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/lx200classic.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200classic.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200classic.cpp	(revision 500)
@@ -0,0 +1,347 @@
+/*
+    LX200 Classoc
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "lx200classic.h"
+#include "lx200driver.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern LX200Generic *telescope;
+extern INumberVectorProperty EquatorialCoordsWNP;
+extern INumberVectorProperty EquatorialCoordsRNP;
+extern ITextVectorProperty TimeTP;
+extern int MaxReticleFlashRate;
+
+/* Handy Macros */
+#define currentRA	EquatorialCoordsRNP.np[0].value
+#define currentDEC	EquatorialCoordsRNP.np[1].value
+#define targetRA	EquatorialCoordsWNP.np[0].value
+#define targetDEC	EquatorialCoordsWNP.np[1].value
+
+#define BASIC_GROUP	"Main Control"
+#define LIBRARY_GROUP	"Library"
+#define MOVE_GROUP	"Movement Control"
+
+static IText   ObjectText[] = {{"objectText", "Info", 0, 0, 0, 0}};
+static ITextVectorProperty ObjectInfoTP = {mydev, "Object Info", "", BASIC_GROUP, IP_RO, 0, IPS_IDLE, ObjectText, NARRAY(ObjectText), "", 0};
+
+/* Library group */
+static ISwitch StarCatalogS[]    = {{"STAR", "", ISS_ON, 0, 0}, {"SAO", "", ISS_OFF, 0, 0}, {"GCVS", "", ISS_OFF, 0, 0}};
+static ISwitch DeepSkyCatalogS[] = {{"NGC", "", ISS_ON, 0, 0}, {"IC", "", ISS_OFF, 0, 0}, {"UGC", "", ISS_OFF, 0, 0}, {"Caldwell", "", ISS_OFF, 0, 0}, {"Arp", "", ISS_OFF, 0, 0}, {"Abell", "", ISS_OFF, 0, 0}, {"Messier", "", ISS_OFF, 0, 0}};
+static ISwitch SolarS[]          = { {"Select", "Select item...", ISS_ON, 0, 0}, {"1", "Mercury", ISS_OFF,0 , 0}, {"2", "Venus", ISS_OFF, 0, 0}, {"3", "Moon", ISS_OFF, 0, 0}, {"4", "Mars", ISS_OFF, 0, 0}, {"5", "Jupiter", ISS_OFF, 0, 0}, {"6", "Saturn", ISS_OFF, 0, 0}, {"7", "Uranus", ISS_OFF, 0, 0}, {"8", "Neptune", ISS_OFF, 0, 0}, {"9", "Pluto", ISS_OFF, 0 ,0}};
+
+static ISwitchVectorProperty StarCatalogSP   = { mydev, "Star Catalogs", "", LIBRARY_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, StarCatalogS, NARRAY(StarCatalogS), "", 0};
+static ISwitchVectorProperty DeepSkyCatalogSP= { mydev, "Deep Sky Catalogs", "", LIBRARY_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DeepSkyCatalogS, NARRAY(DeepSkyCatalogS), "", 0};
+static ISwitchVectorProperty SolarSP         = { mydev, "SOLAR_SYSTEM", "Solar System", LIBRARY_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SolarS, NARRAY(SolarS), "", 0};
+
+static INumber ObjectN[] = {{ "ObjectN", "Number", "%g", 1., 10000., 1., 0., 0, 0, 0}};
+static INumberVectorProperty ObjectNoNP= { mydev, "Object Number", "", LIBRARY_GROUP, IP_RW, 0, IPS_IDLE, ObjectN, NARRAY(ObjectN), "", 0 };
+
+static INumber MaxSlew[] = {{"maxSlew", "Rate", "%g", 2.0, 9.0, 1.0, 9., 0, 0 ,0}};
+static INumberVectorProperty MaxSlewRateNP = { mydev, "Max slew Rate", "", MOVE_GROUP, IP_RW, 0, IPS_IDLE, MaxSlew, NARRAY(MaxSlew), "", 0};
+
+static INumber altLimit[] = {
+       {"minAlt", "min Alt", "%+03f", -90., 90., 0., 0., 0, 0, 0},
+       {"maxAlt", "max Alt", "%+03f", -90., 90., 0., 0., 0, 0, 0}};
+static INumberVectorProperty ElevationLimitNP = { mydev, "altLimit", "Slew elevation Limit", BASIC_GROUP, IP_RW, 0, IPS_IDLE, altLimit, NARRAY(altLimit), "", 0};
+
+void changeLX200ClassicDeviceName(const char *newName)
+{
+ strcpy(ObjectInfoTP.device, newName);
+ strcpy(SolarSP.device, newName);
+ strcpy(StarCatalogSP.device, newName);
+ strcpy(DeepSkyCatalogSP.device, newName);
+ strcpy(ObjectNoNP.device, newName);
+ strcpy(MaxSlewRateNP.device , newName );
+ strcpy(ElevationLimitNP.device , newName );
+}
+
+LX200Classic::LX200Classic() : LX200Generic()
+{
+   ObjectInfoTP.tp[0].text = NULL;
+   
+   currentCatalog = LX200_STAR_C;
+   currentSubCatalog = 0;
+
+}
+
+void LX200Classic::ISGetProperties (const char *dev)
+{
+
+if (dev && strcmp (thisDevice, dev))
+    return;
+
+  LX200Generic::ISGetProperties(dev);
+
+  IDDefNumber (&ElevationLimitNP, NULL);
+  IDDefText   (&ObjectInfoTP, NULL);
+  IDDefSwitch (&SolarSP, NULL);
+  IDDefSwitch (&StarCatalogSP, NULL);
+  IDDefSwitch (&DeepSkyCatalogSP, NULL);
+  IDDefNumber (&ObjectNoNP, NULL);
+  IDDefNumber (&MaxSlewRateNP, NULL);
+
+}
+
+void LX200Classic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+    // ignore if not ours //
+	if (strcmp (dev, thisDevice))
+	    return;
+
+  LX200Generic::ISNewText (dev, name, texts, names, n);
+}
+
+
+void LX200Classic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+    int err=0;
+    
+    // ignore if not ours //
+	if (strcmp (dev, thisDevice))
+	    return;
+
+    if ( !strcmp (name, ObjectNoNP.name) )
+	{
+
+	  char object_name[256];
+
+	  if (checkPower(&ObjectNoNP))
+	    return;
+
+	  if (selectCatalogObject(fd, currentCatalog, (int) values[0]) < 0)
+	  {
+		ObjectNoNP.s = IPS_ALERT;
+		IDSetNumber(&ObjectNoNP, "Failed to select catalog object.");
+		return;
+	  }
+           
+	  getLX200RA(fd, &targetRA);
+	  getLX200DEC(fd, &targetDEC);
+
+	  ObjectNoNP.s = IPS_OK;
+	  IDSetNumber(&ObjectNoNP , "Object updated.");
+
+	  if (getObjectInfo(fd, object_name) < 0)
+	    IDMessage(thisDevice, "Getting object info failed.");
+	  else
+	  {
+	    IUSaveText(&ObjectInfoTP.tp[0], object_name);
+	    IDSetText  (&ObjectInfoTP, NULL);
+	  }
+
+	  handleCoordSet();
+	  return;
+        }
+	
+    if ( !strcmp (name, MaxSlewRateNP.name) )
+    {
+
+	 if (checkPower(&MaxSlewRateNP))
+	  return;
+
+	 if ( ( err = setMaxSlewRate(fd, (int) values[0]) < 0) )
+	 {
+	        handleError(&MaxSlewRateNP, err, "Setting maximum slew rate");
+		return;
+	 }
+	  MaxSlewRateNP.s = IPS_OK;
+	  MaxSlewRateNP.np[0].value = values[0];
+	  IDSetNumber(&MaxSlewRateNP, NULL);
+	  return;
+    }
+
+
+    if (!strcmp (name, ElevationLimitNP.name))
+	{
+	    // new elevation limits
+	    double minAlt = 0, maxAlt = 0;
+	    int i, nset;
+
+	  if (checkPower(&ElevationLimitNP))
+	   return;
+
+	    for (nset = i = 0; i < n; i++)
+	    {
+		INumber *altp = IUFindNumber (&ElevationLimitNP, names[i]);
+		if (altp == &altLimit[0])
+		{
+		    minAlt = values[i];
+		    nset += minAlt >= -90.0 && minAlt <= 90.0;
+		} else if (altp == &altLimit[1])
+		{
+		    maxAlt = values[i];
+		    nset += maxAlt >= -90.0 && maxAlt <= 90.0;
+		}
+	    }
+	    if (nset == 2)
+	    {
+		//char l[32], L[32];
+		if ( ( err = setMinElevationLimit(fd, (int) minAlt) < 0) )
+	 	{
+	         handleError(&ElevationLimitNP, err, "Setting elevation limit");
+	 	}
+		setMaxElevationLimit(fd, (int) maxAlt);
+		ElevationLimitNP.np[0].value = minAlt;
+		ElevationLimitNP.np[1].value = maxAlt;
+		ElevationLimitNP.s = IPS_OK;
+		IDSetNumber (&ElevationLimitNP, NULL);
+	    } else
+	    {
+		ElevationLimitNP.s = IPS_IDLE;
+		IDSetNumber(&ElevationLimitNP, "elevation limit missing or invalid");
+	    }
+
+	    return;
+	}
+
+    LX200Generic::ISNewNumber (dev, name, values, names, n);
+}
+
+ void LX200Classic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+ {
+
+      int index=0;
+      
+       // ignore if not ours //
+	if (strcmp (dev, thisDevice))
+	    return;
+      
+        // Star Catalog
+	if (!strcmp (name, StarCatalogSP.name))
+	{
+	  if (checkPower(&StarCatalogSP))
+	   return;
+
+	 IUResetSwitch(&StarCatalogSP);
+	 IUUpdateSwitch(&StarCatalogSP, states, names, n);
+	 index = getOnSwitch(&StarCatalogSP);
+
+	 currentCatalog = LX200_STAR_C;
+
+	  if (selectSubCatalog(fd, currentCatalog, index))
+	  {
+	   currentSubCatalog = index;
+	   StarCatalogSP.s = IPS_OK;
+	   IDSetSwitch(&StarCatalogSP, NULL);
+	  }
+	  else
+	  {
+	   StarCatalogSP.s = IPS_IDLE;
+	   IDSetSwitch(&StarCatalogSP, "Catalog unavailable");
+	  }
+	  return;
+	}
+
+	// Deep sky catalog
+	if (!strcmp (name, DeepSkyCatalogSP.name))
+	{
+	  if (checkPower(&DeepSkyCatalogSP))
+	   return;
+
+	IUResetSwitch(&DeepSkyCatalogSP);
+	IUUpdateSwitch(&DeepSkyCatalogSP, states, names, n);
+	index = getOnSwitch(&DeepSkyCatalogSP);
+
+	  if (index == LX200_MESSIER_C)
+	  {
+	    currentCatalog = index;
+	    DeepSkyCatalogSP.s = IPS_OK;
+	    IDSetSwitch(&DeepSkyCatalogSP, NULL);
+	    return;
+	  }
+	  else
+	    currentCatalog = LX200_DEEPSKY_C;
+
+	  if (selectSubCatalog(fd, currentCatalog, index))
+	  {
+	   currentSubCatalog = index;
+	   DeepSkyCatalogSP.s = IPS_OK;
+	   IDSetSwitch(&DeepSkyCatalogSP, NULL);
+	  }
+	  else
+	  {
+	   DeepSkyCatalogSP.s = IPS_IDLE;
+	   IDSetSwitch(&DeepSkyCatalogSP, "Catalog unavailable");
+	  }
+	  return;
+	}
+
+	// Solar system
+	if (!strcmp (name, SolarSP.name))
+	{
+
+	  if (checkPower(&SolarSP))
+	   return;
+
+	   if (IUUpdateSwitch(&SolarSP, states, names, n) < 0)
+		return;
+
+	   index = getOnSwitch(&SolarSP);
+
+	  // We ignore the first option : "Select item"
+	  if (index == 0)
+	  {
+	    SolarSP.s  = IPS_IDLE;
+	    IDSetSwitch(&SolarSP, NULL);
+	    return;
+	  }
+
+          selectSubCatalog (fd, LX200_STAR_C, LX200_STAR);
+	  selectCatalogObject(fd, LX200_STAR_C, index + 900);
+
+	  ObjectNoNP.s = IPS_OK;
+	  SolarSP.s  = IPS_OK;
+
+	  getObjectInfo(fd, ObjectInfoTP.tp[0].text);
+	  IDSetNumber(&ObjectNoNP , "Object updated.");
+	  IDSetSwitch(&SolarSP, NULL);
+
+	  if (currentCatalog == LX200_STAR_C || currentCatalog == LX200_DEEPSKY_C)
+	  	selectSubCatalog(fd, currentCatalog, currentSubCatalog);
+
+	  getObjectRA(fd, &targetRA);
+	  getObjectDEC(fd, &targetDEC);
+
+	  handleCoordSet();
+
+	  return;
+	}
+
+   LX200Generic::ISNewSwitch (dev, name, states, names,  n);
+
+ }
+
+ void LX200Classic::ISPoll ()
+ {
+
+      LX200Generic::ISPoll();
+
+ }
+
+ void LX200Classic::getBasicData()
+ {
+
+   // process parent first
+   LX200Generic::getBasicData();
+
+ }
Index: /BAORadio/libindi/v1/drivers/telescope/lx200classic.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200classic.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200classic.h	(revision 500)
@@ -0,0 +1,49 @@
+/*
+    LX200 Classic
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef LX200CLASSIC_H
+#define LX200CLASSIC_H
+
+#include "lx200generic.h"
+
+class LX200Classic : public LX200Generic
+{
+ public:
+  LX200Classic();
+  ~LX200Classic() {}
+
+ void ISGetProperties (const char *dev);
+ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ void ISPoll ();
+ void getBasicData();
+ 
+ private:
+ int currentCatalog;
+ int currentSubCatalog;
+
+
+};
+
+void changeLX200ClassicDeviceName(const char *newName);
+
+#endif
+ 
Index: /BAORadio/libindi/v1/drivers/telescope/lx200driver.c
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200driver.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200driver.c	(revision 500)
@@ -0,0 +1,1474 @@
+#if 0
+    LX200 Driver
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "indicom.h"
+#include "indidevapi.h"
+#include "lx200driver.h"
+
+#ifndef _WIN32
+#include <termios.h>
+#endif
+
+#define LX200_TIMEOUT	5		/* FD timeout in seconds */
+
+int controller_format;
+
+/**************************************************************************
+ Diagnostics
+ **************************************************************************/
+char ACK(int fd);
+/*int testTelescope(void);
+int testAP(void);*/
+int check_lx200_connection(int fd);
+
+/**************************************************************************
+ Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure 
+ **************************************************************************/
+ 
+/* Get Double from Sexagisemal */
+int getCommandSexa(int fd, double *value, const char *cmd);
+/* Get String */
+int getCommandString(int fd, char *data, const char* cmd);
+/* Get Int */
+int getCommandInt(int fd, int *value, const char* cmd);
+/* Get tracking frequency */
+int getTrackFreq(int fd, double * value);
+/* Get site Latitude */
+int getSiteLatitude(int fd, int *dd, int *mm);
+/* Get site Longitude */
+int getSiteLongitude(int fd, int *ddd, int *mm);
+/* Get Calender data */
+int getCalenderDate(int fd, char *date);
+/* Get site Name */
+int getSiteName(int fd, char *siteName, int siteNum);
+/* Get Number of Bars */
+int getNumberOfBars(int fd, int *value);
+/* Get Home Search Status */
+int getHomeSearchStatus(int fd, int *status);
+/* Get OTA Temperature */
+int getOTATemp(int fd, double * value);
+/* Get time format: 12 or 24 */
+int getTimeFormat(int fd, int *format);
+
+
+/**************************************************************************
+ Set Commands
+ **************************************************************************/
+
+/* Set Int */
+int setCommandInt(int fd, int data, const char *cmd);
+/* Set Sexigesimal */
+int setCommandXYZ(int fd, int x, int y, int z, const char *cmd);
+/* Common routine for Set commands */
+int setStandardProcedure(int fd, char * writeData);
+/* Set Slew Mode */
+int setSlewMode(int fd, int slewMode);
+/* Set Alignment mode */
+int setAlignmentMode(int fd, unsigned int alignMode);
+/* Set Object RA */
+int setObjectRA(int fd, double ra);
+/* set Object DEC */
+int setObjectDEC(int fd, double dec);
+/* Set Calender date */
+int setCalenderDate(int fd, int dd, int mm, int yy);
+/* Set UTC offset */
+int setUTCOffset(int fd, double hours);
+/* Set Track Freq */
+int setTrackFreq(int fd, double trackF);
+/* Set current site longitude */
+int setSiteLongitude(int fd, double Long);
+/* Set current site latitude */
+int setSiteLatitude(int fd, double Lat);
+/* Set Object Azimuth */
+int setObjAz(int fd, double az);
+/* Set Object Altitude */
+int setObjAlt(int fd, double alt);
+/* Set site name */
+int setSiteName(int fd, char * siteName, int siteNum);
+/* Set maximum slew rate */
+int setMaxSlewRate(int fd, int slewRate);
+/* Set focuser motion */
+int setFocuserMotion(int fd, int motionType);
+/* Set focuser speed mode */
+int setFocuserSpeedMode (int fd, int speedMode);
+/* Set minimum elevation limit */
+int setMinElevationLimit(int fd, int min);
+/* Set maximum elevation limit */
+int setMaxElevationLimit(int fd, int max);
+
+/**************************************************************************
+ Motion Commands
+ **************************************************************************/
+/* Slew to the selected coordinates */
+int Slew(int fd);
+/* Synchronize to the selected coordinates and return the matching object if any */
+int Sync(int fd, char *matchedObject);
+/* Abort slew in all axes */
+int abortSlew(int fd);
+/* Move into one direction, two valid directions can be stacked */
+int MoveTo(int fd, int direction);
+/* Half movement in a particular direction */
+int HaltMovement(int fd, int direction);
+/* Select the tracking mode */
+int selectTrackingMode(int fd, int trackMode);
+/* Select Astro-Physics tracking mode */
+int selectAPTrackingMode(int fd, int trackMode);
+/* Send Pulse-Guide command (timed guide move), two valid directions can be stacked */
+int SendPulseCmd(int fd, int direction, int duration_msec);
+
+/**************************************************************************
+ Other Commands
+ **************************************************************************/
+ /* Ensures LX200 RA/DEC format is long */
+int checkLX200Format(int fd);
+/* Select a site from the LX200 controller */
+int selectSite(int fd, int siteNum);
+/* Select a catalog object */
+int selectCatalogObject(int fd, int catalog, int NNNN);
+/* Select a sub catalog */
+int selectSubCatalog(int fd, int catalog, int subCatalog);
+
+int check_lx200_connection(int in_fd)
+{
+
+  int i=0;
+  char ack[1] = { (char) 0x06 };
+  char MountAlign[64];
+  int nbytes_read=0;
+
+  #ifdef INDI_DEBUG
+  IDLog("Testing telescope's connection using ACK...\n");
+  #endif
+
+  if (in_fd <= 0) return -1;
+
+  for (i=0; i < 2; i++)
+  {
+    if (write(in_fd, ack, 1) < 0) return -1;
+    tty_read(in_fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read);
+    if (nbytes_read == 1)
+     return 0;
+    usleep(50000);
+  }
+  
+  return -1;
+}
+
+
+/**********************************************************************
+* GET
+**********************************************************************/
+
+char ACK(int fd)
+{
+  char ack[1] = { (char) 0x06 };
+  char MountAlign[2];
+  int nbytes_write=0, nbytes_read=0, error_type;
+
+  nbytes_write = write(fd, ack, 1);
+
+  if (nbytes_write < 0)
+    return -1;
+ 
+  /*read_ret = portRead(MountAlign, 1, LX200_TIMEOUT);*/
+  error_type = tty_read(fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read);
+  
+  if (nbytes_read == 1)
+    return MountAlign[0];
+  else
+    return error_type;
+}
+
+int getCommandSexa(int fd, double *value, const char * cmd)
+{
+  char temp_string[16];
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+  
+  tcflush(fd, TCIFLUSH);
+
+  if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
+   return error_type;
+  
+  /*if ( (read_ret = portRead(temp_string, -1, LX200_TIMEOUT)) < 1)
+     return read_ret;*/
+  tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+ 
+  temp_string[nbytes_read - 1] = '\0';
+  
+  /*IDLog("getComandSexa: %s\n", temp_string);*/
+
+  if (f_scansexa(temp_string, value))
+  {
+   #ifdef INDI_DEBUG
+   IDLog("unable to process [%s]\n", temp_string);
+   #endif
+   return -1;
+  }
+ 
+   tcflush(fd, TCIFLUSH);
+   return 0;
+}
+
+int getCommandInt(int fd, int *value, const char* cmd)
+{
+  char temp_string[16];
+  float temp_number;
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+
+  
+  tcflush(fd, TCIFLUSH);
+
+  if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
+   return error_type;
+  
+  tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+ 
+  temp_string[nbytes_read - 1] = '\0';
+
+  /* Float */
+  if (strchr(temp_string, '.'))
+  {
+     if (sscanf(temp_string, "%f", &temp_number) != 1)
+	return -1;
+
+	*value = (int) temp_number;
+   }
+  /* Int */
+  else if (sscanf(temp_string, "%d", value) != 1)
+	return -1;
+
+   return 0;
+}
+
+
+int getCommandString(int fd, char *data, const char* cmd)
+{
+    char * term;
+    int error_type;
+    int nbytes_write=0, nbytes_read=0;
+    
+   /*if (portWrite(cmd) < 0)
+      return -1;*/
+
+   if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK)
+    return error_type;
+
+    /*read_ret = portRead(data, -1, LX200_TIMEOUT);*/
+    error_type = tty_read_section(fd, data, '#', LX200_TIMEOUT, &nbytes_read);
+    tcflush(fd, TCIFLUSH);
+
+    if (error_type != TTY_OK)
+	return error_type;
+
+    term = strchr (data, '#');
+    if (term)
+      *term = '\0';
+
+   #ifdef INDI_DEBUG
+    /*IDLog("Requested data: %s\n", data);*/
+   #endif
+
+    return 0;
+}
+
+int getCalenderDate(int fd, char *date)
+{
+
+ int dd, mm, yy;
+ int error_type;
+ int nbytes_read=0;
+ char mell_prefix[3];
+ 
+
+ if ( (error_type = getCommandString(fd, date, "#:GC#")) )
+   return error_type;
+
+ /* Meade format is MM/DD/YY */
+
+  nbytes_read = sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy);
+  if (nbytes_read < 3)
+   return -1;
+
+  /* We consider years 50 or more to be in the last century, anything less in the 21st century.*/
+  if (yy > 50)
+	strncpy(mell_prefix, "19", 3);
+  else
+	strncpy(mell_prefix, "20", 3);
+
+ /* We need to have in in YYYY/MM/DD format */
+ snprintf(date, 16, "%s%02d/%02d/%02d", mell_prefix, yy, mm, dd);
+
+ return (0);
+
+}
+
+int getTimeFormat(int fd, int *format)
+{
+  char temp_string[16];
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+  int tMode;
+
+  /*if (portWrite("#:Gc#") < 0)
+    return -1;*/
+  
+ if ( (error_type = tty_write_string(fd, "#:Gc#", &nbytes_write)) != TTY_OK)
+    return error_type;
+
+  /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/
+  if ( (error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK)
+	return error_type;
+
+  tcflush(fd, TCIFLUSH);
+  
+  if (nbytes_read < 1)
+   return error_type;
+   
+  temp_string[nbytes_read-1] = '\0';
+
+  nbytes_read = sscanf(temp_string, "(%d)", &tMode);
+
+  if (nbytes_read < 1)
+   return -1;
+  else
+   *format = tMode;
+   
+  return 0;
+
+}
+
+int getSiteName(int fd, char *siteName, int siteNum)
+{
+  char * term;
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+
+  switch (siteNum)
+  {
+    case 1:
+     /*if (portWrite("#:GM#") < 0)
+      return -1;*/
+       if ( (error_type = tty_write_string(fd, "#:GM#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     break;
+    case 2:
+     /*if (portWrite("#:GN#") < 0)
+      return -1;*/
+	if ( (error_type = tty_write_string(fd, "#:GN#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     break;
+    case 3:
+     /*if (portWrite("#:GO#") < 0)
+       return -1;*/
+	if ( (error_type = tty_write_string(fd, "#:GO#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     break;
+    case 4:
+     /*if (portWrite("#:GP#") < 0)
+      return -1;*/
+	if ( (error_type = tty_write_string(fd, "#:GP#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     break;
+    default:
+     return -1;
+   }
+
+   /*read_ret = portRead(siteName, -1, LX200_TIMEOUT);*/
+   error_type = tty_read_section(fd, siteName, '#', LX200_TIMEOUT, &nbytes_read);
+   tcflush(fd, TCIFLUSH);
+
+   if (nbytes_read < 1)
+     return error_type;
+
+   siteName[nbytes_read - 1] = '\0';
+
+   term = strchr (siteName, ' ');
+    if (term)
+      *term = '\0';
+
+    term = strchr (siteName, '<');
+    if (term)
+      strcpy(siteName, "unused site");
+
+   #ifdef INDI_DEBUG
+   IDLog("Requested site name: %s\n", siteName);
+   #endif
+
+    return 0;
+}
+
+int getSiteLatitude(int fd, int *dd, int *mm)
+{
+  char temp_string[16];
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+
+  /*if (portWrite("#:Gt#") < 0)
+    return -1;*/
+  if ( (error_type = tty_write_string(fd, "#:Gt#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+  /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/
+  error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+  tcflush(fd, TCIFLUSH);
+  
+   if (nbytes_read < 1) 
+   return error_type;
+   
+  temp_string[nbytes_read -1] = '\0';
+
+  if (sscanf (temp_string, "%d%*c%d", dd, mm) < 2)
+   return -1;
+
+  #ifdef INDI_DEBUG
+  fprintf(stderr, "Requested site latitude in String %s\n", temp_string);
+  fprintf(stderr, "Requested site latitude %d:%d\n", *dd, *mm);
+  #endif
+
+  return 0;
+}
+
+int getSiteLongitude(int fd, int *ddd, int *mm)
+{
+  char temp_string[16];
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+
+  if ( (error_type = tty_write_string(fd, "#:Gg#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+  /*if (portWrite("#:Gg#") < 0)
+   return -1;*/
+  error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+  /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/
+  
+  tcflush(fd, TCIFLUSH);
+  
+  if (nbytes_read < 1)
+    return error_type;
+    
+  temp_string[nbytes_read -1] = '\0';
+
+  if (sscanf (temp_string, "%d%*c%d", ddd, mm) < 2)
+   return -1;
+
+  #ifdef INDI_DEBUG
+  fprintf(stderr, "Requested site longitude in String %s\n", temp_string);
+  fprintf(stderr, "Requested site longitude %d:%d\n", *ddd, *mm);
+  #endif
+
+  return 0;
+}
+
+int getTrackFreq(int fd, double *value)
+{
+    float Freq;
+    char temp_string[16];
+    int error_type;
+    int nbytes_write=0, nbytes_read=0;
+    
+    if ( (error_type = tty_write_string(fd, "#:GT#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+	/*if (portWrite("#:GT#") < 0)
+      return -1;*/
+
+    /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/
+    error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+    tcflush(fd, TCIFLUSH);
+    
+    if (nbytes_read < 1)
+     return error_type;
+
+    temp_string[nbytes_read] = '\0';
+    
+    /*fprintf(stderr, "Telescope tracking freq str: %s\n", temp_string);*/
+    
+    if (sscanf(temp_string, "%f#", &Freq) < 1)
+     return -1;
+   
+    *value = (double) Freq;
+    
+    #ifdef INDI_DEBUG
+    fprintf(stderr, "Tracking frequency value is %f\n", Freq);
+    #endif
+
+    return 0;
+}
+
+int getNumberOfBars(int fd, int *value)
+{
+   char temp_string[128];
+   int error_type;
+   int nbytes_write=0, nbytes_read=0;
+
+   if ( (error_type = tty_write_string(fd, "#:D#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+   /*if (portWrite("#:D#") < 0)
+     return -1;*/
+
+   error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+   tcflush(fd, TCIFLUSH);
+   
+   if (nbytes_read < 0)
+    return error_type;
+
+   *value = nbytes_read -1;
+   
+   return 0;
+}
+
+int getHomeSearchStatus(int fd, int *status)
+{
+  char temp_string[16];
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+
+  if ( (error_type = tty_write_string(fd, "#:h?#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+ /*if (portWrite("#:h?#") < 0)
+   return -1;*/
+
+  /*read_ret = portRead(temp_string, 1, LX200_TIMEOUT);*/
+  error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+  tcflush(fd, TCIFLUSH);
+  
+  if (nbytes_read < 1)
+   return error_type;
+   
+  temp_string[1] = '\0';
+
+  if (temp_string[0] == '0')
+    *status = 0;
+  else if (temp_string[0] == '1')
+    *status = 1;
+  else if (temp_string[0] == '2')
+    *status = 1;
+  
+  return 0;
+}
+
+int getOTATemp(int fd, double *value)
+{
+
+  char temp_string[16];
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+  float temp;
+  
+  if ( (error_type = tty_write_string(fd, "#:fT#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+  error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+  
+  if (nbytes_read < 1)
+   return error_type;
+   
+  temp_string[nbytes_read - 1] = '\0';
+
+  if (sscanf(temp_string, "%f", &temp) < 1)
+   return -1;
+   
+   *value = (double) temp;
+
+  return 0;
+
+}
+
+int updateSkyCommanderCoord(int fd, double *ra, double *dec)
+{
+  char coords[16];
+  char CR[1] = { (char) 0x0D };
+  float RA=0.0, DEC=0.0;
+  int error_type;
+  int nbytes_read=0;
+
+  error_type = write(fd, CR, 1);
+
+  error_type = tty_read(fd, coords, 16, LX200_TIMEOUT, &nbytes_read);
+  /*read_ret = portRead(coords, 16, LX200_TIMEOUT);*/
+  tcflush(fd, TCIFLUSH);
+
+  nbytes_read = sscanf(coords, " %g %g", &RA, &DEC);
+
+  if (nbytes_read < 2)
+  {
+   #ifdef INDI_DEBUG
+   IDLog("Error in Sky commander number format [%s], exiting.\n", coords);
+   #endif
+   return error_type;
+  }
+
+  *ra  = RA;
+  *dec = DEC;
+
+  return 0;
+
+}
+
+int updateIntelliscopeCoord (int fd, double *ra, double *dec)
+{
+  char coords[16];
+  char CR[1] = { (char) 0x51 };	/* "Q" */
+  float RA = 0.0, DEC = 0.0;
+  int error_type;
+  int nbytes_read=0;
+
+  /*IDLog ("Sending a Q\n");*/
+  error_type = write (fd, CR, 1);
+  /* We start at 14 bytes in case its a Sky Wizard, 
+     but read one more later it if it's a intelliscope */
+  /*read_ret = portRead (coords, 14, LX200_TIMEOUT);*/
+  error_type = tty_read(fd, coords, 14, LX200_TIMEOUT, &nbytes_read);
+  tcflush(fd, TCIFLUSH);
+  /*IDLog ("portRead() = [%s]\n", coords);*/
+
+  /* Remove the Q in the response from the Intelliscope  but not the Sky Wizard */
+  if (coords[0] == 'Q') {
+    coords[0] = ' ';
+    /* Read one more byte if Intelliscope to get the "CR" */
+    error_type = tty_read(fd, coords, 1, LX200_TIMEOUT, &nbytes_read);
+    /*read_ret = portRead (coords, 1, LX200_TIMEOUT);*/
+  }
+  nbytes_read = sscanf (coords, " %g %g", &RA, &DEC);
+  /*IDLog ("sscanf() RA = [%f]\n", RA * 0.0390625);*/
+  /*IDLog ("sscanf() DEC = [%f]\n", DEC * 0.0390625);*/
+
+  /*IDLog ("Intelliscope output [%s]", coords);*/
+  if (nbytes_read < 2)
+  {
+    #ifdef INDI_DEBUG
+    IDLog ("Error in Intelliscope number format [%s], exiting.\n", coords);
+    #endif
+    return -1;
+  }
+
+  *ra = RA * 0.0390625;
+  *dec = DEC * 0.0390625;
+
+  return 0;
+
+}
+
+
+/**********************************************************************
+* SET
+**********************************************************************/
+
+int setStandardProcedure(int fd, char * data)
+{
+ char bool_return[2];
+ int error_type;
+ int nbytes_write=0, nbytes_read=0;
+ 
+ if ( (error_type = tty_write_string(fd, data, &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+ error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read);
+ /*read_ret = portRead(boolRet, 1, LX200_TIMEOUT);*/
+ tcflush(fd, TCIFLUSH);
+ 
+ if (nbytes_read < 1)
+   return error_type;
+
+ if (bool_return[0] == '0')
+ {
+     #ifdef INDI_DEBUG
+     IDLog("%s Failed.\n", data);
+     #endif
+     return -1;
+ }
+
+ #ifdef INDI_DEBUG
+ IDLog("%s Successful\n", data);
+ #endif
+
+ return 0;
+
+
+}
+
+int setCommandInt(int fd, int data, const char *cmd)
+{
+  char temp_string[16];
+  int error_type;
+  int nbytes_write=0;
+
+  snprintf(temp_string, sizeof( temp_string ), "%s%d#", cmd, data);
+
+  if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+ /*  if (portWrite(temp_string) < 0)
+    return -1;*/
+
+  return 0;
+}
+
+int setMinElevationLimit(int fd, int min)
+{
+ char temp_string[16];
+
+ snprintf(temp_string, sizeof( temp_string ), "#:Sh%02d#", min);
+
+ return (setStandardProcedure(fd, temp_string));
+}
+
+int setMaxElevationLimit(int fd, int max)
+{
+ char temp_string[16];
+
+ snprintf(temp_string, sizeof( temp_string ), "#:So%02d*#", max);
+
+ return (setStandardProcedure(fd, temp_string));
+
+}
+
+int setMaxSlewRate(int fd, int slewRate)
+{
+
+   char temp_string[16];
+
+   if (slewRate < 2 || slewRate > 8)
+    return -1;
+
+   snprintf(temp_string, sizeof( temp_string ), "#:Sw%d#", slewRate);
+
+   return (setStandardProcedure(fd, temp_string));
+
+}
+
+int setObjectRA(int fd, double ra)
+{
+
+ int h, m, s, frac_m;
+ char temp_string[16];
+
+ getSexComponents(ra, &h, &m, &s);
+
+ frac_m = (s / 60.0) * 10.;
+
+ if (controller_format == LX200_LONG_FORMAT)
+ 	snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d:%02d#", h, m, s);
+ else
+	snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d.%01d#", h, m, frac_m);
+	
+ /*IDLog("Set Object RA String %s\n", temp_string);*/
+ return (setStandardProcedure(fd, temp_string));
+}
+
+
+int setObjectDEC(int fd, double dec)
+{
+  int d, m, s;
+  char temp_string[16];
+
+  getSexComponents(dec, &d, &m, &s);
+
+  switch(controller_format)
+  {
+ 
+    case LX200_SHORT_FORMAT:
+    /* case with negative zero */
+    if (!d && dec < 0)
+    	snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d*%02d#", d, m);
+    else	
+    	snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d*%02d#", d, m);
+    break;
+
+    case LX200_LONG_FORMAT:
+    /* case with negative zero */
+    if (!d && dec < 0)
+    	snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d:%02d:%02d#", d, m, s);
+    else	
+    	snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d:%02d:%02d#", d, m, s);
+    break;
+  }
+
+  /*IDLog("Set Object DEC String %s\n", temp_string);*/
+  
+  return (setStandardProcedure(fd, temp_string));
+
+}
+
+int setCommandXYZ(int fd, int x, int y, int z, const char *cmd)
+{
+  char temp_string[16];
+
+  snprintf(temp_string, sizeof( temp_string ), "%s %02d:%02d:%02d#", cmd, x, y, z);
+
+  return (setStandardProcedure(fd, temp_string));
+}
+
+int setAlignmentMode(int fd, unsigned int alignMode)
+{
+  /*fprintf(stderr , "Set alignment mode %d\n", alignMode);*/
+  int error_type;
+  int nbytes_write=0;
+
+  switch (alignMode)
+   {
+     case LX200_ALIGN_POLAR:
+	if ( (error_type = tty_write_string(fd, "#:AP#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+      /*if (portWrite("#:AP#") < 0)
+        return -1;*/
+      break;
+     case LX200_ALIGN_ALTAZ:
+	if ( (error_type = tty_write_string(fd, "#:AA#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+      /*if (portWrite("#:AA#") < 0)
+        return -1;*/
+      break;
+     case LX200_ALIGN_LAND:
+	if ( (error_type = tty_write_string(fd, "#:AL#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+       /*if (portWrite("#:AL#") < 0)
+        return -1;*/
+       break;
+   }
+   
+   tcflush(fd, TCIFLUSH);
+   return 0;
+}
+
+int setCalenderDate(int fd, int dd, int mm, int yy)
+{
+   char temp_string[32];
+   char dumpPlanetaryUpdateString[64];
+   char bool_return[2];
+   int error_type;
+   int nbytes_write=0, nbytes_read=0;
+   yy = yy % 100;
+
+   snprintf(temp_string, sizeof( temp_string ), "#:SC %02d/%02d/%02d#", mm, dd, yy);
+
+   if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+   /*if (portWrite(temp_string) < 0)
+    return -1;*/
+
+   /*read_ret = portRead(boolRet, 1, LX200_TIMEOUT);*/
+   error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read);
+   tcflush(fd, TCIFLUSH);
+   
+   if (nbytes_read < 1)
+    return error_type;
+    
+   bool_return[1] = '\0';
+
+   if (bool_return[0] == '0')
+     return -1;
+     
+    /* Read dumped data */
+    error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', LX200_TIMEOUT, &nbytes_read);
+    error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', 5, &nbytes_read);
+
+   return 0;
+}
+
+int setUTCOffset(int fd, double hours)
+{
+   char temp_string[16];
+
+   snprintf(temp_string, sizeof( temp_string ), "#:SG %+03d#", (int) hours);
+
+   /*IDLog("UTC string is %s\n", temp_string);*/
+
+   return (setStandardProcedure(fd, temp_string));
+
+}
+
+int setSiteLongitude(int fd, double Long)
+{
+   int d, m, s;
+   char temp_string[32];
+
+   getSexComponents(Long, &d, &m, &s);
+
+   snprintf(temp_string, sizeof( temp_string ), "#:Sg%03d:%02d#", d, m);
+
+   return (setStandardProcedure(fd, temp_string));
+}
+
+int setSiteLatitude(int fd, double Lat)
+{
+   int d, m, s;
+   char temp_string[32];
+
+   getSexComponents(Lat, &d, &m, &s);
+
+   snprintf(temp_string, sizeof( temp_string ), "#:St%+03d:%02d:%02d#", d, m, s);
+
+   return (setStandardProcedure(fd, temp_string));
+}
+
+int setObjAz(int fd, double az)
+{
+   int d,m,s;
+   char temp_string[16];
+
+   getSexComponents(az, &d, &m, &s);
+
+   snprintf(temp_string, sizeof( temp_string ), "#:Sz%03d:%02d#", d, m);
+
+   return (setStandardProcedure(fd, temp_string));
+
+}
+
+int setObjAlt(int fd, double alt)
+{
+    int d, m, s;
+    char temp_string[16];
+
+   getSexComponents(alt, &d, &m, &s);
+
+   snprintf(temp_string, sizeof( temp_string ), "#:Sa%+02d*%02d#", d, m);
+
+   return (setStandardProcedure(fd, temp_string));
+}
+
+
+int setSiteName(int fd, char * siteName, int siteNum)
+{
+
+   char temp_string[16];
+
+   switch (siteNum)
+   {
+     case 1:
+      snprintf(temp_string, sizeof( temp_string ), "#:SM %s#", siteName);
+      break;
+     case 2:
+      snprintf(temp_string, sizeof( temp_string ), "#:SN %s#", siteName);
+      break;
+     case 3:
+      snprintf(temp_string, sizeof( temp_string ), "#:SO %s#", siteName);
+      break;
+    case 4:
+      snprintf(temp_string, sizeof( temp_string ), "#:SP %s#", siteName);
+      break;
+    default:
+      return -1;
+    }
+
+   return (setStandardProcedure(fd, temp_string));
+}
+
+int setSlewMode(int fd, int slewMode)
+{
+  int error_type;
+  int nbytes_write=0;
+
+  switch (slewMode)
+  {
+    case LX200_SLEW_MAX:
+   if ( (error_type = tty_write_string(fd, "#:RS#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     /*if (portWrite("#:RS#") < 0)
+      return -1;*/
+     break;
+    case LX200_SLEW_FIND:
+     if ( (error_type = tty_write_string(fd, "#:RM#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     /*if (portWrite("#:RM#") < 0)
+      return -1;*/
+     break;
+    case LX200_SLEW_CENTER:
+	if ( (error_type = tty_write_string(fd, "#:RC#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     /*if (portWrite("#:RC#") < 0)
+      return -1;*/
+     break;
+    case LX200_SLEW_GUIDE:
+    if ( (error_type = tty_write_string(fd, "#:RG#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     /*if (portWrite("#:RG#") < 0)
+      return -1;*/
+     break;
+    default:
+     break;
+   }
+   
+   tcflush(fd, TCIFLUSH);
+   return 0;
+
+}
+
+int setFocuserMotion(int fd, int motionType)
+{
+  int error_type;
+  int nbytes_write=0;
+
+  switch (motionType)
+  {
+    case LX200_FOCUSIN:
+    if ( (error_type = tty_write_string(fd, "#:F+#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+	#ifdef INDI_DEBUG
+	/*IDLog("Focus IN Command\n");*/
+	#endif
+    /*if (portWrite("#:F+#") < 0)
+      return -1;*/
+      break;
+    case LX200_FOCUSOUT:
+    if ( (error_type = tty_write_string(fd, "#:F-#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+	#ifdef INDI_DEBUG
+	/*IDLog("Focus OUT Command\n");*/
+	#endif
+     /*if (portWrite("#:F-#") < 0)
+       return -1;*/
+     break;
+  }
+
+  tcflush(fd, TCIFLUSH);
+  return 0;
+}
+
+int setFocuserSpeedMode (int fd, int speedMode)
+{
+  int error_type;
+  int nbytes_write=0;
+
+ switch (speedMode)
+ {
+    case LX200_HALTFOCUS:
+    if ( (error_type = tty_write_string(fd, "#:FQ#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+	#ifdef INDI_DEBUG
+	/*IDLog("Halt Focus Command\n");*/
+	#endif
+    /* if (portWrite("#:FQ#") < 0)
+      return -1;*/
+     break;
+   case LX200_FOCUSSLOW:
+    if ( (error_type = tty_write_string(fd, "#:FS#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+	#ifdef INDI_DEBUG
+	/*IDLog("Focus Slow (FS) Command\n");*/
+	#endif
+      /*if (portWrite("#:FS#") < 0)
+       return -1;*/
+      break;
+    case LX200_FOCUSFAST:
+     if ( (error_type = tty_write_string(fd, "#:FF#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+	#ifdef INDI_DEBUG
+	/*IDLog("Focus Fast (FF) Command\n");*/
+	#endif
+     /*if (portWrite("#:FF#") < 0)
+      return -1;*/
+     break;
+ }
+
+ tcflush(fd, TCIFLUSH);
+ return 0;
+}
+
+int setGPSFocuserSpeed (int fd, int speed)
+{
+  char speed_str[8];
+  int error_type;
+  int nbytes_write=0;
+
+  if (speed == 0)
+  {
+     /*if (portWrite("#:FQ#") < 0)
+      return -1;*/
+     if ( (error_type = tty_write_string(fd, "#:FQ#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+	#ifdef INDI_DEBUG
+	/*IDLog("GPS Focus HALT Command (FQ) \n");*/
+	#endif
+
+     return 0;
+  }
+
+  snprintf(speed_str, 8, "#:F%d#", speed);
+
+  if ( (error_type = tty_write_string(fd, speed_str, &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+    #ifdef INDI_DEBUG
+    /*IDLog("GPS Focus Speed command %s \n", speed_str);*/
+    #endif
+  /*if (portWrite(speed_str) < 0)
+       return -1;*/
+
+  tcflush(fd, TCIFLUSH);
+  return 0;
+}
+
+int setTrackFreq(int fd, double trackF)
+{
+  char temp_string[16];
+
+  snprintf(temp_string, sizeof( temp_string ), "#:ST %04.1f#", trackF);
+
+  return (setStandardProcedure(fd, temp_string));
+
+}
+
+/**********************************************************************
+* Misc
+*********************************************************************/
+
+int Slew(int fd)
+{
+    char slewNum[2];
+    int error_type;
+    int nbytes_write=0, nbytes_read=0;
+
+    if ( (error_type = tty_write_string(fd, "#:MS#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+
+    error_type = tty_read(fd, slewNum, 1, LX200_TIMEOUT, &nbytes_read);
+    
+    if (nbytes_read < 1)
+      return error_type;
+
+    /* We don't need to read the string message, just return corresponding error code */
+    tcflush(fd, TCIFLUSH);
+
+    if (slewNum[0] == '0')
+     return 0;
+    else if  (slewNum[0] == '1')
+      return 1;
+    else return 2;
+
+}
+
+int MoveTo(int fd, int direction)
+{
+  int nbytes_write=0;
+
+  switch (direction)
+  {
+    case LX200_NORTH:
+    tty_write_string(fd, "#:Mn#", &nbytes_write);
+    /*portWrite("#:Mn#");*/
+    break;
+    case LX200_WEST:
+    tty_write_string(fd, "#:Mw#", &nbytes_write);
+    /*portWrite("#:Mw#");*/
+    break;
+    case LX200_EAST:
+    tty_write_string(fd, "#:Me#", &nbytes_write);
+    /*portWrite("#:Me#");*/
+    break;
+    case LX200_SOUTH:
+    tty_write_string(fd, "#:Ms#", &nbytes_write);
+    /*portWrite("#:Ms#");*/
+    break;
+    default:
+    break;
+  }
+  
+  tcflush(fd, TCIFLUSH);
+  return 0;
+}
+
+int SendPulseCmd(int fd, int direction, int duration_msec)
+{
+  int nbytes_write=0;
+  char cmd[20];
+  switch (direction)
+  {
+    case LX200_NORTH: sprintf(cmd, "#:Mgn%04d#", duration_msec); break;
+    case LX200_SOUTH: sprintf(cmd, "#:Mgs%04d#", duration_msec); break;
+    case LX200_EAST:  sprintf(cmd, "#:Mge%04d#", duration_msec); break;
+    case LX200_WEST:  sprintf(cmd, "#:Mgw%04d#", duration_msec); break;
+    default: return 1;
+  }
+  
+  tty_write_string(fd, cmd, &nbytes_write);
+  
+  tcflush(fd, TCIFLUSH);
+  return 0;
+}
+
+int HaltMovement(int fd, int direction)
+{
+    int error_type;
+    int nbytes_write=0;
+
+  switch (direction)
+  {
+    case LX200_NORTH:
+     /*if (portWrite("#:Qn#") < 0)
+      return -1;*/
+       if ( (error_type = tty_write_string(fd, "#:Qn#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     break;
+    case LX200_WEST:
+     /*if (portWrite("#:Qw#") < 0)
+      return -1;*/
+     if ( (error_type = tty_write_string(fd, "#:Qw#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     break;
+    case LX200_EAST:
+     /*if (portWrite("#:Qe#") < 0)
+      return -1;*/
+      if ( (error_type = tty_write_string(fd, "#:Qe#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     break;
+    case LX200_SOUTH:
+    if ( (error_type = tty_write_string(fd, "#:Qs#", &nbytes_write)) != TTY_OK)
+    	return error_type;
+     /*if (portWrite("#:Qs#") < 0)
+       return -1;*/
+    break;
+    case LX200_ALL:
+     /*if (portWrite("#:Q#") < 0)
+       return -1;*/
+	if ( (error_type = tty_write_string(fd, "#:Q#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+     break;
+    default:
+     return -1;
+    break;
+  }
+  
+  tcflush(fd, TCIFLUSH);
+  return 0;
+
+}
+
+int abortSlew(int fd)
+{
+ /*if (portWrite("#:Q#") < 0)
+  return -1;*/
+  int error_type;
+  int nbytes_write=0;
+
+ if ( (error_type = tty_write_string(fd, "#:Q#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+
+ tcflush(fd, TCIFLUSH);
+ return 0;
+}
+
+int Sync(int fd, char *matchedObject)
+{
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+
+  if ( (error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+
+  /*portWrite("#:CM#");*/
+
+  /*read_ret = portRead(matchedObject, -1, LX200_TIMEOUT);*/
+    error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read);
+  
+  if (nbytes_read < 1)
+   return error_type;
+   
+  matchedObject[nbytes_read-1] = '\0';
+
+  /*IDLog("Matched Object: %s\n", matchedObject);*/
+  
+  /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */
+  usleep(10000);
+  tcflush(fd, TCIFLUSH);
+
+  return 0;
+}
+
+int selectSite(int fd, int siteNum)
+{
+  int error_type;
+  int nbytes_write=0;
+
+  switch (siteNum)
+  {
+    case 1:
+  	if ( (error_type = tty_write_string(fd, "#:W1#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+      /*if (portWrite("#:W1#") < 0)
+       return -1;*/
+      break;
+    case 2:
+	if ( (error_type = tty_write_string(fd, "#:W2#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+      /*if (portWrite("#:W2#") < 0)
+       return -1;*/
+      break;
+    case 3:
+	if ( (error_type = tty_write_string(fd, "#:W3#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+      /*if (portWrite("#:W3#") < 0)
+       return -1;*/
+      break;
+    case 4:
+	if ( (error_type = tty_write_string(fd, "#:W4#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+      /*if (portWrite("#:W4#") < 0)
+       return -1;*/
+      break;
+    default:
+    return -1;
+    break;
+  }
+  
+  tcflush(fd, TCIFLUSH);
+  return 0;
+
+}
+
+int selectCatalogObject(int fd, int catalog, int NNNN)
+{
+ char temp_string[16];
+ int error_type;
+ int nbytes_write=0;
+ 
+ switch (catalog)
+ {
+   case LX200_STAR_C:
+    snprintf(temp_string, sizeof( temp_string ), "#:LS%d#", NNNN);
+    break;
+   case LX200_DEEPSKY_C:
+    snprintf(temp_string, sizeof( temp_string ), "#:LC%d#", NNNN);
+    break;
+   case LX200_MESSIER_C:
+    snprintf(temp_string, sizeof( temp_string ), "#:LM%d#", NNNN);
+    break;
+   default:
+    return -1;
+  }
+
+  if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK)
+    	   return error_type;
+  /*if (portWrite(temp_string) < 0)
+   return -1;*/
+
+  tcflush(fd, TCIFLUSH);
+  return 0;
+}
+
+int selectSubCatalog(int fd, int catalog, int subCatalog)
+{
+  char temp_string[16];
+  switch (catalog)
+  {
+    case LX200_STAR_C:
+    snprintf(temp_string, sizeof( temp_string ), "#:LsD%d#", subCatalog);
+    break;
+    case LX200_DEEPSKY_C:
+    snprintf(temp_string, sizeof( temp_string ), "#:LoD%d#", subCatalog);
+    break;
+    case LX200_MESSIER_C:
+     return 1;
+    default:
+     return 0;
+  }
+
+  return (setStandardProcedure(fd, temp_string));
+}
+
+int checkLX200Format(int fd)
+{
+  char temp_string[16];
+  controller_format = LX200_LONG_FORMAT;
+  int error_type;
+  int nbytes_write=0, nbytes_read=0;
+
+  if ( (error_type = tty_write_string(fd, "#:GR#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+
+  /*if (portWrite("#:GR#") < 0)
+   return -1;*/
+
+  /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/
+  error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read);
+  
+  if (nbytes_read < 1)
+   return error_type;
+   
+  temp_string[nbytes_read - 1] = '\0';
+
+  /* Check whether it's short or long */
+  if (temp_string[5] == '.')
+  {
+     controller_format = LX200_SHORT_FORMAT;
+      return 0;
+  }
+  else
+     return 0;
+}
+
+int selectTrackingMode(int fd, int trackMode)
+{
+ int error_type;
+ int nbytes_write=0;
+  
+   switch (trackMode)
+   {
+    case LX200_TRACK_DEFAULT:
+      #ifdef INDI_DEBUG
+      IDLog("Setting tracking mode to sidereal.\n");
+      #endif
+     if ( (error_type = tty_write_string(fd, "#:TQ#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+     /*if (portWrite("#:TQ#") < 0)
+       return -1;*/
+     break;
+    case LX200_TRACK_LUNAR:
+      #ifdef INDI_DEBUG
+      IDLog("Setting tracking mode to LUNAR.\n");
+      #endif
+      if ( (error_type = tty_write_string(fd, "#:TL#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+     /*if (portWrite("#:TL#") < 0)
+       return -1;*/
+     break;
+   case LX200_TRACK_MANUAL:
+     #ifdef INDI_DEBUG
+     IDLog("Setting tracking mode to CUSTOM.\n");
+     #endif
+     if ( (error_type = tty_write_string(fd, "#:TM#", &nbytes_write)) != TTY_OK)
+    	   return error_type;
+     /*if (portWrite("#:TM#") < 0)
+      return -1;*/
+     break;
+   default:
+    return -1;
+    break;
+   }
+   
+   tcflush(fd, TCIFLUSH);
+   return 0;
+
+}
+
Index: /BAORadio/libindi/v1/drivers/telescope/lx200driver.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200driver.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200driver.h	(revision 500)
@@ -0,0 +1,250 @@
+/*
+    LX200 Driver
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef LX200DRIVER_H
+#define LX200DRIVER_H
+
+  /* Slew speeds */
+enum TSlew { LX200_SLEW_MAX, LX200_SLEW_FIND, LX200_SLEW_CENTER, LX200_SLEW_GUIDE};
+  /* Alignment modes */
+enum TAlign {  LX200_ALIGN_POLAR, LX200_ALIGN_ALTAZ, LX200_ALIGN_LAND };
+  /* Directions */
+enum TDirection { LX200_NORTH, LX200_WEST, LX200_EAST, LX200_SOUTH, LX200_ALL};
+  /* Formats of Right ascention and Declenation */
+enum TFormat { LX200_SHORT_FORMAT, LX200_LONG_FORMAT};
+  /* Time Format */
+enum TTimeFormat { LX200_24, LX200_AM, LX200_PM};
+  /* Focus operation */
+enum TFocusMotion { LX200_FOCUSIN, LX200_FOCUSOUT };
+enum TFocusSpeed  { LX200_HALTFOCUS = 0, LX200_FOCUSSLOW, LX200_FOCUSFAST};
+  /* Library catalogs */
+enum TCatalog { LX200_STAR_C, LX200_DEEPSKY_C};
+  /* Frequency mode */
+enum StarCatalog { LX200_STAR, LX200_SAO, LX200_GCVS };
+  /* Deep Sky Catalogs */
+enum DeepSkyCatalog { LX200_NGC, LX200_IC, LX200_UGC, LX200_CALDWELL, LX200_ARP, LX200_ABELL, LX200_MESSIER_C};
+  /* Mount tracking frequency, in Hz */
+enum TFreq { LX200_TRACK_DEFAULT, LX200_TRACK_LUNAR, LX200_TRACK_MANUAL};
+
+#define MaxReticleDutyCycle		15
+#define MaxFocuserSpeed			4
+
+/* GET formatted sexagisemal value from device, return as double */
+#define getLX200RA(fd, x)				getCommandSexa(fd, x, "#:GR#")
+#define getLX200DEC(fd, x)				getCommandSexa(fd, x, "#:GD#")
+#define getObjectRA(fd, x)				getCommandSexa(fd, x, "#:Gr#")
+#define getObjectDEC(fd, x)				getCommandSexa(fd, x, "#:Gd#")
+#define getLocalTime12(fd, x)				getCommandSexa(fd, x, "#:Ga#")
+#define getLocalTime24(fd, x)				getCommandSexa(fd, x, "#:GL#")
+#define getSDTime(fd, x)				getCommandSexa(fd, x, "#:GS#")
+#define getLX200Alt(fd, x)				getCommandSexa(fd, x, "#:GA#")
+#define getLX200Az(fd, x)				getCommandSexa(fd, x, "#:GZ#")
+
+/* GET String from device and store in supplied buffer x */
+#define getObjectInfo(fd, x)				getCommandString(fd, x, "#:LI#")
+#define getVersionDate(fd, x)				getCommandString(fd, x, "#:GVD#")
+#define getVersionTime(fd, x)				getCommandString(fd, x, "#:GVT#")
+#define getFullVersion(fd, x)				getCommandString(fd, x, "#:GVF#")
+#define getVersionNumber(fd, x)				getCommandString(fd, x, "#:GVN#")
+#define getProductName(fd, x)				getCommandString(fd, x, "#:GVP#")
+#define turnGPS_StreamOn(fd)				getCommandString(fd, x, "#:gps#")
+
+/* GET Int from device and store in supplied pointer to integer x */
+#define getUTCOffset(fd, x)				getCommandInt(fd, x, "#:GG#")
+#define getMaxElevationLimit(fd, x)			getCommandInt(fd, x, "#:Go#")
+#define getMinElevationLimit(fd, x)			getCommandInt(fd, x, "#:Gh#")
+
+/* Generic set, x is an integer */
+#define setReticleDutyFlashCycle(fd, x)			setCommandInt(fd, x, "#:BD")
+#define setReticleFlashRate(fd, x)			setCommandInt(fd, x, "#:B")
+#define setFocuserSpeed(fd, x)				setCommandInt(fd, x, "#:F")
+#define setSlewSpeed(fd, x)				setCommandInt(fd, x, "#:Sw")
+
+/* Set X:Y:Z */
+#define setLocalTime(fd, x,y,z)				setCommandXYZ(fd, x,y,z, "#:SL")
+#define setSDTime(fd, x,y,z)				setCommandXYZ(fd, x,y,z, "#:SS")
+
+/* GPS Specefic */
+#define turnGPSOn(fd)					write(fd, "#:g+#", 5)
+#define turnGPSOff(fd)					write(fd, "#:g-#", 5)
+#define alignGPSScope(fd)				write(fd, "#:Aa#", 5)
+#define gpsSleep(fd)					write(fd, "#:hN#", 5)
+#define gpsWakeUp(fd)					write(fd, "#:hW#", 5);
+#define gpsRestart(fd)					write(fd, "#:I#", 4);
+#define updateGPS_System(fd)				setStandardProcedure(fd, "#:gT#")
+#define enableDecAltPec(fd)				write(fd, "#:QA+#", 6)
+#define disableDecAltPec(fd)				write(fd, "#:QA-#", 6)
+#define enableRaAzPec(fd)				write(fd, "#:QZ+#", 6)
+#define disableRaAzPec(fd)				write(fd, "#:QZ-#", 6)
+#define activateAltDecAntiBackSlash(fd)			write(fd, "#$BAdd#", 7)
+#define activateAzRaAntiBackSlash(fd)			write(fd, "#$BZdd#", 7)
+#define SelenographicSync(fd)				write(fd, "#:CL#", 5); 
+
+#define slewToAltAz(fd)					setStandardProcedure(fd, "#:MA#")
+#define toggleTimeFormat(fd)				write(fd, "#:H#", 4)
+#define increaseReticleBrightness(fd)			write(fd, "#:B+#", 5)
+#define decreaseReticleBrightness(fd)			write(fd, "#:B-#", 5)
+#define turnFanOn(fd)					write(fd, "#:f+#", 5)
+#define turnFanOff(fd)					write(fd, "#:f-#", 5)
+#define seekHomeAndSave(fd)				write(fd, "#:hS#", 5)
+#define seekHomeAndSet(fd)				write(fd, "#:hF#", 5)
+#define turnFieldDeRotatorOn(fd)			write(fd, "#:r+#", 5)
+#define turnFieldDeRotatorOff(fd)			write(fd, "#:r-#", 5)
+#define slewToPark(fd)					write(fd, "#:hP#", 5)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**************************************************************************
+ Basic I/O - OBSELETE
+**************************************************************************/
+/*int openPort(const char *portID);
+int portRead(char *buf, int nbytes, int timeout);
+int portWrite(const char * buf);
+int LX200readOut(int timeout);
+int Connect(const char* device);
+void Disconnect();*/
+
+/**************************************************************************
+ Diagnostics
+ **************************************************************************/
+char ACK(int fd);
+/*int testTelescope();
+int testAP();*/
+int check_lx200_connection(int fd);
+
+/**************************************************************************
+ Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure 
+ **************************************************************************/
+ 
+/* Get Double from Sexagisemal */
+int getCommandSexa(int fd, double *value, const char *cmd);
+/* Get String */
+int getCommandString(int fd, char *data, const char* cmd);
+/* Get Int */
+int getCommandInt(int fd, int *value, const char* cmd);
+/* Get tracking frequency */
+int getTrackFreq(int fd, double * value);
+/* Get site Latitude */
+int getSiteLatitude(int fd, int *dd, int *mm);
+/* Get site Longitude */
+int getSiteLongitude(int fd, int *ddd, int *mm);
+/* Get Calender data */
+int getCalenderDate(int fd, char *date);
+/* Get site Name */
+int getSiteName(int fd, char *siteName, int siteNum);
+/* Get Number of Bars */
+int getNumberOfBars(int fd, int *value);
+/* Get Home Search Status */
+int getHomeSearchStatus(int fd, int *status);
+/* Get OTA Temperature */
+int getOTATemp(int fd, double * value);
+/* Get time format: 12 or 24 */
+int getTimeFormat(int fd, int *format);
+/* Get RA, DEC from Sky Commander controller */
+int updateSkyCommanderCoord(int fd, double *ra, double *dec);
+/* Get RA, DEC from Intelliscope/SkyWizard controllers */
+int updateIntelliscopeCoord (int fd, double *ra, double *dec);
+
+/**************************************************************************
+ Set Commands
+ **************************************************************************/
+
+/* Set Int */
+int setCommandInt(int fd, int data, const char *cmd);
+/* Set Sexigesimal */
+int setCommandXYZ(int fd, int x, int y, int z, const char *cmd);
+/* Common routine for Set commands */
+int setStandardProcedure(int fd, char * writeData);
+/* Set Slew Mode */
+int setSlewMode(int fd, int slewMode);
+/* Set Alignment mode */
+int setAlignmentMode(int fd, unsigned int alignMode);
+/* Set Object RA */
+int setObjectRA(int fd, double ra);
+/* set Object DEC */
+int setObjectDEC(int fd, double dec);
+/* Set Calender date */
+int setCalenderDate(int fd, int dd, int mm, int yy);
+/* Set UTC offset */
+int setUTCOffset(int fd, double hours);
+/* Set Track Freq */
+int setTrackFreq(int fd, double trackF);
+/* Set current site longitude */
+int setSiteLongitude(int fd, double Long);
+/* Set current site latitude */
+int setSiteLatitude(int fd, double Lat);
+/* Set Object Azimuth */
+int setObjAz(int fd, double az);
+/* Set Object Altitude */
+int setObjAlt(int fd, double alt);
+/* Set site name */
+int setSiteName(int fd, char * siteName, int siteNum);
+/* Set maximum slew rate */
+int setMaxSlewRate(int fd, int slewRate);
+/* Set focuser motion */
+int setFocuserMotion(int fd, int motionType);
+/* SET GPS Focuser raneg (1 to 4) */
+int setGPSFocuserSpeed (int fd, int speed);
+/* Set focuser speed mode */
+int setFocuserSpeedMode (int fd, int speedMode);
+/* Set minimum elevation limit */
+int setMinElevationLimit(int fd, int min);
+/* Set maximum elevation limit */
+int setMaxElevationLimit(int fd, int max);
+
+/**************************************************************************
+ Motion Commands
+ **************************************************************************/
+/* Slew to the selected coordinates */
+int Slew(int fd);
+/* Synchronize to the selected coordinates and return the matching object if any */
+int Sync(int fd, char *matchedObject);
+/* Abort slew in all axes */
+int abortSlew(int fd);
+/* Move into one direction, two valid directions can be stacked */
+int MoveTo(int fd, int direction);
+/* Halt movement in a particular direction */
+int HaltMovement(int fd, int direction);
+/* Select the tracking mode */
+int selectTrackingMode(int fd, int trackMode);
+/* Select Astro-Physics tracking mode */
+int selectAPTrackingMode(int fd, int trackMode);
+/* Send Pulse-Guide command (timed guide move), two valid directions can be stacked */
+int SendPulseCmd(int fd, int direction, int duration_msec);
+
+/**************************************************************************
+ Other Commands
+ **************************************************************************/
+ /* Ensures LX200 RA/DEC format is long */
+int checkLX200Format(int fd);
+/* Select a site from the LX200 controller */
+int selectSite(int fd, int siteNum);
+/* Select a catalog object */
+int selectCatalogObject(int fd, int catalog, int NNNN);
+/* Select a sub catalog */
+int selectSubCatalog(int fd, int catalog, int subCatalog);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/lx200generic.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200generic.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200generic.cpp	(revision 500)
@@ -0,0 +1,2233 @@
+#if 0
+    LX200 Generic
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "indicom.h"
+#include "lx200driver.h"
+#include "lx200gps.h"
+#include "lx200ap.h"
+#include "lx200classic.h"
+
+#include <config.h>
+
+#ifdef HAVE_NOVA_H
+#include <libnova.h>
+#endif
+
+LX200Generic *telescope = NULL;
+int MaxReticleFlashRate = 3;
+
+/* There is _one_ binary for all LX200 drivers, but each binary is renamed
+** to its device name (i.e. lx200gps, lx200_16..etc). The main function will
+** fetch from std args the binary name and ISInit will create the apporpiate
+** device afterwards. If the binary name does not match any known devices,
+** we simply create a generic device.
+*/
+extern char* me;
+
+#define COMM_GROUP	"Communication"
+#define BASIC_GROUP	"Main Control"
+#define MOTION_GROUP	"Motion Control"
+#define DATETIME_GROUP	"Date/Time"
+#define SITE_GROUP	"Site Management"
+#define FOCUS_GROUP	"Focus Control"
+
+#define LX200_TRACK	0
+#define LX200_SYNC	1
+
+/* Simulation Parameters */
+#define	SLEWRATE	1		/* slew rate, degrees/s */
+#define SIDRATE		0.004178	/* sidereal rate, degrees/s */
+
+/* Handy Macros */
+#define currentRA	EquatorialCoordsRN[0].value
+#define currentDEC	EquatorialCoordsRN[1].value
+#define targetRA	EquatorialCoordsWN[0].value
+#define targetDEC	EquatorialCoordsWN[1].value
+
+static void ISPoll(void *);
+static void retryConnection(void *);
+
+/*INDI Propertries */
+
+/**********************************************************************************************/
+/************************************ GROUP: Communication ************************************/
+/**********************************************************************************************/
+
+/********************************************
+ Property: Connection
+*********************************************/
+static ISwitch ConnectS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+ISwitchVectorProperty ConnectSP		= { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0};
+
+/********************************************
+ Property: Device Port
+*********************************************/
+/*wildi removed static */
+static IText PortT[]			= {{"PORT", "Port", 0, 0, 0, 0}};
+ITextVectorProperty PortTP	= { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
+
+/********************************************
+ Property: Telescope Alignment Mode
+*********************************************/
+static ISwitch AlignmentS []		= {{"Polar", "", ISS_ON, 0, 0}, {"AltAz", "", ISS_OFF, 0, 0}, {"Land", "", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty AlignmentSw= { mydev, "Alignment", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AlignmentS, NARRAY(AlignmentS), "", 0};
+
+/**********************************************************************************************/
+/************************************ GROUP: Main Control *************************************/
+/**********************************************************************************************/
+
+/********************************************
+ Property: Equatorial Coordinates JNow
+ Perm: Transient WO.
+ Timeout: 120 seconds.
+*********************************************/
+INumber EquatorialCoordsWN[] 		= { {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0} };
+INumberVectorProperty EquatorialCoordsWNP= { mydev, "EQUATORIAL_EOD_COORD_REQUEST", "Equatorial JNow", BASIC_GROUP, IP_WO, 120, IPS_IDLE, EquatorialCoordsWN, NARRAY(EquatorialCoordsWN), "", 0};
+
+/********************************************
+ Property: Equatorial Coordinates JNow
+ Perm: RO
+*********************************************/
+INumber EquatorialCoordsRN[]	 	= { {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}};
+INumberVectorProperty EquatorialCoordsRNP= { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 120, IPS_IDLE, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), "", 0};
+
+/********************************************
+ Property: On Coord Set
+ Description: This property decides what happens
+             when we receive a new equatorial coord
+             value. We either track, or sync
+	     to the new coordinates.
+*********************************************/
+static ISwitch OnCoordSetS[]		 = {{"SLEW", "Slew", ISS_ON, 0, 0 }, {"SYNC", "Sync", ISS_OFF, 0 , 0}};
+ISwitchVectorProperty OnCoordSetSP= { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
+
+/********************************************
+ Property: Abort telescope motion
+*********************************************/
+static ISwitch AbortSlewS[]		= {{"ABORT", "Abort", ISS_OFF, 0, 0 }};
+ISwitchVectorProperty AbortSlewSP= { mydev, "TELESCOPE_ABORT_MOTION", "Abort Slew", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AbortSlewS, NARRAY(AbortSlewS), "", 0};
+
+/**********************************************************************************************/
+/************************************** GROUP: Motion *****************************************/
+/**********************************************************************************************/
+
+/********************************************
+ Property: Slew Speed
+*********************************************/
+static ISwitch SlewModeS[]		= {{"Max", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0 , 0}};
+ISwitchVectorProperty SlewModeSP	= { mydev, "Slew rate", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0};
+
+/********************************************
+ Property: Tracking Mode
+*********************************************/
+static ISwitch TrackModeS[]		= {{ "Default", "", ISS_ON, 0, 0} , { "Lunar", "", ISS_OFF, 0, 0}, {"Manual", "", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty TrackModeSP= { mydev, "Tracking Mode", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0};
+
+/********************************************
+ Property: Tracking Frequency
+*********************************************/
+static INumber TrackFreqN[] 		 = {{ "trackFreq", "Freq", "%g", 56.4, 60.1, 0.1, 60.1, 0, 0, 0}};
+static INumberVectorProperty TrackingFreqNP= { mydev, "Tracking Frequency", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, TrackFreqN, NARRAY(TrackFreqN), "", 0};
+
+/********************************************
+ Property: Movement (Arrow keys on handset). North/South
+*********************************************/
+static ISwitch MovementNSS[]       = {{"MOTION_NORTH", "North", ISS_OFF, 0, 0}, {"MOTION_SOUTH", "South", ISS_OFF, 0, 0}};
+ISwitchVectorProperty MovementNSSP      = { mydev, "TELESCOPE_MOTION_NS", "North/South", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementNSS, NARRAY(MovementNSS), "", 0};
+
+/********************************************
+ Property: Movement (Arrow keys on handset). West/East
+*********************************************/
+static ISwitch MovementWES[]       = {{"MOTION_WEST", "West", ISS_OFF, 0, 0}, {"MOTION_EAST", "East", ISS_OFF, 0, 0}};
+ISwitchVectorProperty MovementWESP      = { mydev, "TELESCOPE_MOTION_WE", "West/East", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0};
+
+/********************************************
+ Property: Timed Guide movement. North/South
+*********************************************/
+static INumber GuideNSN[]       = {{"TIMED_GUIDE_N", "North (sec)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_S", "South (sec)", "%g", 0, 10, 0.001, 0, 0, 0}};
+INumberVectorProperty GuideNSNP      = { mydev, "TELESCOPE_TIMED_GUIDE_NS", "Guide North/South", MOTION_GROUP, IP_RW, 0, IPS_IDLE, GuideNSN, NARRAY(GuideNSN), "", 0};
+
+/********************************************
+ Property: Timed Guide movement. West/East
+*********************************************/
+static INumber GuideWEN[]       = {{"TIMED_GUIDE_W", "West (sec)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_E", "East (sec)", "%g", 0, 10, 0.001, 0, 0, 0}};
+INumberVectorProperty GuideWENP      = { mydev, "TELESCOPE_TIMED_GUIDE_WE", "Guide West/East", MOTION_GROUP, IP_RW, 0, IPS_IDLE, GuideWEN, NARRAY(GuideWEN), "", 0};
+
+/********************************************
+ Property: Slew Accuracy
+ Desciption: How close the scope have to be with
+	     respect to the requested coords for 
+	     the tracking operation to be successull
+	     i.e. returns OK
+*********************************************/
+INumber SlewAccuracyN[] = {
+    {"SlewRA",  "RA (arcmin)", "%g",  0., 60., 1., 3.0, 0, 0, 0},
+    {"SlewkDEC", "Dec (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0},
+};
+INumberVectorProperty SlewAccuracyNP = {mydev, "Slew Accuracy", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, SlewAccuracyN, NARRAY(SlewAccuracyN), "", 0};
+
+/********************************************
+ Property: Use pulse-guide commands
+ Desciption: Set to on if this mount can support
+             pulse guide commands.  There appears to
+             be no way to query this information from
+             the mount
+*********************************************/
+static ISwitch UsePulseCmdS[]		= {{ "Off", "", ISS_ON, 0, 0} , { "On", "", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty UsePulseCmdSP= { mydev, "Use Pulse Cmd", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, UsePulseCmdS, NARRAY(UsePulseCmdS), "", 0};
+
+/**********************************************************************************************/
+/************************************** GROUP: Focus ******************************************/
+/**********************************************************************************************/
+
+/********************************************
+ Property: Focus Direction
+*********************************************/
+ISwitch  FocusMotionS[]	 = { {"IN", "Focus in", ISS_OFF, 0, 0}, {"OUT", "Focus out", ISS_OFF, 0, 0}};
+ISwitchVectorProperty	FocusMotionSP = {mydev, "FOCUS_MOTION", "Motion", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusMotionS, NARRAY(FocusMotionS), "", 0};
+
+/********************************************
+ Property: Focus Timer
+*********************************************/
+INumber  FocusTimerN[]    = { {"TIMER", "Timer (ms)", "%g", 0., 10000., 1000., 50., 0, 0, 0 }};
+INumberVectorProperty FocusTimerNP = { mydev, "FOCUS_TIMER", "Focus Timer", FOCUS_GROUP, IP_RW, 0, IPS_IDLE, FocusTimerN, NARRAY(FocusTimerN), "", 0};
+
+/********************************************
+ Property: Focus Mode
+*********************************************/
+static ISwitch  FocusModeS[]	 = { {"FOCUS_HALT", "Halt", ISS_ON, 0, 0},
+				     {"FOCUS_SLOW", "Slow", ISS_OFF, 0, 0},
+				     {"FOCUS_FAST", "Fast", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty FocusModeSP = {mydev, "FOCUS_MODE", "Mode", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusModeS, NARRAY(FocusModeS), "", 0};
+
+/**********************************************************************************************/
+/*********************************** GROUP: Date & Time ***************************************/
+/**********************************************************************************************/
+
+/********************************************
+ Property: UTC Time
+*********************************************/
+static IText TimeT[] = {{"UTC", "UTC", 0, 0, 0, 0}};
+ITextVectorProperty TimeTP = { mydev, "TIME_UTC", "UTC Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, TimeT, NARRAY(TimeT), "", 0};
+
+/********************************************
+ Property: DST Corrected UTC Offfset
+*********************************************/
+static INumber UTCOffsetN[] = {{"OFFSET", "Offset", "%0.3g" , -12.,12.,0.5,0., 0, 0, 0}};
+INumberVectorProperty UTCOffsetNP = { mydev, "TIME_UTC_OFFSET", "UTC Offset", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, UTCOffsetN , NARRAY(UTCOffsetN), "", 0};
+
+/********************************************
+ Property: Sidereal Time
+*********************************************/
+static INumber SDTimeN[] = {{"LST", "Sidereal time", "%10.6m" , 0.,24.,0.,0., 0, 0, 0}};
+INumberVectorProperty SDTimeNP = { mydev, "TIME_LST", "Sidereal Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, SDTimeN, NARRAY(SDTimeN), "", 0};
+
+/**********************************************************************************************/
+/************************************* GROUP: Sites *******************************************/
+/**********************************************************************************************/
+
+/********************************************
+ Property: Site Management
+*********************************************/
+static ISwitch SitesS[]          = {{"Site 1", "", ISS_ON, 0, 0}, {"Site 2", "", ISS_OFF, 0, 0},  {"Site 3", "", ISS_OFF, 0, 0},  {"Site 4", "", ISS_OFF, 0 ,0}};
+static ISwitchVectorProperty SitesSP  = { mydev, "Sites", "", SITE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SitesS, NARRAY(SitesS), "", 0};
+
+/********************************************
+ Property: Site Name
+*********************************************/
+static IText   SiteNameT[] = {{"Name", "", 0, 0, 0, 0}};
+static ITextVectorProperty SiteNameTP = { mydev, "Site Name", "", SITE_GROUP, IP_RW, 0 , IPS_IDLE, SiteNameT, NARRAY(SiteNameT), "", 0};
+
+/********************************************
+ Property: Geographical Location
+*********************************************/
+
+static INumber geo[] = {
+    {"LAT",  "Lat.  D:M:S +N", "%10.6m",  -90.,  90., 0., 0., 0, 0, 0},
+    {"LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0., 0, 0, 0},
+    {"HEIGHT", "Height m", "%10.2f", -300., 6000., 0., 610., 0, 0, 0},
+};
+INumberVectorProperty geoNP = {
+    mydev, "GEOGRAPHIC_COORD", "Geographic Location", SITE_GROUP, IP_RW, 0., IPS_IDLE,
+    geo, NARRAY(geo), "", 0};
+
+/*****************************************************************************************************/
+/**************************************** END PROPERTIES *********************************************/
+/*****************************************************************************************************/
+
+void changeLX200GenericDeviceName(const char * newName)
+{
+  // COMM_GROUP
+  strcpy(ConnectSP.device , newName);
+  strcpy(PortTP.device , newName);
+  strcpy(AlignmentSw.device, newName);
+
+  // BASIC_GROUP
+  strcpy(EquatorialCoordsWNP.device, newName);
+  strcpy(EquatorialCoordsRNP.device, newName);
+  strcpy(OnCoordSetSP.device , newName );
+  strcpy(AbortSlewSP.device , newName );
+
+  // MOTION_GROUP
+  strcpy(SlewModeSP.device , newName );
+  strcpy(TrackModeSP.device , newName );
+  strcpy(TrackingFreqNP.device , newName );
+  strcpy(MovementNSSP.device , newName );
+  strcpy(MovementWESP.device , newName );
+  strcpy(GuideNSNP.device , newName );
+  strcpy(GuideWENP.device , newName );
+  strcpy(SlewAccuracyNP.device, newName);
+  strcpy(UsePulseCmdSP.device, newName);
+
+  // FOCUS_GROUP
+  strcpy(FocusModeSP.device , newName );
+  strcpy(FocusMotionSP.device , newName );
+  strcpy(FocusTimerNP.device, newName);
+
+  // DATETIME_GROUP
+  strcpy(TimeTP.device , newName );
+  strcpy(UTCOffsetNP.device , newName );
+  strcpy(SDTimeNP.device , newName );
+
+  // SITE_GROUP
+  strcpy(SitesSP.device , newName );
+  strcpy(SiteNameTP.device , newName );
+  strcpy(geoNP.device , newName );
+  
+}
+
+void changeAllDeviceNames(const char *newName)
+{
+  changeLX200GenericDeviceName(newName);
+  changeLX200AutostarDeviceName(newName);
+  changeLX200AstroPhysicsDeviceName(newName);
+  changeLX200_16DeviceName(newName);
+  changeLX200ClassicDeviceName(newName);
+  changeLX200GPSDeviceName(newName);
+}
+
+
+/* send client definitions of all properties */
+void ISInit()
+{
+  static int isInit=0;
+
+ if (isInit)
+  return;
+
+ isInit = 1;
+ 
+  IUSaveText(&PortT[0], "/dev/ttyS0");
+  IUSaveText(&TimeT[0], "YYYY-MM-DDTHH:MM:SS");
+
+  // We need to check if UTCOffset has been set by user or not
+  UTCOffsetN[0].aux0 = (int *) malloc(sizeof(int));
+  *((int *) UTCOffsetN[0].aux0) = 0;
+  
+  
+  if (strstr(me, "indi_lx200classic"))
+  {
+     fprintf(stderr , "initilizaing from LX200 classic device...\n");
+     // 1. mydev = device_name
+     changeAllDeviceNames("LX200 Classic");
+     // 2. device = sub_class
+     telescope = new LX200Classic();
+     telescope->setCurrentDeviceName("LX200 Classic");
+
+     MaxReticleFlashRate = 3;
+  }
+
+  else if (strstr(me, "indi_lx200gps"))
+  {
+     fprintf(stderr , "initilizaing from LX200 GPS device...\n");
+     // 1. mydev = device_name
+     changeAllDeviceNames("LX200 GPS");
+     // 2. device = sub_class
+     telescope = new LX200GPS();
+     telescope->setCurrentDeviceName("LX200 GPS");
+
+     MaxReticleFlashRate = 9;
+  }
+  else if (strstr(me, "indi_lx200_16"))
+  {
+
+    IDLog("Initilizaing from LX200 16 device...\n");
+    // 1. mydev = device_name
+    changeAllDeviceNames("LX200 16");
+    // 2. device = sub_class
+   telescope = new LX200_16();
+   telescope->setCurrentDeviceName("LX200 16");
+
+   MaxReticleFlashRate = 3;
+ }
+ else if (strstr(me, "indi_lx200autostar"))
+ {
+   fprintf(stderr , "initilizaing from autostar device...\n");
+  
+   // 1. change device name
+   changeAllDeviceNames("LX200 Autostar");
+   // 2. device = sub_class
+   telescope = new LX200Autostar();
+   telescope->setCurrentDeviceName("LX200 Autostar");
+
+   MaxReticleFlashRate = 9;
+ }
+ else if (strstr(me, "indi_lx200ap"))
+ {
+   fprintf(stderr , "initilizaing from ap device...\n");
+  
+   // 1. change device name
+   changeAllDeviceNames("LX200 Astro-Physics");
+   // 2. device = sub_class
+   telescope = new LX200AstroPhysics();
+   telescope->setCurrentDeviceName("LX200 Astro-Physics");
+
+   MaxReticleFlashRate = 9;
+ }
+ // be nice and give them a generic device
+ else
+ {
+  telescope = new LX200Generic();
+  telescope->setCurrentDeviceName("LX200 Generic");
+ }
+
+}
+
+void ISGetProperties (const char *dev)
+{ ISInit(); telescope->ISGetProperties(dev); IEAddTimer (POLLMS, ISPoll, NULL);}
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{ ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);}
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{ ISInit(); telescope->ISNewText(dev, name, texts, names, n);}
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{ ISInit(); telescope->ISNewNumber(dev, name, values, names, n);}
+void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;}
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+
+void ISSnoopDevice (XMLEle *root)
+{
+  telescope->ISSnoopDevice(root);
+}
+
+/**************************************************
+*** LX200 Generic Implementation
+***************************************************/
+
+LX200Generic::LX200Generic()
+{
+   currentSiteNum = 1;
+   trackingMode   = LX200_TRACK_DEFAULT;
+   lastSet        = -1;
+   fault          = false;
+   simulation     = false;
+   currentSet     = 0;
+   fd             = -1;
+   GuideNSTID     = 0;
+   GuideWETID     = 0;
+
+   // Children call parent routines, this is the default
+   IDLog("INDI Library v%g\n", INDI_LIBV);
+   IDLog("initilizaing from generic LX200 device...\n");
+   IDLog("Driver Version: 2008-05-21\n");
+ 
+   //enableSimulation(true);  
+}
+
+LX200Generic::~LX200Generic()
+{
+}
+
+void LX200Generic::setCurrentDeviceName(const char * devName)
+{
+  strcpy(thisDevice, devName);
+}
+
+void LX200Generic::ISGetProperties(const char *dev)
+{
+
+ if (dev && strcmp (thisDevice, dev))
+    return;
+
+  // COMM_GROUP
+  IDDefSwitch (&ConnectSP, NULL);
+  IDDefText   (&PortTP, NULL);
+  IDDefSwitch (&AlignmentSw, NULL);
+
+  // BASIC_GROUP
+  IDDefNumber (&EquatorialCoordsWNP, NULL);
+  IDDefNumber (&EquatorialCoordsRNP, NULL);
+  IDDefSwitch (&OnCoordSetSP, NULL);
+  IDDefSwitch (&AbortSlewSP, NULL);
+
+  // MOTION_GROUP
+  IDDefNumber (&TrackingFreqNP, NULL);
+  IDDefSwitch (&SlewModeSP, NULL);
+  IDDefSwitch (&TrackModeSP, NULL);
+  IDDefSwitch (&MovementNSSP, NULL);
+  IDDefSwitch (&MovementWESP, NULL);
+  IDDefNumber (&GuideNSNP, NULL );
+  IDDefNumber (&GuideWENP, NULL );
+  IDDefNumber (&SlewAccuracyNP, NULL);
+  IDDefSwitch (&UsePulseCmdSP, NULL);
+
+  // FOCUS_GROUP
+  IDDefSwitch(&FocusModeSP, NULL);
+  IDDefSwitch(&FocusMotionSP, NULL);
+  IDDefNumber(&FocusTimerNP, NULL);
+
+  // DATETIME_GROUP
+  #ifdef HAVE_NOVA_H
+  IDDefText   (&TimeTP, NULL);
+  IDDefNumber(&UTCOffsetNP, NULL);
+  #endif
+
+  IDDefNumber (&SDTimeNP, NULL);
+
+  // SITE_GROUP
+  IDDefSwitch (&SitesSP, NULL);
+  IDDefText   (&SiteNameTP, NULL);
+  IDDefNumber (&geoNP, NULL);
+  
+  /* Send the basic data to the new client if the previous client(s) are already connected. */		
+   if (ConnectSP.s == IPS_OK)
+       getBasicData();
+
+}
+
+void LX200Generic::ISSnoopDevice (XMLEle *root)
+{
+  INDI_UNUSED(root);
+}
+
+void LX200Generic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	int err;
+	IText *tp;
+
+	// ignore if not ours //
+	if (strcmp (dev, thisDevice))
+	    return;
+
+	// suppress warning
+	n=n;
+
+	if (!strcmp(name, PortTP.name) )
+	{
+	  PortTP.s = IPS_OK;
+	  tp = IUFindText( &PortTP, names[0] );
+	  if (!tp)
+	   return;
+
+	  IUSaveText(&PortTP.tp[0], texts[0]);
+	  IDSetText (&PortTP, NULL);
+	  return;
+	}
+
+	if (!strcmp (name, SiteNameTP.name) )
+	{
+	  if (checkPower(&SiteNameTP))
+	   return;
+
+	  if ( ( err = setSiteName(fd, texts[0], currentSiteNum) < 0) )
+	  {
+	     handleError(&SiteNameTP, err, "Setting site name");
+	     return;
+	  }
+	     SiteNameTP.s = IPS_OK;
+	     tp = IUFindText(&SiteNameTP, names[0]);
+	     tp->text = new char[strlen(texts[0])+1];
+	     strcpy(tp->text, texts[0]);
+   	     IDSetText(&SiteNameTP , "Site name updated");
+	     return;
+       }
+
+       #ifdef HAVE_NOVA_H
+       if (!strcmp (name, TimeTP.name))
+       {
+	  if (checkPower(&TimeTP))
+	   return;
+
+	 if (simulation)
+	 {
+		TimeTP.s = IPS_OK;
+		IUSaveText(&TimeTP.tp[0], texts[0]);
+		IDSetText(&TimeTP, "Simulated time updated.");
+		return;
+	 }
+
+	 struct ln_date utm;
+	 struct ln_zonedate ltm;
+
+        if (*((int *) UTCOffsetN[0].aux0) == 0)
+	{
+		TimeTP.s = IPS_IDLE;
+		IDSetText(&TimeTP, "You must set the UTC Offset property first.");
+		return;
+	}
+
+	  if (extractISOTime(texts[0], &utm) < 0)
+	  {
+	    TimeTP.s = IPS_IDLE;
+	    IDSetText(&TimeTP , "Time invalid");
+	    return;
+	  }
+
+	 // update JD
+         JD = ln_get_julian_day(&utm);
+	 IDLog("New JD is %f\n", (float) JD);
+
+	ln_date_to_zonedate(&utm, &ltm, UTCOffsetN[0].value*3600.0);
+
+	// Set Local Time
+	if ( ( err = setLocalTime(fd, ltm.hours, ltm.minutes, ltm.seconds) < 0) )
+	{
+	          handleError(&TimeTP, err, "Setting local time");
+        	  return;
+	}
+
+	if (!strcmp(dev, "LX200 GPS"))
+	{
+			if ( ( err = setCalenderDate(fd, utm.days, utm.months, utm.years) < 0) )
+	  		{
+		  		handleError(&TimeTP, err, "Setting TimeT date.");
+		  		return;
+			}
+	}
+	else
+	{
+			if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) )
+	  		{
+		  		handleError(&TimeTP, err, "Setting local date.");
+		  		return;
+			}
+	}
+	
+	// Everything Ok, save time value	
+	if (IUUpdateText(&TimeTP, texts, names, n) < 0)
+		return;
+
+	TimeTP.s = IPS_OK;
+ 	IDSetText(&TimeTP , "Time updated to %s, updating planetary data...", texts[0]);
+
+	// Also update telescope's sidereal time
+	getSDTime(fd, &SDTimeN[0].value);
+	IDSetNumber(&SDTimeNP, NULL);
+	}
+	#endif
+}
+
+
+void LX200Generic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+	int h =0, m =0, s=0, err;
+	double newRA =0, newDEC =0;
+	
+	// ignore if not ours //
+	if (strcmp (dev, thisDevice))
+	    return;
+
+        // Slewing Accuracy
+        if (!strcmp (name, SlewAccuracyNP.name))
+	{
+		if (!IUUpdateNumber(&SlewAccuracyNP, values, names, n))
+		{
+			SlewAccuracyNP.s = IPS_OK;
+			IDSetNumber(&SlewAccuracyNP, NULL);
+			return;
+		}
+		
+		SlewAccuracyNP.s = IPS_ALERT;
+		IDSetNumber(&SlewAccuracyNP, "unknown error while setting tracking precision");
+		return;
+	}
+
+	#ifdef HAVE_NOVA_H
+	// DST Correct TimeT Offset
+	if (!strcmp (name, UTCOffsetNP.name))
+	{
+		if (strcmp(names[0], UTCOffsetN[0].name))
+		{
+			UTCOffsetNP.s = IPS_ALERT;
+			IDSetNumber( &UTCOffsetNP , "Unknown element %s for property %s.", names[0], UTCOffsetNP.label);
+			return;
+		}
+
+		if (!simulation)
+			if ( ( err = setUTCOffset(fd, (values[0] * -1.0)) < 0) )
+			{
+		        	UTCOffsetNP.s = IPS_ALERT;
+	        		IDSetNumber( &UTCOffsetNP , "Setting UTC Offset failed.");
+				return;
+			}
+		
+		*((int *) UTCOffsetN[0].aux0) = 1;
+		IUUpdateNumber(&UTCOffsetNP, values, names, n);
+		UTCOffsetNP.s = IPS_OK;
+		IDSetNumber(&UTCOffsetNP, NULL);
+		return;
+	}
+	#endif
+
+	if (!strcmp (name, EquatorialCoordsWNP.name))
+	{
+	  int i=0, nset=0;
+
+	  if (checkPower(&EquatorialCoordsWNP))
+	   return;
+
+	    for (nset = i = 0; i < n; i++)
+	    {
+		INumber *eqp = IUFindNumber (&EquatorialCoordsWNP, names[i]);
+		if (eqp == &EquatorialCoordsWN[0])
+		{
+                    newRA = values[i];
+		    nset += newRA >= 0 && newRA <= 24.0;
+		} else if (eqp == &EquatorialCoordsWN[1])
+		{
+		    newDEC = values[i];
+		    nset += newDEC >= -90.0 && newDEC <= 90.0;
+		}
+	    }
+
+	  if (nset == 2)
+	  {
+	   /*EquatorialCoordsWNP.s = IPS_BUSY;*/
+	   char RAStr[32], DecStr[32];
+
+	   fs_sexa(RAStr, newRA, 2, 3600);
+	   fs_sexa(DecStr, newDEC, 2, 3600);
+	  
+           #ifdef INDI_DEBUG
+	   IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC);
+	   IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr);
+	   #endif
+
+	  if (!simulation)
+	   if ( (err = setObjectRA(fd, newRA)) < 0 || ( err = setObjectDEC(fd, newDEC)) < 0)
+	   {
+	     EquatorialCoordsWNP.s = IPS_ALERT ;
+	     IDSetNumber(&EquatorialCoordsWNP, NULL);
+	     handleError(&EquatorialCoordsWNP, err, "Setting RA/DEC");
+	     return;
+	   } 
+	   /* wildi In principle this line is according to the discussion */
+	   /* In case the telescope is slewing, we have to abort that. No status change here */
+           /* EquatorialCoordsWNP.s = IPS_OK; */
+           IDSetNumber(&EquatorialCoordsWNP, NULL);
+	   targetRA  = newRA;
+	   targetDEC = newDEC;
+
+	   if (handleCoordSet())
+	   {
+	     EquatorialCoordsWNP.s = IPS_ALERT;
+	     IDSetNumber(&EquatorialCoordsWNP, NULL);
+	   }
+	} // end nset
+	else
+	{
+		EquatorialCoordsWNP.s = IPS_ALERT;
+		IDSetNumber(&EquatorialCoordsWNP, "RA or Dec missing or invalid");
+	}
+
+	    return;
+     } /* end EquatorialCoordsWNP */
+
+	// Update Sidereal Time
+        if ( !strcmp (name, SDTimeNP.name) )
+	{
+	  if (checkPower(&SDTimeNP))
+	   return;
+
+
+	  if (values[0] < 0.0 || values[0] > 24.0)
+	  {
+	    SDTimeNP.s = IPS_IDLE;
+	    IDSetNumber(&SDTimeNP , "Time invalid");
+	    return;
+	  }
+
+	  getSexComponents(values[0], &h, &m, &s);
+	  IDLog("Siderial Time is %02d:%02d:%02d\n", h, m, s);
+	  
+	  if ( ( err = setSDTime(fd, h, m, s) < 0) )
+	  {
+	    handleError(&SDTimeNP, err, "Setting siderial time"); 
+            return;
+	  }
+	  
+	  SDTimeNP.np[0].value = values[0];
+	  SDTimeNP.s = IPS_OK;
+
+	  IDSetNumber(&SDTimeNP , "Sidereal time updated to %02d:%02d:%02d", h, m, s);
+
+	  return;
+        }
+
+	// Update Geographical Location
+	if (!strcmp (name, geoNP.name))
+	{
+	    // new geographic coords
+	    double newLong = 0, newLat = 0;
+	    int i, nset;
+	    char msg[128];
+
+	  if (checkPower(&geoNP))
+	   return;
+
+
+	    for (nset = i = 0; i < n; i++)
+	    {
+		INumber *geop = IUFindNumber (&geoNP, names[i]);
+		if (geop == &geo[0])
+		{
+		    newLat = values[i];
+		    nset += newLat >= -90.0 && newLat <= 90.0;
+		} else if (geop == &geo[1])
+		{
+		    newLong = values[i];
+		    nset += newLong >= 0.0 && newLong < 360.0;
+		}
+	    }
+
+	    if (nset == 2)
+	    {
+		char l[32], L[32];
+		geoNP.s = IPS_OK;
+		fs_sexa (l, newLat, 3, 3600);
+		fs_sexa (L, newLong, 4, 3600);
+		
+		if (!simulation)
+		{
+			if ( ( err = setSiteLongitude(fd, 360.0 - newLong) < 0) )
+	        	{	
+		   		handleError(&geoNP, err, "Setting site longitude coordinates");	
+		   		return;
+	         	}	
+			if ( ( err = setSiteLatitude(fd, newLat) < 0) )
+	        	{
+		   		handleError(&geoNP, err, "Setting site latitude coordinates");
+		   		return;
+	        	}
+		}
+		
+		geoNP.np[0].value = newLat;
+		geoNP.np[1].value = newLong;
+		snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L);
+	    } else
+	    {
+		geoNP.s = IPS_IDLE;
+		strcpy(msg, "Lat or Long missing or invalid");
+	    }
+	    IDSetNumber (&geoNP, "%s", msg);
+	    return;
+	}
+
+	// Update Frequency
+	if ( !strcmp (name, TrackingFreqNP.name) )
+	{
+
+	 if (checkPower(&TrackingFreqNP))
+	  return;
+
+	  IDLog("Trying to set track freq of: %f\n", values[0]);
+
+	  if ( ( err = setTrackFreq(fd, values[0])) < 0) 
+	  {
+             handleError(&TrackingFreqNP, err, "Setting tracking frequency");
+	     return;
+	 }
+	 
+	 TrackingFreqNP.s = IPS_OK;
+	 TrackingFreqNP.np[0].value = values[0];
+	 IDSetNumber(&TrackingFreqNP, "Tracking frequency set to %04.1f", values[0]);
+	 if (trackingMode != LX200_TRACK_MANUAL)
+	 {
+	      trackingMode = LX200_TRACK_MANUAL;
+	      TrackModeS[0].s = ISS_OFF;
+	      TrackModeS[1].s = ISS_OFF;
+	      TrackModeS[2].s = ISS_ON;
+	      TrackModeSP.s   = IPS_OK;
+	      selectTrackingMode(fd, trackingMode);
+	      IDSetSwitch(&TrackModeSP, NULL);
+	 }
+	 
+	  return;
+	}
+	
+	if (!strcmp(name, FocusTimerNP.name))
+	{
+	  if (checkPower(&FocusTimerNP))
+	   return;
+	   
+	  // Don't update if busy
+	  if (FocusTimerNP.s == IPS_BUSY)
+	   return;
+	   
+	  IUUpdateNumber(&FocusTimerNP, values, names, n);
+	  
+	  FocusTimerNP.s = IPS_OK;
+	  
+	  IDSetNumber(&FocusTimerNP, NULL);
+	  IDLog("Setting focus timer to %g\n", FocusTimerN[0].value);
+	  
+	  return;
+
+	}
+
+	if (!strcmp(name, GuideNSNP.name))
+	{
+	  long direction;
+	  int duration_msec;
+	  int use_pulse_cmd;
+	  if (checkPower(&GuideNSNP))
+	   return;
+	  if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
+	  {
+		handleError(&GuideNSNP, err, "Can't guide while moving");
+		return;
+	  }
+	  if (GuideNSNP.s == IPS_BUSY)
+	  {
+		// Already guiding so stop before restarting timer
+		HaltMovement(fd, LX200_NORTH);
+		HaltMovement(fd, LX200_SOUTH);
+	  }
+	  if (GuideNSTID) {
+		IERmTimer(GuideNSTID);
+		GuideNSTID = 0;
+	  }
+	  IUUpdateNumber(&GuideNSNP, values, names, n);
+
+	  if (GuideNSNP.np[0].value > 0) {
+		duration_msec = GuideNSNP.np[0].value * 1000;
+		direction = LX200_NORTH;
+	  } else {
+		duration_msec = GuideNSNP.np[1].value * 1000;
+		direction = LX200_SOUTH;
+	  }
+	  if (duration_msec <= 0) {
+		GuideNSNP.s = IPS_IDLE;
+		IDSetNumber (&GuideNSNP, NULL);
+		return;
+	  }
+	  use_pulse_cmd = getOnSwitch(&UsePulseCmdSP);
+	  // fprintf(stderr, "Using %s mode to move %dmsec %s\n",
+	  //         use_pulse_cmd ? "Pulse" : "Legacy",
+	  //         duration_msec, direction == LX200_NORTH ? "North" : "South");
+	  if (use_pulse_cmd) {
+		SendPulseCmd(fd, direction, duration_msec);
+	  } else {
+		if ( ( err = setSlewMode(fd, LX200_SLEW_GUIDE) < 0) )
+		{
+			handleError(&SlewModeSP, err, "Setting slew mode");
+			return;
+		}
+		MoveTo(fd, direction);
+	  }
+	  GuideNSTID = IEAddTimer (duration_msec, guideTimeout, (void *)direction);
+	  GuideNSNP.s = IPS_BUSY;
+	  IDSetNumber(&GuideNSNP, NULL);
+	}
+	if (!strcmp(name, GuideWENP.name))
+	{
+	  long direction;
+	  int duration_msec;
+	  int use_pulse_cmd;
+
+	  if (checkPower(&GuideWENP))
+	   return;
+	  if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
+	  {
+		handleError(&GuideWENP, err, "Can't guide while moving");
+		return;
+	  }
+	  if (GuideWENP.s == IPS_BUSY)
+	  {
+		// Already guiding so stop before restarting timer
+		HaltMovement(fd, LX200_WEST);
+		HaltMovement(fd, LX200_EAST);
+	  }
+	  if (GuideWETID) {
+		IERmTimer(GuideWETID);
+		GuideWETID = 0;
+	  }
+	  IUUpdateNumber(&GuideWENP, values, names, n);
+
+	  if (GuideWENP.np[0].value > 0) {
+		duration_msec = GuideWENP.np[0].value * 1000;
+		direction = LX200_WEST;
+	  } else {
+		duration_msec = GuideWENP.np[1].value * 1000;
+		direction = LX200_EAST;
+	  }
+	  if (duration_msec <= 0) {
+		GuideWENP.s = IPS_IDLE;
+		IDSetNumber (&GuideWENP, NULL);
+		return;
+	  }
+	  use_pulse_cmd = getOnSwitch(&UsePulseCmdSP);
+	  // fprintf(stderr, "Using %s mode to move %dmsec %s\n",
+	  //         use_pulse_cmd ? "Pulse" : "Legacy",
+          //         duration_msec, direction == LX200_WEST ? "West" : "East");
+	  
+	  if (use_pulse_cmd) {
+		SendPulseCmd(fd, direction, duration_msec);
+	  } else {
+		if ( ( err = setSlewMode(fd, LX200_SLEW_GUIDE) < 0) )
+		{
+			handleError(&SlewModeSP, err, "Setting slew mode");
+			return;
+		}
+		MoveTo(fd, direction);
+	  }
+	  GuideWETID = IEAddTimer (duration_msec, guideTimeout, (void *)direction);
+	  GuideWENP.s = IPS_BUSY;
+	  IDSetNumber(&GuideWENP, NULL);
+	}
+}
+
+void LX200Generic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	int err=0, index=0;
+	INDI_UNUSED(names);
+
+	// ignore if not ours //
+	if (strcmp (thisDevice, dev))
+	    return;
+
+	// FIRST Switch ALWAYS for power
+	if (!strcmp (name, ConnectSP.name))
+	{
+         bool connectionEstablished = (ConnectS[0].s == ISS_ON);
+	 if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return;
+	 if ( (connectionEstablished && ConnectS[0].s == ISS_ON) || (!connectionEstablished && ConnectS[1].s == ISS_ON))
+	 {
+		ConnectSP.s = IPS_OK;
+		IDSetSwitch(&ConnectSP, NULL);
+		return;
+	 }
+   	 connectTelescope();
+	 return;
+	}
+
+	// Coord set
+	if (!strcmp(name, OnCoordSetSP.name))
+	{
+  	  if (checkPower(&OnCoordSetSP))
+	   return;
+
+	  if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return;
+	  currentSet = getOnSwitch(&OnCoordSetSP);
+	  OnCoordSetSP.s = IPS_OK;
+	  IDSetSwitch(&OnCoordSetSP, NULL);
+	}
+	
+	// Abort Slew
+	if (!strcmp (name, AbortSlewSP.name))
+	{
+	  if (checkPower(&AbortSlewSP))
+	  {
+	    AbortSlewSP.s = IPS_IDLE;
+	    IDSetSwitch(&AbortSlewSP, NULL);
+	    return;
+	  }
+	  
+	  IUResetSwitch(&AbortSlewSP);
+	  if (abortSlew(fd) < 0)
+	  {
+		AbortSlewSP.s = IPS_ALERT;
+		IDSetSwitch(&AbortSlewSP, NULL);
+		return;
+	  }
+
+	    if (EquatorialCoordsWNP.s == IPS_BUSY)
+	    {
+		AbortSlewSP.s = IPS_OK;
+		EquatorialCoordsWNP.s       = IPS_IDLE;
+		IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+		IDSetNumber(&EquatorialCoordsWNP, NULL);
+            }
+	    else if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
+	    {
+		MovementNSSP.s  = MovementWESP.s =  IPS_IDLE; 
+	
+		AbortSlewSP.s = IPS_OK;		
+		EquatorialCoordsWNP.s       = IPS_IDLE;
+		IUResetSwitch(&MovementNSSP);
+		IUResetSwitch(&MovementWESP);
+		IUResetSwitch(&AbortSlewSP);
+
+		IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+		IDSetSwitch(&MovementNSSP, NULL);
+		IDSetSwitch(&MovementWESP, NULL);
+		IDSetNumber(&EquatorialCoordsWNP, NULL);
+	    }
+	    else if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY)
+	    {
+		GuideNSNP.s  = GuideWENP.s =  IPS_IDLE; 
+		GuideNSN[0].value = GuideNSN[1].value = 0.0;
+		GuideWEN[0].value = GuideWEN[1].value = 0.0;
+		if (GuideNSTID) {
+			IERmTimer(GuideNSTID);
+			GuideNSTID = 0;
+		}
+		if (GuideWETID) {
+			IERmTimer(GuideWETID);
+			GuideNSTID = 0;
+		}
+
+		AbortSlewSP.s = IPS_OK;
+		EquatorialCoordsWNP.s       = IPS_IDLE;
+		IUResetSwitch(&AbortSlewSP);
+
+		IDSetSwitch(&AbortSlewSP, "Guide aborted.");
+		IDSetNumber(&GuideNSNP, NULL);
+		IDSetNumber(&GuideWENP, NULL);
+		IDSetNumber(&EquatorialCoordsWNP, NULL);
+	    }
+	    else
+	    {
+	        AbortSlewSP.s = IPS_OK;
+	        IDSetSwitch(&AbortSlewSP, NULL);
+	    }
+
+	    return;
+	}
+
+	// Alignment
+	if (!strcmp (name, AlignmentSw.name))
+	{
+	  if (checkPower(&AlignmentSw))
+	   return;
+
+	  if (IUUpdateSwitch(&AlignmentSw, states, names, n) < 0) return;
+	  index = getOnSwitch(&AlignmentSw);
+
+	  if ( ( err = setAlignmentMode(fd, index) < 0) )
+	  {
+	     handleError(&AlignmentSw, err, "Setting alignment");
+             return;
+	  }
+	  
+	  AlignmentSw.s = IPS_OK;
+          IDSetSwitch (&AlignmentSw, NULL);
+	  return;
+
+	}
+
+        // Sites
+	if (!strcmp (name, SitesSP.name))
+	{
+	  int dd=0, mm=0;
+
+	  if (checkPower(&SitesSP))
+	   return;
+
+	  if (IUUpdateSwitch(&SitesSP, states, names, n) < 0) return;
+	  currentSiteNum = getOnSwitch(&SitesSP) + 1;
+	  
+	  if ( ( err = selectSite(fd, currentSiteNum) < 0) )
+	  {
+   	      handleError(&SitesSP, err, "Selecting sites");
+	      return;
+	  }
+
+	  if ( ( err = getSiteLatitude(fd, &dd, &mm) < 0))
+	  {
+	      handleError(&SitesSP, err, "Selecting sites");
+	      return;
+	  }
+
+	  if (dd > 0) geoNP.np[0].value = dd + mm / 60.0;
+	  else geoNP.np[0].value = dd - mm / 60.0;
+	  
+	  if ( ( err = getSiteLongitude(fd, &dd, &mm) < 0))
+	  {
+	        handleError(&SitesSP, err, "Selecting sites");
+		return;
+	  }
+	  
+	  if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm / 60.0);
+	  else geoNP.np[1].value = (dd - mm / 60.0) * -1.0;
+	  
+	  getSiteName(fd, SiteNameTP.tp[0].text, currentSiteNum);
+
+	  IDLog("Selecting site %d\n", currentSiteNum);
+	  
+	  geoNP.s = SiteNameTP.s = SitesSP.s = IPS_OK;
+
+	  IDSetNumber (&geoNP, NULL);
+	  IDSetText   (&SiteNameTP, NULL);
+          IDSetSwitch (&SitesSP, NULL);
+	  return;
+	}
+
+	// Focus Motion
+	if (!strcmp (name, FocusMotionSP.name))
+	{
+	  if (checkPower(&FocusMotionSP))
+	   return;
+
+	  // If mode is "halt"
+	  if (FocusModeS[0].s == ISS_ON)
+	  {
+	    FocusMotionSP.s = IPS_IDLE;
+	    IDSetSwitch(&FocusMotionSP, NULL);
+	    return;
+	  }
+	  
+	  if (IUUpdateSwitch(&FocusMotionSP, states, names, n) < 0) return;
+	  index = getOnSwitch(&FocusMotionSP);
+	  
+	  if ( ( err = setFocuserMotion(fd, index) < 0) )
+	  {
+	     handleError(&FocusMotionSP, err, "Setting focuser speed");
+             return;
+	  }
+
+	  FocusMotionSP.s = IPS_BUSY;
+	  
+	  // with a timer 
+	  if (FocusTimerN[0].value > 0)  
+	  {
+	     FocusTimerNP.s  = IPS_BUSY;
+	     IEAddTimer(50, LX200Generic::updateFocusTimer, this);
+	  }
+	  
+	  IDSetSwitch(&FocusMotionSP, NULL);
+	  return;
+	}
+
+	// Slew mode
+	if (!strcmp (name, SlewModeSP.name))
+	{
+	  if (checkPower(&SlewModeSP))
+	   return;
+
+	  if (IUUpdateSwitch(&SlewModeSP, states, names, n) < 0) return;
+	  index = getOnSwitch(&SlewModeSP);
+	   
+	  if ( ( err = setSlewMode(fd, index) < 0) )
+	  {
+              handleError(&SlewModeSP, err, "Setting slew mode");
+              return;
+	  }
+	  
+          SlewModeSP.s = IPS_OK;
+	  IDSetSwitch(&SlewModeSP, NULL);
+	  return;
+	}
+
+	// Movement (North/South)
+	if (!strcmp (name, MovementNSSP.name))
+	{
+	  if (checkPower(&MovementNSSP))
+	   return;
+	  if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY)
+	  {
+              handleError(&MovementNSSP, err, "Can't move while guiding");
+	      return;
+	  }
+
+	 int last_move=-1;
+         int current_move = -1;
+
+	// -1 means all off previously
+	 last_move = getOnSwitch(&MovementNSSP);
+
+	 if (IUUpdateSwitch(&MovementNSSP, states, names, n) < 0)
+		return;
+
+	current_move = getOnSwitch(&MovementNSSP);
+
+	// Previosuly active switch clicked again, so let's stop.
+	if (current_move == last_move)
+	{
+		HaltMovement(fd, (current_move == 0) ? LX200_NORTH : LX200_SOUTH);
+		IUResetSwitch(&MovementNSSP);
+	    	MovementNSSP.s = IPS_IDLE;
+	    	IDSetSwitch(&MovementNSSP, NULL);
+		return;
+	}
+
+	#ifdef INDI_DEBUG
+        IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
+	#endif
+
+	// 0 (North) or 1 (South)
+	last_move      = current_move;
+
+	// Correction for LX200 Driver: North 0 - South 3
+	current_move = (current_move == 0) ? LX200_NORTH : LX200_SOUTH;
+
+        if ( ( err = MoveTo(fd, current_move) < 0) )
+	{
+	        	 handleError(&MovementNSSP, err, "Setting motion direction");
+ 		 	return;
+	}
+	
+	  MovementNSSP.s = IPS_BUSY;
+	  IDSetSwitch(&MovementNSSP, "Moving toward %s", (current_move == LX200_NORTH) ? "North" : "South");
+	  return;
+	}
+
+	// Movement (West/East)
+	if (!strcmp (name, MovementWESP.name))
+	{
+	  if (checkPower(&MovementWESP))
+	   return;
+	  if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY)
+	  {
+              handleError(&MovementWESP, err, "Can't move while guiding");
+	      return;
+	  }
+
+	 int last_move=-1;
+         int current_move = -1;
+
+	// -1 means all off previously
+	 last_move = getOnSwitch(&MovementWESP);
+
+	 if (IUUpdateSwitch(&MovementWESP, states, names, n) < 0)
+		return;
+
+	current_move = getOnSwitch(&MovementWESP);
+
+	// Previosuly active switch clicked again, so let's stop.
+	if (current_move == last_move)
+	{
+		HaltMovement(fd, (current_move ==0) ? LX200_WEST : LX200_EAST);
+		IUResetSwitch(&MovementWESP);
+	    	MovementWESP.s = IPS_IDLE;
+	    	IDSetSwitch(&MovementWESP, NULL);
+		return;
+	}
+
+	#ifdef INDI_DEBUG
+        IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move);
+	#endif
+
+	// 0 (West) or 1 (East)
+	last_move      = current_move;
+
+	// Correction for LX200 Driver: West 1 - East 2
+	current_move = (current_move == 0) ? LX200_WEST : LX200_EAST;
+
+        if ( ( err = MoveTo(fd, current_move) < 0) )
+	{
+	        	 handleError(&MovementWESP, err, "Setting motion direction");
+ 		 	return;
+	}
+	
+	  MovementWESP.s = IPS_BUSY;
+	  IDSetSwitch(&MovementWESP, "Moving toward %s", (current_move == LX200_WEST) ? "West" : "East");
+	  return;
+	}
+
+	// Tracking mode
+	if (!strcmp (name, TrackModeSP.name))
+	{
+	  if (checkPower(&TrackModeSP))
+	   return;
+
+	  IUResetSwitch(&TrackModeSP);
+	  IUUpdateSwitch(&TrackModeSP, states, names, n);
+	  trackingMode = getOnSwitch(&TrackModeSP);
+	  
+	  if ( ( err = selectTrackingMode(fd, trackingMode) < 0) )
+	  {
+	         handleError(&TrackModeSP, err, "Setting tracking mode.");
+		 return;
+	  }
+	  
+          getTrackFreq(fd, &TrackFreqN[0].value);
+	  TrackModeSP.s = IPS_OK;
+	  IDSetNumber(&TrackingFreqNP, NULL);
+	  IDSetSwitch(&TrackModeSP, NULL);
+	  return;
+	}
+
+        // Focus speed
+	if (!strcmp (name, FocusModeSP.name))
+	{
+	  if (checkPower(&FocusModeSP))
+	   return;
+
+	  IUResetSwitch(&FocusModeSP);
+	  IUUpdateSwitch(&FocusModeSP, states, names, n);
+
+	  index = getOnSwitch(&FocusModeSP);
+
+	  /* disable timer and motion */
+	  if (index == 0)
+	  {
+	    IUResetSwitch(&FocusMotionSP);
+	    FocusMotionSP.s = IPS_IDLE;
+	    FocusTimerNP.s  = IPS_IDLE;
+	    IDSetSwitch(&FocusMotionSP, NULL);
+	    IDSetNumber(&FocusTimerNP, NULL);
+	  }
+	    
+	  setFocuserSpeedMode(fd, index);
+	  FocusModeSP.s = IPS_OK;
+	  IDSetSwitch(&FocusModeSP, NULL);
+	  return;
+	}
+
+        // Pulse-Guide command support
+	if (!strcmp (name, UsePulseCmdSP.name))
+	{
+	  if (checkPower(&UsePulseCmdSP))
+	   return;
+
+	  IUResetSwitch(&UsePulseCmdSP);
+	  IUUpdateSwitch(&UsePulseCmdSP, states, names, n);
+
+	  UsePulseCmdSP.s = IPS_OK;
+	  IDSetSwitch(&UsePulseCmdSP, NULL);
+	  return;
+	}
+}
+
+void LX200Generic::handleError(ISwitchVectorProperty *svp, int err, const char *msg)
+{
+  
+  svp->s = IPS_ALERT;
+  
+  /* First check to see if the telescope is connected */
+    if (check_lx200_connection(fd))
+    {
+      /* The telescope is off locally */
+      ConnectS[0].s = ISS_OFF;
+      ConnectS[1].s = ISS_ON;
+      ConnectSP.s = IPS_BUSY;
+      IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
+      
+      IDSetSwitch(svp, NULL);
+      IEAddTimer(10000, retryConnection, &fd);
+      return;
+    }
+    
+   /* If the error is a time out, then the device doesn't support this property or busy*/
+      if (err == -2)
+      {
+       svp->s = IPS_ALERT;
+       IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
+      }
+      else
+    /* Changing property failed, user should retry. */
+       IDSetSwitch( svp , "%s failed.", msg);
+       
+       fault = true;
+}
+
+void LX200Generic::handleError(INumberVectorProperty *nvp, int err, const char *msg)
+{
+  
+  nvp->s = IPS_ALERT;
+  
+  /* First check to see if the telescope is connected */
+    if (check_lx200_connection(fd))
+    {
+      /* The telescope is off locally */
+      ConnectS[0].s = ISS_OFF;
+      ConnectS[1].s = ISS_ON;
+      ConnectSP.s = IPS_BUSY;
+      IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
+      
+      IDSetNumber(nvp, NULL);
+      IEAddTimer(10000, retryConnection, &fd);
+      return;
+    }
+    
+   /* If the error is a time out, then the device doesn't support this property */
+      if (err == -2)
+      {
+       nvp->s = IPS_ALERT;
+       IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
+      }
+      else
+    /* Changing property failed, user should retry. */
+       IDSetNumber( nvp , "%s failed.", msg);
+       
+       fault = true;
+}
+
+void LX200Generic::handleError(ITextVectorProperty *tvp, int err, const char *msg)
+{
+  
+  tvp->s = IPS_ALERT;
+  
+  /* First check to see if the telescope is connected */
+    if (check_lx200_connection(fd))
+    {
+      /* The telescope is off locally */
+      ConnectS[0].s = ISS_OFF;
+      ConnectS[1].s = ISS_ON;
+      ConnectSP.s = IPS_BUSY;
+      IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds.");
+      
+      IDSetText(tvp, NULL);
+      IEAddTimer(10000, retryConnection, &fd);
+      return;
+    }
+    
+   /* If the error is a time out, then the device doesn't support this property */
+      if (err == -2)
+      {
+       tvp->s = IPS_ALERT;
+       IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
+      }
+       
+      else
+    /* Changing property failed, user should retry. */
+       IDSetText( tvp , "%s failed.", msg);
+       
+       fault = true;
+}
+
+ void LX200Generic::correctFault()
+ {
+ 
+   fault = false;
+   IDMessage(thisDevice, "Telescope is online.");
+   
+ }
+
+bool LX200Generic::isTelescopeOn(void)
+{
+  //if (simulation) return true;
+  
+  return (ConnectSP.sp[0].s == ISS_ON);
+}
+
+static void retryConnection(void * p)
+{
+  int fd = *( (int *) p);
+  
+  if (check_lx200_connection(fd))
+  {
+    ConnectSP.s = IPS_IDLE;
+    IDSetSwitch(&ConnectSP, "The connection to the telescope is lost.");
+    return;
+  }
+  
+  ConnectS[0].s = ISS_ON;
+  ConnectS[1].s = ISS_OFF;
+  ConnectSP.s = IPS_OK;
+   
+  IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed.");
+
+}
+
+void LX200Generic::updateFocusTimer(void *p)
+{
+   int err=0;
+
+    switch (FocusTimerNP.s)
+    {
+
+      case IPS_IDLE:
+	   break;
+	     
+      case IPS_BUSY:
+      IDLog("Focus Timer Value is %g\n", FocusTimerN[0].value);
+	    FocusTimerN[0].value-=50;
+	    
+	    if (FocusTimerN[0].value <= 0)
+	    {
+	      IDLog("Focus Timer Expired\n");
+	      if ( ( err = setFocuserSpeedMode(telescope->fd, 0) < 0) )
+              {
+	        telescope->handleError(&FocusModeSP, err, "setting focuser mode");
+                IDLog("Error setting focuser mode\n");
+                return;
+	      } 
+         
+	      
+	      FocusMotionSP.s = IPS_IDLE;
+	      FocusTimerNP.s  = IPS_OK;
+	      FocusModeSP.s   = IPS_OK;
+	      
+              IUResetSwitch(&FocusMotionSP);
+              IUResetSwitch(&FocusModeSP);
+	      FocusModeS[0].s = ISS_ON;
+	      
+	      IDSetSwitch(&FocusModeSP, NULL);
+	      IDSetSwitch(&FocusMotionSP, NULL);
+	    }
+	    
+         IDSetNumber(&FocusTimerNP, NULL);
+
+	  if (FocusTimerN[0].value > 0)
+		IEAddTimer(50, LX200Generic::updateFocusTimer, p);
+	    break;
+	    
+       case IPS_OK:
+	    break;
+	    
+	case IPS_ALERT:
+	    break;
+     }
+
+}
+
+void LX200Generic::guideTimeout(void *p)
+{
+    long direction = (long)p;
+    int use_pulse_cmd;
+
+    use_pulse_cmd = telescope->getOnSwitch(&UsePulseCmdSP);
+    if (direction == -1)
+    {
+	HaltMovement(telescope->fd, LX200_NORTH);
+	HaltMovement(telescope->fd, LX200_SOUTH);
+	HaltMovement(telescope->fd, LX200_EAST);
+	HaltMovement(telescope->fd, LX200_WEST);
+	IERmTimer(telescope->GuideNSTID);
+	IERmTimer(telescope->GuideWETID);
+	
+    }
+    else if (! use_pulse_cmd)
+    {
+	HaltMovement(telescope->fd, direction);
+    }
+    if (direction == LX200_NORTH || direction == LX200_SOUTH || direction == -1)
+    {
+        GuideNSNP.np[0].value = 0;
+        GuideNSNP.np[1].value = 0;
+	GuideNSNP.s = IPS_IDLE;
+	telescope->GuideNSTID = 0;
+	IDSetNumber(&GuideNSNP, NULL);
+    }
+    if (direction == LX200_WEST || direction == LX200_EAST || direction == -1)
+    {
+        GuideWENP.np[0].value = 0;
+        GuideWENP.np[1].value = 0;
+	GuideWENP.s = IPS_IDLE;
+	telescope->GuideWETID = 0;
+	IDSetNumber(&GuideWENP, NULL);
+    }
+}
+
+void LX200Generic::ISPoll()
+{
+        double dx, dy;
+	/*static int okCounter = 3;*/
+	int err=0;
+	
+	if (!isTelescopeOn())
+	 return;
+
+	if (simulation)
+	{
+		mountSim();
+		return;
+        }
+
+	if ( (err = getLX200RA(fd, &currentRA)) < 0 || (err = getLX200DEC(fd, &currentDEC)) < 0)
+	{
+	  EquatorialCoordsRNP.s = IPS_ALERT;
+	  IDSetNumber(&EquatorialCoordsRNP, NULL);
+	  handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC");
+	  return;
+	}
+	
+	if (fault)
+	  correctFault();
+
+	EquatorialCoordsRNP.s = IPS_OK;
+
+	if ( fabs(lastRA - currentRA) > (SlewAccuracyN[0].value/(60.0*15.0)) || fabs(lastDEC - currentDEC) > (SlewAccuracyN[1].value/60.0))
+	{
+	  	lastRA  = currentRA;
+		lastDEC = currentDEC;
+		IDSetNumber (&EquatorialCoordsRNP, NULL);
+	}
+
+	switch (EquatorialCoordsWNP.s)
+	{
+	case IPS_IDLE:
+        break;
+
+        case IPS_BUSY:
+	    dx = targetRA - currentRA;
+	    dy = targetDEC - currentDEC;
+
+	    // Wait until acknowledged or within threshold
+	    if ( fabs(dx) <= (SlewAccuracyN[0].value/(60.0*15.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0))
+	    {
+	       lastRA  = currentRA;
+	       lastDEC = currentDEC;
+	       
+	       EquatorialCoordsWNP.s = IPS_OK;
+	       IDSetNumber(&EquatorialCoordsWNP, "Slew is complete, target locked...");
+	       
+	    break;
+
+	case IPS_OK:
+        break;
+
+
+	case IPS_ALERT:
+	    break;
+	}
+}
+
+}
+// wildi nothing changed in LX200Generic::mountSim
+void LX200Generic::mountSim ()
+{
+	static struct timeval ltv;
+	struct timeval tv;
+	double dt, da, dx;
+	int nlocked;
+
+	/* update elapsed time since last poll, don't presume exactly POLLMS */
+	gettimeofday (&tv, NULL);
+	
+	if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
+	    ltv = tv;
+	    
+	dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6;
+	ltv = tv;
+	da = SLEWRATE*dt;
+
+	/* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */
+	switch (EquatorialCoordsWNP.s)
+	{
+	
+	/* #1 State is idle, update telesocpe at sidereal rate */
+	case IPS_IDLE:
+	    /* RA moves at sidereal, Dec stands still */
+	    currentRA += (SIDRATE*dt/15.);
+	    
+	   IDSetNumber(&EquatorialCoordsRNP, NULL);
+
+	    break;
+
+	case IPS_BUSY:
+	    /* slewing - nail it when both within one pulse @ SLEWRATE */
+	    nlocked = 0;
+
+	    dx = targetRA - currentRA;
+	    
+	    if (fabs(dx) <= da)
+	    {
+		currentRA = targetRA;
+		nlocked++;
+	    }
+	    else if (dx > 0)
+	    	currentRA += da/15.;
+	    else 
+	    	currentRA -= da/15.;
+	    
+
+	    dx = targetDEC - currentDEC;
+	    if (fabs(dx) <= da)
+	    {
+		currentDEC = targetDEC;
+		nlocked++;
+	    }
+	    else if (dx > 0)
+	      currentDEC += da;
+	    else
+	      currentDEC -= da;
+
+	    if (nlocked == 2)
+	    {
+		EquatorialCoordsRNP.s = IPS_OK;
+		EquatorialCoordsWNP.s = IPS_OK;
+		IDSetNumber(&EquatorialCoordsWNP, "Now tracking");
+		IDSetNumber(&EquatorialCoordsRNP, NULL);
+	    } else
+		IDSetNumber(&EquatorialCoordsRNP, NULL);
+
+	    break;
+
+	case IPS_OK:
+	    /* tracking */
+	   IDSetNumber(&EquatorialCoordsRNP, NULL);
+	    break;
+
+	case IPS_ALERT:
+	    break;
+	}
+
+}
+
+void LX200Generic::getBasicData()
+{
+
+  int err;
+  #ifdef HAVE_NOVA_H
+  struct tm *timep;
+  time_t ut;
+  time (&ut);
+  timep = gmtime (&ut);
+  strftime (TimeTP.tp[0].text, strlen(TimeTP.tp[0].text), "%Y-%m-%dT%H:%M:%S", timep);
+
+  IDLog("PC UTC time is %s\n", TimeTP.tp[0].text);
+  #endif
+
+  getAlignment();
+  
+  checkLX200Format(fd);
+  
+  if ( (err = getTimeFormat(fd, &timeFormat)) < 0)
+     IDMessage(thisDevice, "Failed to retrieve time format from device.");
+  else
+  {
+    timeFormat = (timeFormat == 24) ? LX200_24 : LX200_AM;
+    // We always do 24 hours
+    if (timeFormat != LX200_24)
+      err = toggleTimeFormat(fd);
+  }
+// wildi proposal 
+  if ( (err = getLX200RA(fd, &targetRA)) < 0 || (err = getLX200DEC(fd, &targetDEC)) < 0)
+  {
+     EquatorialCoordsRNP.s = IPS_ALERT;
+     IDSetNumber(&EquatorialCoordsRNP, NULL);
+     handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC");
+     return;
+  }
+	
+  if (fault)
+	correctFault();
+
+//  getLX200RA(fd, &targetRA);
+//  getLX200DEC(fd, &targetDEC);
+
+  EquatorialCoordsRNP.np[0].value = targetRA;
+  EquatorialCoordsRNP.np[1].value = targetDEC;
+  
+  EquatorialCoordsRNP.s = IPS_OK;
+  IDSetNumber (&EquatorialCoordsRNP, NULL);  
+  
+  SiteNameT[0].text = new char[64];
+  
+  if ( (err = getSiteName(fd, SiteNameT[0].text, currentSiteNum)) < 0)
+    IDMessage(thisDevice, "Failed to get site name from device");
+  else
+    IDSetText   (&SiteNameTP, NULL);
+  
+  if ( (err = getTrackFreq(fd, &TrackFreqN[0].value)) < 0)
+     IDMessage(thisDevice, "Failed to get tracking frequency from device.");
+  else
+     IDSetNumber (&TrackingFreqNP, NULL);
+     
+  /*updateLocation();
+  updateTime();*/
+  
+}
+
+int LX200Generic::handleCoordSet()
+{
+
+  int  err;
+  char syncString[256];
+  char RAStr[32], DecStr[32];
+
+  switch (currentSet)
+  {
+    // Slew
+    case LX200_TRACK:
+          lastSet = LX200_TRACK;
+	  if (EquatorialCoordsWNP.s == IPS_BUSY)
+	  {
+	     #ifdef INDI_DEBUG
+	     IDLog("Aboring Slew\n");
+	     #endif
+	     if (abortSlew(fd) < 0)
+	     {
+		AbortSlewSP.s = IPS_ALERT;
+		IDSetSwitch(&AbortSlewSP, NULL);
+                slewError(err);
+		return (-1);
+	     }
+
+	     AbortSlewSP.s = IPS_OK;
+	     EquatorialCoordsWNP.s       = IPS_IDLE;
+             IDSetSwitch(&AbortSlewSP, "Slew aborted.");
+	     IDSetNumber(&EquatorialCoordsWNP, NULL);
+
+	     if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)
+	     {
+		MovementNSSP.s  = MovementWESP.s =  IPS_IDLE; 
+		EquatorialCoordsWNP.s       = IPS_IDLE;
+		IUResetSwitch(&MovementNSSP);
+		IUResetSwitch(&MovementWESP);
+		IUResetSwitch(&AbortSlewSP);
+
+		IDSetSwitch(&MovementNSSP, NULL);
+		IDSetSwitch(&MovementWESP, NULL);
+	      }
+
+	// sleep for 100 mseconds
+	usleep(100000);
+	}
+
+	if ((err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */
+	{
+	    IDMessage(mydev "ERROR Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
+	    slewError(err);
+	    return  -1;
+	}
+
+	EquatorialCoordsWNP.s = IPS_BUSY;
+	fs_sexa(RAStr, targetRA, 2, 3600);
+	fs_sexa(DecStr, targetDEC, 2, 3600);
+	IDSetNumber(&EquatorialCoordsWNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr);
+	#ifdef INDI_DEBUG
+	IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr);
+        #endif
+	break;
+
+    // Sync
+    case LX200_SYNC:
+          lastSet = LX200_SYNC;
+	   
+	if (!simulation)
+	  if ( ( err = Sync(fd, syncString) < 0) )
+	  {
+		EquatorialCoordsWNP.s = IPS_ALERT;
+	        IDSetNumber(&EquatorialCoordsWNP , "Synchronization failed.");
+		return (-1);
+	  }
+
+	  EquatorialCoordsWNP.s = IPS_OK;
+	  IDLog("Synchronization successful %s\n", syncString);
+	  IDSetNumber(&EquatorialCoordsWNP, "Synchronization successful.");
+	  break;
+	  
+   }
+   
+   return (0);
+
+}
+
+int LX200Generic::getOnSwitch(ISwitchVectorProperty *sp)
+{
+ for (int i=0; i < sp->nsp ; i++)
+     if (sp->sp[i].s == ISS_ON)
+      return i;
+
+ return -1;
+}
+
+
+int LX200Generic::checkPower(ISwitchVectorProperty *sp)
+{
+  if (simulation) return 0;
+  
+  if (ConnectSP.s != IPS_OK)
+  {
+    if (!strcmp(sp->label, ""))
+    	IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->name);
+    else
+        IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->label);
+	
+    sp->s = IPS_IDLE;
+    IDSetSwitch(sp, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int LX200Generic::checkPower(INumberVectorProperty *np)
+{
+  if (simulation) return 0;
+  
+  if (ConnectSP.s != IPS_OK)
+  {
+    if (!strcmp(np->label, ""))
+    	IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->name);
+    else
+        IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->label);
+	
+    np->s = IPS_IDLE;
+    IDSetNumber(np, NULL);
+    return -1;
+  }
+
+  return 0;
+
+}
+
+int LX200Generic::checkPower(ITextVectorProperty *tp)
+{
+
+  if (simulation) return 0;
+  
+  if (ConnectSP.s != IPS_OK)
+  {
+    if (!strcmp(tp->label, ""))
+    	IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->name);
+    else
+        IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->label);
+	
+    tp->s = IPS_IDLE;
+    IDSetText(tp, NULL);
+    return -1;
+  }
+
+  return 0;
+
+}
+
+void LX200Generic::connectTelescope()
+{
+     switch (ConnectSP.sp[0].s)
+     {
+      case ISS_ON:  
+	
+        if (simulation)
+	{
+	  ConnectSP.s = IPS_OK;
+	  IDSetSwitch (&ConnectSP, "Simulated telescope is online.");
+	  //updateTime();
+	  return;
+	}
+	
+	 if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
+	 {
+	   ConnectS[0].s = ISS_OFF;
+	   ConnectS[1].s = ISS_ON;
+	   IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text);
+	   return;
+	 }
+	 if (check_lx200_connection(fd))
+	 {   
+	   ConnectS[0].s = ISS_OFF;
+	   ConnectS[1].s = ISS_ON;
+	   IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline.");
+	   return;
+	 }
+
+        #ifdef INDI_DEBUG
+        IDLog("Telescope test successfful.\n");
+	#endif
+
+        *((int *) UTCOffsetN[0].aux0) = 0;
+	ConnectSP.s = IPS_OK;
+	IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data...");
+	getBasicData();
+	break;
+
+     case ISS_OFF:
+         ConnectS[0].s = ISS_OFF;
+	 ConnectS[1].s = ISS_ON;
+         ConnectSP.s = IPS_IDLE;
+         IDSetSwitch (&ConnectSP, "Telescope is offline.");
+	 IDLog("Telescope is offline.");
+	 tty_disconnect(fd);
+	 break;
+
+    }
+
+}
+
+void LX200Generic::slewError(int slewCode)
+{
+    EquatorialCoordsWNP.s = IPS_ALERT;
+
+    if (slewCode == 1)
+	IDSetNumber(&EquatorialCoordsWNP, "Object below horizon.");
+    else if (slewCode == 2)
+	IDSetNumber(&EquatorialCoordsWNP, "Object below the minimum elevation limit.");
+    else
+	IDSetNumber(&EquatorialCoordsWNP, "Slew failed.");
+
+}
+
+void LX200Generic::getAlignment()
+{
+
+   if (ConnectSP.s != IPS_OK)
+    return;
+
+   signed char align = ACK(fd);
+   if (align < 0)
+   {
+     IDSetSwitch (&AlignmentSw, "Failed to get telescope alignment.");
+     return;
+   }
+
+   AlignmentS[0].s = ISS_OFF;
+   AlignmentS[1].s = ISS_OFF;
+   AlignmentS[2].s = ISS_OFF;
+
+    switch (align)
+    {
+      case 'P': AlignmentS[0].s = ISS_ON;
+       		break;
+      case 'A': AlignmentS[1].s = ISS_ON;
+      		break;
+      case 'L': AlignmentS[2].s = ISS_ON;
+            	break;
+    }
+
+    AlignmentSw.s = IPS_OK;
+    IDSetSwitch (&AlignmentSw, NULL);
+    IDLog("ACK success %c\n", align);
+}
+
+void LX200Generic::enableSimulation(bool enable)
+{
+   simulation = enable;
+   
+   if (simulation)
+     IDLog("Warning: Simulation is activated.\n");
+   else
+     IDLog("Simulation is disabled.\n");
+}
+
+void LX200Generic::updateTime()
+{
+  #ifdef HAVE_NOVA_H
+  char cdate[32];
+  double ctime;
+  int h, m, s, lx200_utc_offset=0;
+  int day, month, year, result;
+  struct tm ltm;
+  struct tm utm;
+  time_t time_epoch;
+  
+  if (simulation)
+  {
+    sprintf(TimeT[0].text, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30);
+    IDLog("Telescope ISO date and time: %s\n", TimeT[0].text);
+    IDSetText(&TimeTP, NULL);
+    return;
+  }
+
+  getUTCOffset(fd, &lx200_utc_offset);
+
+  // LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition.
+  UTCOffsetN[0].value = lx200_utc_offset*-1;
+
+  // We got a valid value for UTCOffset now
+  *((int *) UTCOffsetN[0].aux0) = 1;  
+
+  #ifdef INDI_DEBUG
+  IDLog("Telescope TimeT Offset: %g\n", UTCOffsetN[0].value);
+  #endif
+
+  getLocalTime24(fd, &ctime);
+  getSexComponents(ctime, &h, &m, &s);
+
+  if ( (result = getSDTime(fd, &SDTimeN[0].value)) < 0)
+    IDMessage(thisDevice, "Failed to retrieve siderial time from device.");
+  
+  getCalenderDate(fd, cdate);
+  result = sscanf(cdate, "%d/%d/%d", &year, &month, &day);
+  if (result != 3) return;
+
+  // Let's fill in the local time
+  ltm.tm_sec = s;
+  ltm.tm_min = m;
+  ltm.tm_hour = h;
+  ltm.tm_mday = day;
+  ltm.tm_mon = month - 1;
+  ltm.tm_year = year - 1900;
+
+  // Get time epoch
+  time_epoch = mktime(&ltm);
+
+  // Convert to TimeT
+  time_epoch -= (int) (UTCOffsetN[0].value * 60.0 * 60.0);
+
+  // Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time)
+  localtime_r(&time_epoch, &utm);
+
+  /* Format it into ISO 8601 */
+  strftime(cdate, 32, "%Y-%m-%dT%H:%M:%S", &utm);
+  IUSaveText(&TimeT[0], cdate);
+  
+  #ifdef INDI_DEBUG
+  IDLog("Telescope Local Time: %02d:%02d:%02d\n", h, m , s);
+  IDLog("Telescope SD Time is: %g\n", SDTimeN[0].value);
+  IDLog("Telescope UTC Time: %s\n", TimeT[0].text);
+  #endif
+
+  // Let's send everything to the client
+  IDSetText(&TimeTP, NULL);
+  IDSetNumber(&SDTimeNP, NULL);
+  IDSetNumber(&UTCOffsetNP, NULL);
+  #endif
+
+}
+
+void LX200Generic::updateLocation()
+{
+
+ int dd = 0, mm = 0, err = 0;
+
+ if (simulation)
+	return;
+ 
+ if ( (err = getSiteLatitude(fd, &dd, &mm)) < 0)
+    IDMessage(thisDevice, "Failed to get site latitude from device.");
+  else
+  {
+    if (dd > 0)
+    	geoNP.np[0].value = dd + mm/60.0;
+    else
+        geoNP.np[0].value = dd - mm/60.0;
+  
+      IDLog("Autostar Latitude: %d:%d\n", dd, mm);
+      IDLog("INDI Latitude: %g\n", geoNP.np[0].value);
+  }
+  
+  if ( (err = getSiteLongitude(fd, &dd, &mm)) < 0)
+    IDMessage(thisDevice, "Failed to get site longitude from device.");
+  else
+  {
+    if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm/60.0);
+    else geoNP.np[1].value = (dd - mm/60.0) * -1.0;
+    
+    IDLog("Autostar Longitude: %d:%d\n", dd, mm);
+    IDLog("INDI Longitude: %g\n", geoNP.np[1].value);
+  }
+  
+  IDSetNumber (&geoNP, NULL);
+
+}
+
Index: /BAORadio/libindi/v1/drivers/telescope/lx200generic.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200generic.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200generic.h	(revision 500)
@@ -0,0 +1,89 @@
+/*
+    LX200 Generic
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef LX200GENERIC_H
+#define LX200GENERIC_H
+
+#include "indidevapi.h"
+#include "indicom.h"
+
+#define	POLLMS		1000		/* poll period, ms */
+#define mydev		"LX200 Generic" /* The device name */
+
+class LX200Generic
+{
+ public:
+ LX200Generic();
+ virtual ~LX200Generic();
+
+ virtual void ISGetProperties (const char *dev);
+ virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ virtual void ISSnoopDevice (XMLEle *root);
+ virtual void ISPoll ();
+ virtual void getBasicData();
+
+ int checkPower(INumberVectorProperty *np);
+ int checkPower(ISwitchVectorProperty *sp);
+ int checkPower(ITextVectorProperty *tp);
+ void handleError(ISwitchVectorProperty *svp, int err, const char *msg);
+ void handleError(INumberVectorProperty *nvp, int err, const char *msg);
+ void handleError(ITextVectorProperty *tvp, int err, const char *msg);
+ bool isTelescopeOn(void);
+ void connectTelescope();
+ void slewError(int slewCode);
+ void getAlignment();
+ int handleCoordSet();
+ int getOnSwitch(ISwitchVectorProperty *sp);
+ void setCurrentDeviceName(const char * devName);
+ void correctFault();
+ void enableSimulation(bool enable);
+ void updateTime();
+ void updateLocation();
+ void mountSim();
+
+ static void updateFocusTimer(void *p);
+ static void guideTimeout(void *p);
+ int    fd;
+ int    GuideNSTID;
+ int    GuideWETID;
+
+ protected:
+  int timeFormat;
+  int currentSiteNum;
+  int trackingMode;
+
+  double JD;
+  double lastRA;
+  double lastDEC;
+  bool   fault;
+  bool   simulation;
+  char   thisDevice[64];
+  int    currentSet;
+  int    lastSet;
+  
+
+};
+
+void changeLX200GenericDeviceName(const char * newName);
+void changeAllDeviceNames(const char *newName);
+
+#endif
Index: /BAORadio/libindi/v1/drivers/telescope/lx200gps.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200gps.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200gps.cpp	(revision 500)
@@ -0,0 +1,369 @@
+/*
+    LX200 GPS
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "lx200gps.h"
+#include "lx200driver.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define GPSGroup   "Extended GPS Features"
+
+extern LX200Generic *telescope;
+extern int MaxReticleFlashRate;
+
+static ISwitch GPSPowerS[]		= {{ "On", "", ISS_OFF, 0, 0}, {"Off", "", ISS_ON, 0, 0}};
+static ISwitch GPSStatusS[]	  	= {{ "Sleep", "", ISS_OFF, 0, 0}, {"Wake up", "", ISS_OFF, 0 ,0}, {"Restart", "", ISS_OFF, 0, 0}};
+static ISwitch GPSUpdateS[]	  	= { {"Update GPS", "", ISS_OFF, 0, 0}, {"Update Client", "", ISS_OFF, 0, 0}};
+static ISwitch AltDecPecS[]		= {{ "Enable", "", ISS_OFF, 0 ,0}, {"Disable", "", ISS_OFF, 0 ,0}};
+static ISwitch AzRaPecS[]		= {{ "Enable", "", ISS_OFF, 0, 0}, {"Disable", "", ISS_OFF, 0 ,0}};
+static ISwitch SelenSyncS[]		= {{ "Sync", "",  ISS_OFF, 0, 0}};
+static ISwitch AltDecBackSlashS[]	= {{ "Activate", "", ISS_OFF, 0, 0}};
+static ISwitch AzRaBackSlashS[]		= {{ "Activate", "", ISS_OFF, 0, 0}};
+static ISwitch OTAUpdateS[]		= {{ "Update", "", ISS_OFF, 0, 0}};
+
+static ISwitchVectorProperty GPSPowerSP	   = { mydev, "GPS Power", "", GPSGroup, IP_RW, ISR_1OFMANY, 0 , IPS_IDLE, GPSPowerS, NARRAY(GPSPowerS), "", 0};
+static ISwitchVectorProperty GPSStatusSP   = { mydev, "GPS Status", "", GPSGroup, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, GPSStatusS, NARRAY(GPSStatusS), "", 0};
+static ISwitchVectorProperty GPSUpdateSP   = { mydev, "GPS System", "", GPSGroup, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, GPSUpdateS, NARRAY(GPSUpdateS), "", 0};
+static ISwitchVectorProperty AltDecPecSP   = { mydev, "Alt/Dec PEC", "", GPSGroup, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AltDecPecS, NARRAY(AltDecPecS), "", 0};
+static ISwitchVectorProperty AzRaPecSP	   = { mydev, "Az/Ra PEC", "", GPSGroup, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AzRaPecS, NARRAY(AzRaPecS), "", 0};
+static ISwitchVectorProperty SelenSyncSP   = { mydev, "Selenographic Sync", "", GPSGroup, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, SelenSyncS, NARRAY(SelenSyncS), "", 0};
+static ISwitchVectorProperty AltDecBackSlashSP	= { mydev, "Alt/Dec Anti-backslash", "", GPSGroup, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, AltDecBackSlashS, NARRAY(AltDecBackSlashS), "", 0};
+static ISwitchVectorProperty AzRaBackSlashSP	= { mydev, "Az/Ra Anti-backslash", "", GPSGroup, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, AzRaBackSlashS, NARRAY(AzRaBackSlashS), "", 0};
+static ISwitchVectorProperty OTAUpdateSP	= { mydev, "OTA Update", "", GPSGroup, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, OTAUpdateS, NARRAY(OTAUpdateS), "", 0};
+
+static INumber OTATempN[]	= { {"Temp.", "", "%g", -200., 500., 0., 0., 0, 0, 0 } };
+static INumberVectorProperty OTATempNP =   { mydev, "OTA Temperature (C)", "", GPSGroup, IP_RO, 0, IPS_IDLE, OTATempN, NARRAY(OTATempN), "", 0};
+
+void updateTemp(void *p);
+
+void changeLX200GPSDeviceName(const char *newName)
+{
+ strcpy(GPSPowerSP.device, newName);
+ strcpy(GPSStatusSP.device, newName );
+ strcpy(GPSUpdateSP.device, newName  );
+ strcpy(AltDecPecSP.device, newName );
+ strcpy(AzRaPecSP.device,newName  );
+ strcpy(SelenSyncSP.device, newName );
+ strcpy(AltDecBackSlashSP.device, newName );
+ strcpy(AzRaBackSlashSP.device, newName );
+ strcpy(OTATempNP.device, newName );
+ strcpy(OTAUpdateSP.device, newName);
+ 
+}
+
+LX200GPS::LX200GPS() : LX200_16()
+{
+   IEAddTimer(900000, updateTemp, &fd);
+   
+}
+
+void LX200GPS::ISGetProperties (const char *dev)
+{
+
+if (dev && strcmp (thisDevice, dev))
+    return;
+
+// process parent first
+   LX200_16::ISGetProperties(dev);
+
+IDDefSwitch (&GPSPowerSP, NULL);
+IDDefSwitch (&GPSStatusSP, NULL);
+IDDefSwitch (&GPSUpdateSP, NULL);
+IDDefSwitch (&AltDecPecSP, NULL);
+IDDefSwitch (&AzRaPecSP, NULL);
+IDDefSwitch (&SelenSyncSP, NULL);
+IDDefSwitch (&AltDecBackSlashSP, NULL);
+IDDefSwitch (&AzRaBackSlashSP, NULL);
+IDDefNumber (&OTATempNP, NULL);
+IDDefSwitch (&OTAUpdateSP, NULL);
+
+}
+
+void LX200GPS::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	// ignore if not ours //
+	if (strcmp (dev, thisDevice))
+	    return;
+
+     LX200_16::ISNewText (dev, name, texts, names, n);
+}
+
+void LX200GPS::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+        
+    LX200_16::ISNewNumber (dev, name, values, names, n);
+
+ }
+
+
+ void LX200GPS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+ {
+    int index=0, err=0;
+    char msg[64];
+
+    if (strcmp (dev, thisDevice))
+	    return;
+
+    /* GPS Power */
+    if (!strcmp(name,GPSPowerSP.name))
+    {
+       if (checkPower(&GPSPowerSP))
+       return;
+
+      if (IUUpdateSwitch(&GPSPowerSP, states, names, n) < 0)
+		return;
+
+      index = getOnSwitch(&GPSPowerSP);
+      if (index == 0)
+	 turnGPSOn(fd);
+      else
+	turnGPSOff(fd);
+
+      GPSPowerSP.s = IPS_OK;
+      IDSetSwitch (&GPSPowerSP, index == 0 ? "GPS System is ON" : "GPS System is OFF" );
+      return;
+    }
+
+    /* GPS Status Update */
+    if (!strcmp(name,GPSStatusSP.name))
+    {
+       if (checkPower(&GPSStatusSP))
+       return;
+
+      if (IUUpdateSwitch(&GPSStatusSP, states, names, n) < 0)
+		return;
+
+      index = getOnSwitch(&GPSStatusSP);
+
+      if (index == 0)
+      {
+	   err = gpsSleep(fd);
+	   strcpy(msg, "GPS system is in sleep mode.");
+      }
+      else if (index == 1)
+      {
+	   err = gpsWakeUp(fd);
+           strcpy(msg, "GPS system is reactivated.");
+      }
+      else
+      {
+	   err = gpsRestart(fd);
+	   strcpy(msg, "GPS system is restarting...");
+	   updateTime();
+	   updateLocation();
+      }
+
+	GPSStatusSP.s = IPS_OK;
+	IDSetSwitch (&GPSStatusSP, "%s", msg);
+	return;
+
+    }
+
+    /* GPS Update */
+    if (!strcmp(name,GPSUpdateSP.name))
+    {
+       if (checkPower(&GPSUpdateSP))
+       return;
+
+	if (IUUpdateSwitch(&GPSUpdateSP, states, names, n) < 0)
+		return;
+
+	index = getOnSwitch(&GPSUpdateSP);
+
+	GPSUpdateSP.s = IPS_OK;
+
+     if (index == 0)
+     {
+	     
+     	     IDSetSwitch(&GPSUpdateSP, "Updating GPS system. This operation might take few minutes to complete...");
+     	     if (updateGPS_System(fd))
+     	     {
+     			IDSetSwitch(&GPSUpdateSP, "GPS system update successful.");
+			updateTime();
+			updateLocation();
+     		}
+     		else
+     		{
+        		GPSUpdateSP.s = IPS_IDLE;
+        		IDSetSwitch(&GPSUpdateSP, "GPS system update failed.");
+     		}
+	}
+	else
+	{
+		updateTime();
+		updateLocation();
+		IDSetSwitch(&GPSUpdateSP, "Client time and location is synced to LX200 GPS Data.");
+	
+	}
+     		return;
+    }
+
+    /* Alt Dec Periodic Error correction */
+    if (!strcmp(name, AltDecPecSP.name))
+    {
+       if (checkPower(&AltDecPecSP))
+       return;
+
+      if (IUUpdateSwitch(&AltDecPecSP, states, names, n) < 0)
+	return;
+
+      index = getOnSwitch(&AltDecPecSP);
+      
+       if (index == 0)
+      {
+        err = enableDecAltPec(fd);
+	strcpy (msg, "Alt/Dec Compensation Enabled");
+      }
+      else
+      {
+        err = disableDecAltPec(fd);
+	strcpy (msg, "Alt/Dec Compensation Disabled");
+      }
+
+      AltDecPecSP.s = IPS_OK;
+      IDSetSwitch(&AltDecPecSP, "%s", msg);
+
+      return;
+    }
+
+    /* Az RA periodic error correction */
+    if (!strcmp(name, AzRaPecSP.name))
+    {
+       if (checkPower(&AzRaPecSP))
+       return; 
+
+      if (IUUpdateSwitch(&AzRaPecSP, states, names, n) < 0)
+		return;
+
+      index = getOnSwitch(&AzRaPecSP);
+
+       if (index == 0)
+      {
+        err = enableRaAzPec(fd);
+	strcpy (msg, "Ra/Az Compensation Enabled");
+      }
+      else
+      {
+        err = disableRaAzPec(fd);
+	strcpy (msg, "Ra/Az Compensation Disabled");
+      }
+
+      AzRaPecSP.s = IPS_OK;
+      IDSetSwitch(&AzRaPecSP, "%s", msg);
+
+      return;
+    }
+
+   if (!strcmp(name, AltDecBackSlashSP.name))
+   {
+      if (checkPower(&AltDecBackSlashSP))
+      return;
+
+     err = activateAltDecAntiBackSlash(fd);
+     AltDecBackSlashSP.s = IPS_OK;
+     IDSetSwitch(&AltDecBackSlashSP, "Alt/Dec Anti-backslash enabled");
+     return;
+   }
+
+   if (!strcmp(name, AzRaBackSlashSP.name))
+   {
+     if (checkPower(&AzRaBackSlashSP))
+      return;
+
+     err = activateAzRaAntiBackSlash(fd);
+     AzRaBackSlashSP.s = IPS_OK;
+     IDSetSwitch(&AzRaBackSlashSP, "Az/Ra Anti-backslash enabled");
+     return;
+   }
+   
+   if (!strcmp(name, OTAUpdateSP.name))
+   {
+     int error_type=0;
+
+     if (checkPower(&OTAUpdateSP))
+      return;
+      
+      IUResetSwitch(&OTAUpdateSP);
+      
+      if ( (error_type = getOTATemp(fd, &OTATempNP.np[0].value)) < 0)
+      {
+	OTAUpdateSP.s = IPS_ALERT;
+	OTATempNP.s = IPS_ALERT;
+	IDSetNumber(&OTATempNP, "Error: OTA temperature read timed out.");
+      }
+      else
+      {
+        OTAUpdateSP.s = IPS_OK;
+	OTATempNP.s = IPS_OK;
+	IDSetNumber(&OTATempNP, NULL);
+      }
+      
+      return;
+   }
+
+   LX200_16::ISNewSwitch (dev, name, states, names,  n);
+
+}
+
+ void LX200GPS::ISPoll ()
+ {
+
+   LX200_16::ISPoll();
+
+
+ }
+ 
+ void updateTemp(void * p)
+ {
+   
+   int fd = *((int *) p);
+
+   if (telescope->isTelescopeOn())
+   {
+     if (getOTATemp(fd, &OTATempNP.np[0].value) < 0)
+     {
+       OTATempNP.s = IPS_ALERT;
+       IDSetNumber(&OTATempNP, "Error: OTA temperature read timed out.");
+       return;
+     }
+     else
+     {
+        OTATempNP.s = IPS_OK; 
+   	IDSetNumber(&OTATempNP, NULL);
+     }
+   }
+ 
+   IEAddTimer(900000, updateTemp, &fd);
+      
+ }
+
+ void LX200GPS::getBasicData()
+ {
+
+   //getOTATemp(&OTATempNP.np[0].value);
+   //IDSetNumber(&OTATempNP, NULL);
+   
+   // process parent
+   LX200_16::getBasicData();
+ }
+
Index: /BAORadio/libindi/v1/drivers/telescope/lx200gps.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/lx200gps.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/lx200gps.h	(revision 500)
@@ -0,0 +1,45 @@
+#ifndef LX200GPS_H
+#define LX200GPS_H
+
+/*
+    LX200 GPS
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "lx200_16.h"
+
+class LX200GPS : public LX200_16
+{
+ public:
+  LX200GPS();
+  ~LX200GPS() {} 
+
+ void ISGetProperties (const char *dev);
+ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ void ISPoll ();
+ void getBasicData();
+
+};
+
+void changeLX200GPSDeviceName(const char *newName);
+
+#endif
+
+
Index: /BAORadio/libindi/v1/drivers/telescope/orionatlas.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/orionatlas.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/orionatlas.cpp	(revision 500)
@@ -0,0 +1,785 @@
+/*
+    OrionAtlas (EQ-G/EQ-6 with SkyScan/SynScan controller)
+    Copyright (C) 2005 Bruce Bockius (bruceb@WhiteAntelopeSoftware.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "orionatlas.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#define mydev       "Orion Atlas"
+#define ATLAS_DEBUG 1
+#define POLLMS 5000
+
+#define lat geo[0].value
+#define lon geo[1].value
+
+OrionAtlas *telescope = NULL;
+
+
+/* There is _one_ binary for all LX200 drivers, but each binary is renamed
+** to its device name (i.e. lx200gps, lx200_16..etc). The main function will
+** fetch from std args the binary name and ISInit will create the apporpiate
+** device afterwards. If the binary name does not match any known devices,
+** we simply create a generic device
+*/
+extern char* me;
+
+#define COMM_GROUP  "Communication"
+#define BASIC_GROUP "Main Control"
+#define SETUP_GROUP "Setup"
+
+#define ATLAS_MIN_RA 0.0
+#define ATLAS_MAX_RA 24.0
+#define ATLAS_MIN_DEC -90.0
+#define ATLAS_MAX_DEC 90.0
+
+#define ATLAS_MIN_AZ 0.0
+#define ATLAS_MAX_AZ 360.0
+#define ATLAS_MIN_ALT -90.0
+#define ATLAS_MAX_ALT 90.0
+
+static void ISPoll(void *);
+
+//static ISwitch abortSlewS[]      = {{"ABORT", "Abort", ISS_OFF, 0, 0}};
+
+/* Fundamental group */
+static ISwitch PowerS[] = {{"CONNECT","Connect",ISS_OFF,0,0},{"DISCONNECT","Disconnect",ISS_ON,0,0},{"RECONNECT","Reconnect",ISS_OFF,0,0}};
+static ISwitchVectorProperty PowerSw = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}};
+static ITextVectorProperty Port = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_OK, PortT, NARRAY(PortT), "", 0};
+
+/* Movement group */
+//static ISwitchVectorProperty abortSlewSw     = { mydev, "ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, abortSlewS, NARRAY(abortSlewS), "", 0};
+static INumber eq[] = {
+    {"RA",  "RA (hh:mm.m)", "%010.5m",  ATLAS_MIN_RA, ATLAS_MAX_RA, 0., 0., 0, 0, 0},
+    {"DEC", "Dec (dd:mm.m)", "%010.5m", ATLAS_MIN_DEC, ATLAS_MAX_DEC, 0., 0., 0, 0, 0}};
+// Azimuth/Altitude
+static INumber aa[] = {
+    {"XAZ",  "Az (ddd:mm.m)", "%010.5m", ATLAS_MIN_AZ, ATLAS_MAX_AZ, 0.0, 0.0, 0, 0, 0},
+    {"XALT", "Alt (dd:mm.m)", "%010.5m", ATLAS_MIN_ALT, ATLAS_MAX_ALT, 0.0, 0.0, 0, 0, 0}};
+static INumberVectorProperty eqNum = {
+    mydev, "EQUATORIAL_EOD_COORD", "Eq. Coordinates", BASIC_GROUP, IP_RW, 0, IPS_OK, eq, NARRAY(eq), "", 0};
+
+static INumberVectorProperty aaNum = {
+    mydev, "XHORIZONTAL_COORD", "Horz. Coordinates", BASIC_GROUP, IP_RW, 0, IPS_OK, aa, NARRAY(aa), "", 0};
+
+static ISwitch OnCoordSetS[] = {{"TRACK", "Track", ISS_ON, 0, 0}}; // switch does nothing, but some clients won't let you track w/o it.
+static ISwitchVectorProperty OnCoordSetSw = {
+    mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_OK, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
+static ISwitch UpdateS[] = {{"UPDATE1", "On", ISS_ON, 0, 0},{"UPDATE0","Off", ISS_OFF,0,0}};
+static ISwitch MovementRADecS[] = {{"XRAPLUS", "RA+", ISS_OFF, 0, 0}, {"XRAMINUS", "RA-", ISS_OFF, 0, 0}, {"XDECPLUS", "Dec+", ISS_OFF, 0, 0},            {"XDECMINUS", "Dec-", ISS_OFF, 0, 0}};
+static ISwitch MovementAzAltS[] = {{"XAZPLUS", "Az+", ISS_OFF, 0, 0}, {"XAZMINUS", "Az-", ISS_OFF, 0, 0}, {"XALTPLUS", "Alt+", ISS_OFF, 0, 0},            {"XALTMINUS", "Alt-", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty MovementRADecSw = { mydev, "XRADECMOVEMENT", "Nudge", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_OK, MovementRADecS,             NARRAY(MovementRADecS), "", 0};
+static ISwitchVectorProperty MovementAzAltSw = { mydev, "XAZALTMOVEMENT", "Nudge", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_OK, MovementAzAltS,             NARRAY(MovementAzAltS), "", 0};
+static ISwitchVectorProperty UpdateSw = { mydev, "XUPDATE", "Update Coords", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_OK, UpdateS, NARRAY(UpdateS), "", 0};
+
+/* Telescope Parameters group */
+// Setup group
+static INumber steps[] = {
+    {"XRASTEP", "RA Step", "%010.6m", 0.0, 5.0, 0.0, 0.0, 0, 0, 0},
+    {"XDECSTEP", "Dec Step", "%010.6m", 0.0, 5.0, 0.0, 0.0, 0, 0, 0},
+    {"XAZSTEP", "Az Step", "%010.6m", 0.0, 5.0, 0.0, 0.0, 0, 0, 0},
+    {"XALTSTEP", "Alt Step", "%010.6m", 0.0, 5.0, 0.0, 0.0, 0, 0, 0}};
+// geographic position
+static INumber geo[] = {
+    {"LAT", "Lat (dd:mm.m)", "%010.5m", -90.0, 90.0, 0.0, 0.0, 0, 0, 0},
+    {"LONG", "Lon (ddd:mm.m)", "%010.5m", -180.0, 360.0, 0.0, 0.0, 0, 0, 0}};
+static INumberVectorProperty geoNum = {
+    mydev, "GEOGRAPHIC_COORD", "Scope Location", SETUP_GROUP, IP_RW, 0, IPS_OK, geo, NARRAY(geo), "", 0};
+static INumberVectorProperty stepNum = {
+    mydev, "XSTEPS", "Nudge Steps", SETUP_GROUP, IP_RW, 0, IPS_OK, steps, NARRAY(steps), "", 0};
+
+/* send client definitions of all properties */
+void ISInit()
+{
+    static int isInit=0;
+
+    if (isInit) return;
+
+    isInit = 1;
+
+    PortT[0].text = strcpy(new char[32], "/dev/ttyUSB0");
+    steps[0].value=1.0/60.0;
+    steps[1].value=1.0/60.0;
+    steps[2].value=1.0/60.0;
+    steps[3].value=1.0/60.0;
+
+    telescope = new OrionAtlas();
+
+    IEAddTimer (POLLMS, ISPoll, NULL);
+}
+
+void ISGetProperties (const char *dev)
+{ ISInit(); telescope->ISGetProperties(dev);}
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{ ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);}
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{ ISInit(); telescope->ISNewText(dev, name, texts, names, n);}
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{ ISInit(); telescope->ISNewNumber(dev, name, values, names, n);}
+void ISPoll (void *p) { telescope->ISPoll();    IEAddTimer (POLLMS, ISPoll, NULL); p=p;}
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+OrionAtlas::OrionAtlas()
+{
+    geo[0].value=0;
+    geo[1].value=0;
+    lat=lon=-1000;
+
+    TelConnectFlag=0;
+    Updating=true;
+    // Children call parent routines, this is the default
+    IDLog("Initialized Orion Atlas EQ-G device, driver ver 0.101\n");
+    if (ATLAS_DEBUG) IDLog("Driver in DEBUG mode.");
+}
+
+void OrionAtlas::ISGetProperties(const char *dev)
+{
+
+    if (dev && strcmp (mydev, dev))
+        return;
+
+    // COMM_GROUP
+    IDDefSwitch (&PowerSw, NULL);
+    IDDefText   (&Port, NULL);
+
+    // BASIC_GROUP
+    IDDefNumber (&eqNum, NULL);
+    IDDefNumber (&aaNum, NULL);
+    IDDefSwitch (&UpdateSw, NULL);
+//    IDDefSwitch (&abortSlewSw, NULL);
+    IDDefSwitch (&OnCoordSetSw,NULL);
+    IDDefSwitch (&MovementRADecSw, NULL);
+    IDDefSwitch (&MovementAzAltSw, NULL);
+
+  // SETUP_GROUP
+    IDDefNumber (&geoNum, NULL);
+    IDDefNumber (&stepNum, NULL);
+
+  /* Send the basic data to the new client if the previous client(s) are already connected. */
+    if (PowerSw.s == IPS_OK) {
+        if (ATLAS_DEBUG) log("Initial call to getBasicData()\n");
+        getBasicData();
+    }
+}
+
+void OrionAtlas::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+    IText *tp;
+
+    // suppress warning
+    n=n;
+    // ignore if not ours //
+    if (strcmp (dev, mydev))
+        return;
+
+    if (!strcmp(name, Port.name) ) {
+        Port.s = IPS_OK;
+
+        tp = IUFindText( &Port, names[0] );
+        if (!tp)
+            return;
+
+        tp->text = new char[strlen(texts[0])+1];
+        strcpy(tp->text, texts[0]);
+        IDSetText (&Port, NULL);
+        return;
+    }
+    else {
+        if (ATLAS_DEBUG) log("ISNewText('%s')\n",name);
+    }
+}
+
+void OrionAtlas::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+    double newRA=0, newDEC=0, newAlt=0, newAz=0;
+
+        // ignore if not ours //
+    if (strcmp (dev, mydev))
+        return;
+
+    if (!strcmp (name, eqNum.name)) {
+        int i=0, nset=0;
+        if (checkPower(&eqNum)) return;
+
+        for (nset = i = 0; i < n; i++) {
+            INumber *eqp = IUFindNumber (&eqNum, names[i]);
+            if (eqp == &eq[0]) {
+                newRA = values[i];
+                nset += newRA >= 0 && newRA <= 24.0;
+            } else if (eqp == &eq[1]) {
+                newDEC = values[i];
+                nset += newDEC >= -90.0 && newDEC <= 90.0;
+            }
+        }
+        if (nset==2) { // both coords were valid.  Slew.
+            MoveScope(RADEC,newRA,newDEC);
+        }
+    }
+    else if (!strcmp(name, aaNum.name)) {
+        int i=0, nset=0;
+        if (checkPower(&eqNum)) return;
+
+        for (nset = i = 0; i < n; i++) {
+            INumber *aap = IUFindNumber (&aaNum, names[i]);
+            if (aap == &aa[1]) {
+                newAlt = values[i];
+                nset += newAlt >= -90.0 && newAlt <= 90.0;
+            } else if (aap == &aa[0]) {
+                newAz = values[i];
+                nset += newAz >= 0.0 && newAz <=360.0;
+            }
+        }
+        if (nset==2) { // both coords were valid.  Slew.
+            MoveScope(AZALT,newAz,newAlt);
+        }
+    }
+    else if (!strcmp(name, geoNum.name)) {
+        if (ATLAS_DEBUG) log("NewNumber(geoName)\n");
+        int i=0;
+        for (i=0;i<n;i++) {
+            INumber *geop = IUFindNumber(&geoNum, names[i]);
+            geop->value=values[i];
+        }
+        IDSetNumber(&geoNum,NULL);
+    }
+    else if (!strcmp(name, stepNum.name)) {
+        if (ATLAS_DEBUG) log("NewNumber(stepNum)\n");
+        for (int i=0;i<n;i++) {
+            INumber *stepp = IUFindNumber(&stepNum, names[i]);
+            stepp->value=values[i];
+        }
+        IDSetNumber(&stepNum,NULL);
+    }
+    else {
+        if (ATLAS_DEBUG) log("ISNewNumber('%s')\n",name);
+    }
+}
+
+void OrionAtlas::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+
+    INDI_UNUSED(names);
+
+    // ignore if not ours //
+    if (strcmp(dev,mydev))
+        return;
+
+    // FIRST Switch ALWAYS for power
+    if (!strcmp(name,PowerSw.name)) 
+    {
+        if (IUUpdateSwitch(&PowerSw,states,names,n) < 0)
+		return;
+
+        if (PowerS[1].s  == ISS_ON)
+        	DisconnectTel();
+	else
+        	ConnectTel();
+        return;
+        }
+    else if (!strcmp(name,UpdateSw.name)) {
+        IUResetSwitch(&UpdateSw);
+        IUUpdateSwitch(&UpdateSw,states,names,n);
+        IDSetSwitch(&UpdateSw,NULL);
+        Updating=!Updating;
+    }
+    else if (!strcmp(name,MovementRADecSw.name)) {
+        if (!GetCoords(RADEC)) {
+            IDMessage(mydev,"Invalid coordinates from scope - aborted nudge.");
+        }
+        log("before RA=%f  Dec=%f\n",returnRA,returnDec);
+        for (int i=0; i<n; i++) {
+            states[i]=ISS_OFF;
+            ISwitch *mvp = IUFindSwitch(&MovementRADecSw, names[i]);
+            if (mvp == &MovementRADecS[0]) {
+                // RA+
+                returnRA+=steps[0].value;
+            } else if (mvp == &MovementRADecS[1]) {
+                // RA-
+                returnRA-=steps[0].value;
+            } else if (mvp == &MovementRADecS[2]) {
+                // Dec+
+                returnDec+=steps[1].value;
+            } else if (mvp == &MovementRADecS[3]) {
+                // Dec-
+                returnDec-=steps[1].value;
+            }
+        }
+        log("after  RA=%f  Dec=%f\n",returnRA,returnDec);
+        IUResetSwitch(&MovementRADecSw);
+        IUUpdateSwitch(&MovementRADecSw,states,names,n);
+        IDSetSwitch(&MovementRADecSw,NULL);
+        MoveScope(RADEC,returnRA,returnDec);
+        UpdateCoords();
+    }
+    else if (!strcmp(name,MovementAzAltSw.name)) {
+        if (!GetCoords(AZALT)) {
+            IDMessage(mydev,"Invalid coordinates from scope - aborted nudge.");
+        }
+        log("before     Az=%f  Alt=%f\n",returnAz,returnAlt);
+        for (int i=0; i<n; i++) {
+            states[i]=ISS_OFF;
+            ISwitch *mvp = IUFindSwitch(&MovementAzAltSw, names[i]);
+            if (mvp == &MovementAzAltS[0]) {
+                // Az+
+                returnAz+=steps[2].value;
+            } else if (mvp == &MovementAzAltS[1]) {
+                // Az-
+                returnAz-=steps[2].value;
+            } else if (mvp == &MovementAzAltS[2]) {
+                // Alt+
+                returnAlt+=steps[3].value;
+            } else if (mvp == &MovementAzAltS[3]) {
+                // Alt-
+                returnAlt-=steps[3].value;
+            }
+        }
+        log("commanded  Az=%f  Alt=%f\n",returnAz,returnAlt);
+        IUResetSwitch(&MovementAzAltSw);
+        IUUpdateSwitch(&MovementAzAltSw,states,names,n);
+        IDSetSwitch(&MovementAzAltSw,NULL);
+        MoveScope(AZALT,returnAz,returnAlt);
+        UpdateCoords();
+        log("after      Az=%f  Alt=%f\n",returnAz,returnAlt);
+    }
+    else {
+        if (ATLAS_DEBUG) log("ISNewSwitch('%s')\n",name);
+    }
+}
+
+int OrionAtlas::checkPower(ISwitchVectorProperty *sp)
+{
+    if (PowerSw.s != IPS_OK) {
+        if (!strcmp(sp->label, ""))
+            IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->name);
+        else
+            IDMessage (mydev, "Cannot change property %s while the telescope is offline.", sp->label);
+        sp->s = IPS_IDLE;
+        IDSetSwitch(sp, NULL);
+        return -1;
+    }
+    return 0;
+}
+
+int OrionAtlas::checkPower(INumberVectorProperty *np)
+{
+    if (PowerSw.s != IPS_OK) {
+        if (!strcmp(np->label, ""))
+            IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->name);
+        else
+            IDMessage (mydev, "Cannot change property %s while the telescope is offline.", np->label);
+        np->s = IPS_IDLE;
+        IDSetNumber(np, NULL);
+        return -1;
+    }
+    return 0;
+}
+
+int OrionAtlas::checkPower(ITextVectorProperty *tp)
+{
+    if (PowerSw.s != IPS_OK) {
+        if (!strcmp(tp->label, ""))
+            IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->name);
+        else
+            IDMessage (mydev, "Cannot change property %s while the telescope is offline.", tp->label);
+        tp->s = IPS_IDLE;
+        IDSetText(tp, NULL);
+        return -1;
+    }
+    return 0;
+}
+
+void OrionAtlas::getBasicData()
+{
+    if (ATLAS_DEBUG) log("getBasicData\n");
+    UpdateCoords();
+}
+
+void OrionAtlas::ConnectTel()
+{
+    if (PowerSw.sp[0].s==ISS_ON||PowerSw.sp[2].s==ISS_ON) { // CONNECT or RECONNECT
+        if (ConnectTel(Port.tp[0].text) < 0) 
+	{
+            PowerS[0].s = PowerS[2].s = ISS_OFF;
+            PowerS[1].s = ISS_ON;
+            IDSetSwitch (&PowerSw, "Error connecting to port %s", Port.tp[0].text);
+            return;
+        }
+        PowerSw.s = IPS_OK;
+        PowerS[0].s = ISS_ON;
+        PowerS[1].s = PowerS[2].s= ISS_OFF;
+        IDSetSwitch (&PowerSw, "Telescope is online. Updating coordinates.");
+        if (ATLAS_DEBUG) log("Powered on scope, calling getBasicData()\n");
+        getBasicData();
+    }
+    else if (PowerSw.sp[0].s==ISS_OFF) {
+        IDSetSwitch (&PowerSw, "Telescope is offline.");
+        DisconnectTel();
+    }
+}
+
+int OrionAtlas::CheckConnectTel(void)
+{
+    return TelConnectFlag;
+}
+
+int OrionAtlas::ConnectTel(char *port)
+{
+    struct termios tty;
+    unsigned char returnStr[128];
+    int numRead;
+
+    if (ATLAS_DEBUG) log( "Connecting to port: %s\n",port);
+
+    if(TelConnectFlag != 0)
+        return 0;
+
+    /* Make the connection */
+
+    TelPortFD = open(port,O_RDWR);
+    if(TelPortFD == -1) {
+        IDMessage(mydev,"Could not open the supplied port!");
+        return -1;
+    }
+
+    tcgetattr(TelPortFD,&tty);
+    cfsetospeed(&tty, (speed_t) B9600);
+    cfsetispeed(&tty, (speed_t) B9600);
+    tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
+    tty.c_iflag =  IGNBRK;
+    tty.c_lflag = 0;
+    tty.c_oflag = 0;
+    tty.c_cflag |= CLOCAL | CREAD;
+    tty.c_cc[VMIN] = 1;
+    tty.c_cc[VTIME] = 5;
+    tty.c_iflag &= ~(IXON|IXOFF|IXANY);
+    tty.c_cflag &= ~(PARENB | PARODD);
+    tcsetattr(TelPortFD, TCSANOW, &tty);
+
+    /* Flush the input (read) buffer */
+
+    tcflush(TelPortFD,TCIOFLUSH);
+
+    /* Test connection */
+
+    writen(TelPortFD,(unsigned char*)"?",1);
+    numRead=readn(TelPortFD,returnStr,1,2);
+    returnStr[numRead] = '\0';
+
+    if (numRead == 1 && returnStr[0]=='#') {
+        TelConnectFlag = 1;
+        IDMessage(mydev,"Successfully connected.");
+        return (0);
+    }
+    else if (numRead>0) {
+        IDMessage(mydev,"Connect failure: Did not detect an Orion Atlas EQ-G on this port!");
+        return -2;
+    }
+    else {
+        IDMessage(mydev,"Connect failure: Did not detect any device on this port!");
+        return -3;
+    }
+}
+
+void OrionAtlas::DisconnectTel(void)
+{
+    if(TelConnectFlag == 1)
+        close(TelPortFD);
+    TelConnectFlag = 0;
+    IDMessage(mydev,"Telescope is offline.");
+}
+
+// If System=RADEC, c1=RA, c2=Dec
+//          =AZALT, c1=Az, c2=Alt
+int OrionAtlas::MoveScope(int System, double c1, double c2)
+{
+    MovementRADecSw.s=MovementAzAltSw.s=eqNum.s=aaNum.s=OnCoordSetSw.s=IPS_BUSY;
+    IDSetSwitch(&MovementRADecSw,NULL);
+    IDSetSwitch(&MovementAzAltSw,NULL);
+    IDSetSwitch(&OnCoordSetSw,NULL);
+    IDSetNumber(&eqNum,NULL);
+    IDSetNumber(&aaNum,NULL);
+    union {
+        signed short int ints[2];
+        unsigned short int uints[2];
+        unsigned char bytes[4];
+    };
+
+    char Command=' ';
+    while (1) {
+        if (System==RADEC) Command='R';
+        else if (System==AZALT) Command='A';
+        else {
+            log("Invalid command '%c' to MoveScope!",Command);
+            break;
+        }
+        unsigned char sendStr[5];
+        writen(TelPortFD,(unsigned char*)"?",1);
+        int numRead=readn(TelPortFD,sendStr,1,3);
+        if (numRead!=1 || sendStr[0]!='#') {
+            IDMessage(mydev,"Failure: Scope not ready for movement command!");
+            break;
+        }
+
+        if (Command=='R') {
+            IDMessage(mydev,"Beginning slew to RA=%f Dec=%f\n",c1,c2);
+            // RA:
+            uints[0]= (unsigned short int) (c1*65536.0/24.0);
+            ints[1]=  (signed short int) (c2*65536.0/360.0);
+            sendStr[2]=bytes[0];    sendStr[1]=bytes[1];
+            sendStr[4]=bytes[2];    sendStr[3]=bytes[3];
+        }
+        else {
+            //c2=c2-lat+90.0; // decorrect
+            IDMessage(mydev,"Beginning slew to Az=%f Alt=%f\n",c1,c2);
+            // Az
+            uints[0]= (unsigned short int) (c1*65536.0/360.0);
+            ints[1]= (signed short int) (c2*65536.0/360.0);
+            sendStr[2]=bytes[0];    sendStr[1]=bytes[1];
+            sendStr[4]=bytes[2];    sendStr[3]=bytes[3];
+        }
+        sendStr[0]=Command;
+        if (ATLAS_DEBUG) log("Sending '%c' %X %X %X %X\n",Command,sendStr[1],sendStr[2],sendStr[3],sendStr[4]);
+        writen(TelPortFD,sendStr,5);
+        // it should send us an '@' when done slewing
+        numRead=readn(TelPortFD,sendStr,1,60);
+        if (numRead!=1||sendStr[0]!='@') {
+            IDMessage(mydev,"Timeout waiting for scope to complete slewing.");
+            break;
+        }
+        IDMessage(mydev,"Slewing complete.");
+
+        MovementRADecSw.s=MovementAzAltSw.s=eqNum.s=aaNum.s=OnCoordSetSw.s=IPS_OK;
+        IDSetSwitch(&MovementRADecSw,NULL);
+        IDSetSwitch(&MovementAzAltSw,NULL);
+        IDSetSwitch(&OnCoordSetSw,NULL);
+        IDSetNumber(&eqNum,NULL);
+        IDSetNumber(&aaNum,NULL);
+        return 1;
+    }
+    // only here if break = error
+    MovementRADecSw.s=MovementAzAltSw.s=eqNum.s=aaNum.s=OnCoordSetSw.s=IPS_ALERT;
+    IDSetSwitch(&MovementRADecSw,NULL);
+    IDSetSwitch(&MovementAzAltSw,NULL);
+    IDSetSwitch(&OnCoordSetSw,NULL);
+    IDSetNumber(&eqNum,NULL);
+    IDSetNumber(&aaNum,NULL);
+    return 0;
+}
+
+/* Read the telescope coordinates */
+int OrionAtlas::GetCoords(int System)
+{
+    UpdateSw.s=IPS_BUSY;
+    IDSetSwitch(&UpdateSw,NULL);
+    unsigned char returnStr[4];
+    union {
+        signed short int ints[2];
+        unsigned short int uints[2];
+        unsigned char bytes[4];
+    };
+
+    while (1) {
+        if (System&AZALT) {
+            returnAz=returnAlt=-1000;
+            if (System&RADEC) {returnRA=returnDec=-1000;}
+            // is scope ready?
+            writen(TelPortFD,(unsigned char*)"?",1);
+            int numRead=readn(TelPortFD,returnStr,1,3);
+            if (numRead!=1 || returnStr[0]!='#') {
+                IDMessage(mydev,"Failure: Scope not ready for Z command");
+                break;
+            }
+            // Send request for current Az/Alt coords
+            writen(TelPortFD,(unsigned char*)"Z",1);
+            numRead=readn(TelPortFD,returnStr,4,1);
+            if (numRead!=4) break;
+            // bytes as expected
+            if (ATLAS_DEBUG) log("Received '%c' %02x %02x %02x %02x\n",'Z',returnStr[0],returnStr[1],returnStr[2],returnStr[3]);
+
+            bytes[0]=returnStr[1];  bytes[1]=returnStr[0];
+            bytes[2]=returnStr[3];  bytes[3]=returnStr[2];
+            returnAz=uints[0]/65536.0*360.0;
+            returnAlt=ints[1]/65536.0*360.0;
+    //        returnAlt=returnAlt+lat-90.0;
+        }
+
+        if (System&RADEC) {
+            returnRA=returnDec=-1000;
+            // Check scope is ready
+            writen(TelPortFD,(unsigned char*)"?",1);
+            int numRead=readn(TelPortFD,returnStr,1,3);
+            if (numRead!=1 || returnStr[0]!='#') {
+                IDMessage(mydev,"Failure: Scope not ready for E command");
+                break;
+            }
+            // Send get RA/Dec
+            writen(TelPortFD,(unsigned char*)"E",1);
+            numRead=readn(TelPortFD,returnStr,4,1);
+            if (ATLAS_DEBUG) log("Received '%c' %02x %02x %02x %02x\n",'E',returnStr[0],returnStr[1],returnStr[2],returnStr[3]);
+            if (numRead!=4) break;
+            // bytes read is as expected
+
+            bytes[0]=returnStr[1];  bytes[1]=returnStr[0];
+            bytes[2]=returnStr[3];  bytes[3]=returnStr[2];
+            returnRA=uints[0]/65536.0*24.0;
+            returnDec=ints[1]/65536.0*360.0;
+        }
+        // Yep, data is valid.
+        UpdateSw.s=IPS_OK;
+        IDSetSwitch(&UpdateSw,NULL);
+        return(1);
+    }
+    // only here if break -> error!
+    UpdateSw.s=IPS_ALERT;
+    IDSetSwitch(&UpdateSw,NULL);
+    return 0;
+}
+
+// Get coords from scope and update INumbers
+void OrionAtlas::UpdateCoords(int System)
+{
+    if (GetCoords(System)) {
+        if (System&RADEC) {
+            eqNum.np[0].value = returnRA;
+            eqNum.np[1].value = returnDec;
+            IDSetNumber(&eqNum, NULL);
+        }
+        if (System&AZALT) {
+            aaNum.np[1].value = returnAlt;
+            aaNum.np[0].value = returnAz;
+            IDSetNumber(&aaNum, NULL);
+        }
+    }
+}
+
+int OrionAtlas::writen(int fd, unsigned char* ptr, int nbytes)
+{
+    int nleft, nwritten;
+    nleft = nbytes;
+    while (nleft > 0) {
+        nwritten = write (fd, ptr, nleft);
+        if (nwritten <=0 ) break;
+        nleft -= nwritten;
+        ptr += nwritten;
+    }
+    return (nbytes - nleft);
+}
+
+int OrionAtlas::readn(int fd, unsigned char* ptr, int nbytes, int sec)
+{
+    int status;
+    int nleft, nread;
+    nleft = nbytes;
+    while (nleft > 0) {
+        status = telstat(fd,sec,0);
+        if (status <=  0 ) break;
+        nread  = read (fd, ptr, nleft);
+
+/*  Diagnostic */
+
+/*    printf("readn: %d read\n", nread);  */
+
+        if (nread <= 0)  break;
+        nleft -= nread;
+        ptr += nread;
+    }
+    return (nbytes - nleft);
+}
+
+/*
+ * Examines the read status of a file descriptor.
+ * The timeout (sec, usec) specifies a maximum interval to
+ * wait for data to be available in the descriptor.
+ * To effect a poll, the timeout (sec, usec) should be 0.
+ * Returns non-negative value on data available.
+ * 0 indicates that the time limit referred by timeout expired.
+ * On failure, it returns -1 and errno is set to indicate the
+ * error.
+ */
+
+int OrionAtlas::telstat(int fd,int sec,int usec)
+{
+    int ret;
+    int width;
+    struct timeval timeout;
+    telfds readfds;
+
+    memset((char *)&readfds,0,sizeof(readfds));
+    FD_SET(fd, &readfds);
+    width = fd+1;
+    timeout.tv_sec = sec;
+    timeout.tv_usec = usec;
+    ret = select(width,&readfds,(telfds *)0,(telfds *)0,&timeout);
+    return(ret);
+}
+
+void OrionAtlas::ISPoll()
+{
+    // Called every 2 seconds.
+    if (!TelConnectFlag) return;
+    if (!Updating) return;
+    // Check status of
+    if (eqNum.s==IPS_IDLE||eqNum.s==IPS_OK) {
+        GetCoords();
+        eqNum.np[0].value=returnRA;
+        eqNum.np[1].value=returnDec;
+        aaNum.np[0].value=returnAz;
+        aaNum.np[1].value=returnAlt;
+        IDSetNumber(&eqNum,NULL);
+        IDSetNumber(&aaNum,NULL);
+    }
+    else { // Slewing.  Don't get coords yet.
+        if (ATLAS_DEBUG) log("   (still slewing)\n");
+    }
+}
+
+void OrionAtlas::log(const char *fmt,...)
+{
+    if (fmt) {
+        va_list ap;
+        va_start (ap, fmt);
+        fprintf(stderr, "%i: ", ((int) time(NULL)));
+        vfprintf(stderr, fmt, ap);
+        va_end(ap);
+    }
+}
Index: /BAORadio/libindi/v1/drivers/telescope/orionatlas.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/orionatlas.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/orionatlas.h	(revision 500)
@@ -0,0 +1,83 @@
+/*
+    Celestron GPS
+    Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef ORIONATLAS_H
+#define ORIONATLAS_H
+
+#include <sys/types.h>
+
+#include "indidevapi.h"
+#include "indicom.h"
+
+#define RADEC 1
+#define AZALT 2
+
+class OrionAtlas
+{
+ typedef fd_set telfds;
+
+ public:
+ OrionAtlas();
+ virtual ~OrionAtlas() {}
+
+ virtual void ISGetProperties (const char *dev);
+ virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+ virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+ virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+ virtual void ISPoll ();
+ virtual void getBasicData();
+
+ int checkPower(INumberVectorProperty *np);
+ int checkPower(ISwitchVectorProperty *sp);
+ int checkPower(ITextVectorProperty *tp);
+ void ConnectTel();
+ void log(const char *fmt,...);
+// void slewError(int slewCode);
+// int handleCoordSet();
+// int getOnSwitch(ISwitchVectorProperty *sp);
+
+ private:
+  int timeFormat;
+
+  int CheckConnectTel(void);
+  int ConnectTel(char *port);
+  void DisconnectTel(void);
+  int GetCoords(int System=RADEC|AZALT); // Retrieve coordinates from scope
+  void UpdateCoords(int System=RADEC|AZALT); // Retrieve coordinates and update INumbers
+  int MoveScope(int System, double Coord1, double Coord2); // move the scope
+
+  int TelPortFD;
+  int TelConnectFlag;
+
+  double returnRA;    /* Last update of RA */
+  double returnDec;   /* Last update of Dec */
+  double returnAz;
+  double returnAlt;
+  //double lat,lon;
+
+  int readn(int fd, unsigned char *ptr, int nbytes, int sec);
+  int writen(int fd, unsigned char *ptr, int nbytes);
+  int telstat(int fd,int sec,int usec);
+
+  bool Updating;
+};
+
+#endif
+
Index: /BAORadio/libindi/v1/drivers/telescope/skycommander.c
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/skycommander.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/skycommander.c	(revision 500)
@@ -0,0 +1,199 @@
+#if 0
+    Sky Commander INDI driver
+    Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "indidevapi.h"
+#include "indicom.h"
+#include "lx200driver.h"
+
+#define mydev		"Sky Commander"
+#define BASIC_GROUP	"Main Control"
+#define POLLMS		1000
+#define currentRA	eq[0].value
+#define currentDEC	eq[1].value
+
+static void ISPoll(void *);
+static void ISInit(void);
+static void connectTelescope(void);
+
+int fd;
+
+static ISwitch PowerS[]          = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+ISwitchVectorProperty PowerSP		= { mydev, "CONNECTION" , "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+
+static IText PortT[]			= {{"PORT", "Port", 0, 0, 0, 0}};
+static ITextVectorProperty PortTP		= { mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0};
+
+/* equatorial position */
+INumber eq[] = {
+    {"RA",  "RA  H:M:S", "%10.6m",  0., 24., 0., 0., 0, 0, 0},
+    {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0},
+};
+INumberVectorProperty eqNum = {
+    mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 0, IPS_IDLE,
+    eq, NARRAY(eq), "", 0};
+
+
+void ISInit(void)
+{
+  static int isInit=0;
+
+  if (isInit) return;
+
+  isInit = 1;
+  fd = -1;
+
+  IEAddTimer (POLLMS, ISPoll, NULL);
+
+}
+
+void ISGetProperties (const char *dev)
+{
+  
+  ISInit(); 
+
+  dev=dev;
+
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefText(&PortTP, NULL);
+  IDDefNumber(&eqNum, NULL);
+}
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+   ISInit();
+
+   dev = dev;
+
+   if (!strcmp(name, PowerSP.name))
+   {
+      IUResetSwitch(&PowerSP);
+      IUUpdateSwitch(&PowerSP, states, names, n);
+      connectTelescope();
+      return;
+   }
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+
+  ISInit();
+
+  dev=dev; names=names; n=n;
+
+  if (!strcmp(name, PortTP.name))
+  {
+    IUSaveText(&PortT[0], texts[0]);
+    PortTP.s = IPS_OK;
+    IDSetText(&PortTP, NULL);
+    return;
+  }
+
+}
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+ dev=dev;name=name;values=values;names=names;n=n;
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+void ISPoll (void *p)
+{
+  p=p;
+
+  if (PowerS[0].s == ISS_ON)
+  {
+  	switch (eqNum.s)
+		{
+		case IPS_IDLE:
+	        case IPS_OK:
+	        case IPS_BUSY:
+	        if (updateSkyCommanderCoord(fd, &currentRA, &currentDEC) < 0)
+                 {
+                   eqNum.s = IPS_ALERT;
+                   IDSetNumber(&eqNum, "Unknown error while reading telescope coordinates");
+                   IDLog("Unknown error while reading telescope coordinates\n");
+                   break;
+                 }
+
+	        IDSetNumber(&eqNum, NULL);
+	        break;
+	        
+	        case IPS_ALERT:
+	    	break;
+		}
+  }
+
+  IEAddTimer(POLLMS, ISPoll, NULL);
+}
+
+void connectTelescope(void)
+{
+
+  switch (PowerS[0].s)
+  {
+    case ISS_ON:
+     if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK)
+     {
+       PowerSP.s = IPS_ALERT;
+       IUResetSwitch(&PowerSP);
+       IDSetSwitch(&PowerSP, "Error connecting to port %s", PortT[0].text);
+       return;
+     }
+
+     PowerSP.s = IPS_OK;
+     IDSetSwitch(&PowerSP, "Sky Commander is online.");
+     break;
+
+   case ISS_OFF:
+	tty_disconnect(fd);
+	IUResetSwitch(&PowerSP);
+        eqNum.s = PortTP.s = PowerSP.s = IPS_IDLE;
+	IDSetSwitch(&PowerSP, "Sky Commander is offline.");
+        IDSetText(&PortTP, NULL);
+	IDSetNumber(&eqNum, NULL);
+	break;
+  }
+
+}
+
Index: /BAORadio/libindi/v1/drivers/telescope/temmadriver.c
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/temmadriver.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/temmadriver.c	(revision 500)
@@ -0,0 +1,1010 @@
+#if 0
+	Temma INDI driver
+	Copyright (C) 2004 Francois Meyer (dulle @ free.fr)
+	Remi Petitdemange for the temma protocol
+  Reference site is http://dulle.free.fr/alidade/indi.php
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <time.h>
+
+#include <config.h>
+
+#include <libnova.h>
+
+#include "indicom.h"
+#include "indidevapi.h"
+#include "eventloop.h"
+#include "indicom.h"
+#include "temmadriver.h"
+
+
+	char errormes[][128]={
+		"I/O Timeout",
+		"Error reading from io port",
+		"Error writing to io port",
+		"Unrecognized message"
+	};
+
+char answer[32];
+int fd;
+int read_ret, write_ret;
+unsigned char buffer[256];
+unsigned char buffer2[256];
+
+
+#if 1
+/* Initlization routine */
+static void mountInit()
+{
+	static int inited;		/* set once mountInit is called */
+
+	if (inited)
+		return;
+
+	/* setting default comm port */	
+	PortT->text = realloc(PortT->text, 10);
+	TemmaNoteT[0].text = realloc( TemmaNoteT[0].text, 64);
+	TemmaNoteT[1].text = realloc( TemmaNoteT[1].text, 64);
+	
+	if (!PortT->text || !TemmaNoteT[0].text || !TemmaNoteT[1].text){
+		fprintf(stderr,"Memory allocation error");
+		return;
+	}
+	strcpy(PortT->text, "/dev/ttyS0");
+	strcpy(TemmaNoteT[0].text, "Experimental Driver");
+	strcpy(TemmaNoteT[1].text, "http://dulle.free.fr/alidade/indi.php");
+
+	inited = 1;
+}
+#endif
+
+void ISGetProperties (const char *dev) {
+	if (dev && strcmp (mydev, dev))
+		return;
+
+	mountInit();
+
+	IDDefSwitch (&powSw, NULL);
+	IDDefNumber (&eqTemma, NULL);
+	IDDefNumber (&eqNum, NULL);
+	IDDefSwitch (&OnCoordSetSw, NULL);
+	IDDefSwitch (&abortSlewSw, NULL);
+	IDDefText   (&TemmaNoteTP, NULL);
+	IDDefSwitch (&RAmotorSw, NULL);
+	IDDefSwitch (&trackmodeSw, NULL);
+	IDDefText (&Port, NULL);
+	IDDefText (&TemmaVersion, NULL);
+	IDDefNumber (&Time, NULL);
+	IDDefNumber (&SDTime, NULL);
+	IDDefNumber (&cometNum, NULL);
+	IDDefNumber (&geoNum, NULL);
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) 
+{
+
+	INDI_UNUSED(names);
+	INDI_UNUSED(n);
+
+	if (strcmp (dev, mydev))
+		return;
+
+	if (!strcmp (name, Port.name)) {
+		IUSaveText(PortT, texts[0]);
+		Port.s = IPS_OK;
+		IDSetText (&Port, NULL);
+	}
+	return;
+}
+
+/* client is sending us a new value for a Numeric vector property */
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) {
+	/* ignore if not ours */
+	if (strcmp (dev, mydev))
+		return;
+
+	if (!strcmp (name, eqNum.name)) {
+		/* new equatorial target coords */
+	        /*double newra = 0, newdec = 0;*/
+		int i, nset;
+
+		/* Check power, if it is off, then return */
+		if (power[0].s != ISS_ON)
+		{
+			eqNum.s = IPS_IDLE;
+			IDSetNumber(&eqNum, "Power is off");
+			return;
+		}
+
+		for (nset = i = 0; i < n; i++) {
+			/* Find numbers with the passed names in the eqNum property */
+			INumber *eqp = IUFindNumber (&eqNum, names[i]);
+
+			/* If the number found is Right ascension (eq[0]) then process it */
+			if (eqp == &eq[0])
+			{
+				currentRA = (values[i]);
+				nset += currentRA >= 0 && currentRA <= 24;
+			}
+			/* Otherwise, if the number found is Declination (eq[1]) then process it */ 
+			else if (eqp == &eq[1]) {
+				currentDec = (values[i]);
+				nset += currentDec >= -90 && currentDec <= 90;
+			}
+		} /* end for */
+
+		/* Did we process the two numbers? */
+		if (nset == 2) {
+		        /*char r[32], d[32];*/
+
+			/* Set the mount state to BUSY */
+			eqNum.s = IPS_BUSY;
+
+			if (SLEWSW==ISS_ON || TRACKSW==ISS_ON){
+				IDSetNumber(&eqNum, "Moving to RA Dec %f %f", currentRA,
+						currentDec);
+				do_TemmaGOTO();
+			}
+
+			if (SYNCSW==ISS_ON){
+				IDSetNumber(&eqNum, "Syncing to RA Dec %f %f", currentRA, currentDec);
+				set_TemmaCurrentpos();
+			}
+			eqNum.s = IPS_OK;
+			IDSetNumber(&eqNum, "Synced");
+		}
+		/* We didn't process the two number correctly, report an error */
+		else {
+			/* Set property state to idle */
+			eqNum.s = IPS_IDLE;
+
+			IDSetNumber(&eqNum, "RA or Dec absent or bogus.");
+		}
+	return;
+	}
+}
+
+/* client is sending us a new value for a Switch property */
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	ISwitch *sp;
+
+	/* ignore if not ours */
+	if (strcmp (dev, mydev))
+		return;
+
+	if (!strcmp (name, powSw.name)) {
+		sp = IUFindSwitch (&powSw, names[0]);
+		if (!sp)
+			return;
+
+		fprintf(stderr,"new state %s\n",names[0]);
+
+		sp->s = states[0];
+		if (!strcmp(names[0],"CONNECT")) {
+			connectMount();
+		}		
+		if (!strcmp(names[0],"DISCONNECT")) {
+			disconnectMount();
+		}		
+	}
+
+	if (!strcmp (name, abortSlewSw.name)) {
+		if (POWSW){
+			TemmaabortSlew(); 
+			IDSetSwitch (&abortSlewSw, "Abort slew");
+		}
+		else {
+			IDSetSwitch (&abortSlewSw, "Power is off");
+		}
+	}
+
+	if (!strcmp (name, RAmotorSw.name)) {
+		if (POWSW){
+			sp = IUFindSwitch (&RAmotorSw, names[0]);
+			if (!sp)
+				return;
+
+			fprintf(stderr,"new state %s\n",names[0]);
+
+			sp->s = states[0];
+
+			RAmotorSw.s = IPS_BUSY;
+			if (!strcmp(names[0],"RUN")) {
+				set_TemmaStandbyState(0);
+			}
+
+			if (!strcmp(names[0],"STOP")) {
+				set_TemmaStandbyState(1);
+			}	
+
+			if(get_TemmaStandbyState(buffer)){
+				RAmotorSw.s = IPS_IDLE;
+				IDSetSwitch (&RAmotorSw, "Error writing to port");
+				return;
+			}
+		}
+		else {
+			IDSetSwitch (&RAmotorSw, "Power is off");
+		}
+	}
+
+	if (!strcmp (name, OnCoordSetSw.name)) {
+		if (POWSW){
+			IUResetSwitch(&OnCoordSetSw);
+			sp = IUFindSwitch (&OnCoordSetSw, names[0]);
+			if (!sp)
+				return;
+
+			fprintf(stderr,"new state %s\n",names[0]);
+
+			sp->s = states[0];
+
+			IUResetSwitch(&OnCoordSetSw);
+			IUUpdateSwitch(&OnCoordSetSw, states, names, n);
+			/*			    currentSet = getOnSwitch(&OnCoordSetSw); */
+			OnCoordSetSw.s = IPS_OK;
+			IDSetSwitch(&OnCoordSetSw, NULL);
+		}
+		else {
+			IDSetSwitch (&OnCoordSetSw, "Power is off");
+		}
+	}
+}
+
+double calcLST(char *strlst){
+	double jd,gmst,lst;
+
+	jd = ln_get_julian_from_sys();
+	gmst = ln_get_mean_sidereal_time(jd);
+
+	lst=(gmst-longitude)/15;	
+
+	lst=(lst/24-(int)(lst/24))*24;
+
+	if(lst>=24) 
+		lst-=24;
+	sprintf(strlst,"%.2d%.2d%.2d", (int)lst,
+			((int)(lst*60))%60,
+			((int)(lst*3600))%60);
+	currentLST=lst;
+	IDSetNumber (&SDTime, NULL);
+	IDSetNumber (&Time, NULL);
+	
+	return 0;
+}
+
+#if 1
+/* update the mount over time */
+void readMountcurrentpos (void *p)
+{
+	INDI_UNUSED(p);
+
+	char result[32];
+
+	if(POWSW){
+		get_TemmaCurrentpos(result);
+		calcLST(result);
+
+		/* This is a temporary workaround to allow
+		   clients with only one eq property to work */
+		currentRA=temmaRA;
+		currentDec=temmaDec;
+
+		/* again */
+		IEAddTimer (POLLMS, readMountcurrentpos, NULL);
+	}
+}
+#endif
+
+static void connectMount () {
+	fprintf(stderr,"opening mount port %s\n",PortT->text);
+	if (power[0].s == ISS_ON){
+		if (Port.s != IPS_OK){
+			powSw.s = IPS_IDLE;
+			power[0].s = ISS_OFF;
+
+			IDSetSwitch (&powSw, "Port not set.");
+			return;
+		}
+		else {
+			if (TemmaConnect(PortT->text)==0){
+				IDSetText (&Port, "Port is opened.");
+				if( !get_TemmaVERSION(buffer)){
+					powSw.s = IPS_OK;
+					power[0].s = ISS_ON;
+					power[1].s = ISS_OFF;
+					snprintf(buffer2,sizeof( buffer2 ),"%s",buffer+4);
+
+					IDSetText(&TemmaVersion , "Temma version set");
+					TemmaVersionT->text = realloc(TemmaVersionT->text, strlen(buffer2)+1);
+					if (!TemmaVersionT->text){
+						fprintf(stderr,"Memory allocation error");
+						return;
+					}
+					IDSetSwitch (&powSw, "Mount is ready");
+					IDSetSwitch (&powSw, VERSION);
+
+					strcpy(TemmaVersionT->text, buffer2);
+					TemmaVersion.s = IPS_OK; 
+					IDSetText (&TemmaVersion, NULL);
+					IDLog("%s", buffer2);
+					/* start timer to read mount coords */
+					IEAddTimer (POLLMS, readMountcurrentpos, NULL);
+				}
+				else {
+					powSw.s = IPS_IDLE;
+					power[0].s = ISS_OFF;
+					power[1].s = ISS_ON;
+					IDSetText(&Port , "Com error");
+					IDSetSwitch (&powSw, "Port not set.");
+				}
+
+				if(get_TemmaStandbyState(answer)){
+					IDSetSwitch (&RAmotorSw, "Error writing to port");
+					return;
+				}
+			}
+			else {
+				powSw.s = IPS_IDLE;
+				power[0].s = ISS_OFF;
+				power[1].s = ISS_ON;
+
+				IDSetSwitch (&powSw, "Failed to open port.");
+			}
+		}
+	}
+}
+
+static void disconnectMount () {
+	fprintf(stderr,"closing mount port %s\n",PortT->text);
+	if (power[1].s == ISS_ON){
+		if (Port.s != IPS_OK){
+			powSw.s = IPS_IDLE;
+			power[0].s = ISS_OFF;
+
+			IDSetSwitch (&powSw, "Port not set.");
+			return;
+		}
+		else {
+			TemmaDisconnect();
+			powSw.s = IPS_IDLE;
+			power[0].s = ISS_OFF;
+
+			IDSetSwitch (&powSw, "Port is closed.");
+		}
+	}
+	else {
+		fprintf(stderr, "Already disconnected \n");
+	}
+}
+
+int TemmaConnect(const char *device) {
+	fprintf(stderr, "Connecting to device %s\n", device);
+
+	if (openPort(device) < 0){
+		fprintf(stderr, "Error connecting to device %s\n", device);
+		return -1;
+	}
+	else{
+		return 0;
+	}
+}
+
+int TemmaDisconnect() {
+	fprintf(stderr, "Disconnected.\n");
+	close(fd);
+	
+	return 0;
+}
+
+int set_CometTracking(int RArate, int DECrate){
+#if 0
+	Set Comet Tracking
+	LM+/-99999,+/-9999
+	RA : Adjust Sidereal time by seconds per Day	
+
+	DEC : Adjust DEC tracking by Minutes Per Day			
+	valeur DEC min=-600 /max=+600 (+/-10 deg / jour)
+
+	Example:
+	LM+120,+30 would slow the RA speed by 86164/86284 and 		
+	the Dec would track at 30 Minutes a day.
+	To stop tracking either send a LM0,0 (or a PS 
+	sauf erreur on constate en faite l inverse en RA
+	retour Vsideral => LM0,0 ou LM+0,+0
+#endif
+	char local_buffer[16];
+
+	if (RArate<-21541){
+	RArate=-21541;
+	}
+
+	if (RArate>21541){
+	RArate=21541;
+	}
+
+	if (DECrate<-600){
+	DECrate=-600;
+	}
+
+	if (DECrate>600){
+	DECrate=600;
+	}
+
+	snprintf(local_buffer, sizeof( local_buffer ), "%+6d,%+5d", RArate, DECrate);
+	set_TemmaCometTracking(local_buffer);
+	
+	return 0;
+}
+
+int TemmaabortSlew() {
+	if (portWrite("PS") < 0)
+		return -1;
+
+	return 0;
+}
+
+int do_TemmaGOTO() {
+	/* Temma Sync */
+	char command[16];
+	char sign;
+	double dec;
+
+	calcLST(buffer);
+	set_TemmaLST(buffer);
+
+	dec=fabs(currentDec);
+	if (currentDec>0){
+		sign='+';
+	}
+	else {
+		sign='-';
+	}
+
+	snprintf(buffer, sizeof(buffer),"%.2d%.2d%.2d%c%.2d%.2d%.1d",
+			(int)currentRA,(int)(currentRA*(double)60)%60,((int)(currentRA*(double)6000))%100,sign,
+			(int)dec,(int)(dec*(double)60)%60,((int)(dec*(double)600))%10);
+	fprintf(stderr,"Goto %s\n", buffer);
+
+	snprintf(command,14,"P%s",buffer);
+	buffer[14]=0;
+	fprintf(stderr,"Goto command:%s\n", command);
+	portWrite(command);
+
+	portRead(buffer,-1,TEMMA_TIMEOUT);
+	if(command[0]=='R'){
+		return 0;
+	}
+	else
+		return -1;
+}
+
+int extractRA(char *buf){
+	int r,h,m,s;
+	/*double dra;*/
+
+	r=atoi(buf);
+	h=r/10000;
+	m=r/100-100*h;
+	s=(r%100)*.6;
+	temmaRA=((double)h+((double)m + (double)s/60)/60);
+	IDSetNumber (&eqTemma, NULL);
+	/*	fprintf(stderr,"extractRA: %s %d %d %d %d %lf\n",buf,r,h,m,s,dra);*/
+	return 0;
+}
+
+int extractDEC(char *buf){
+	int dec,d,m,s;
+	/*double ddec;*/
+
+	dec=atoi(buf+1);
+	d=dec/1000;
+	m=dec/10-100*d;
+	s=(dec%10)*6;
+	temmaDec=((double)d+((double)m + (double)s/60)/60);
+	if (*buf=='-')	
+		temmaDec*=-1;
+
+	IDSetNumber (&eqTemma, NULL);
+
+
+	/*	fprintf(stderr,"extractDEC: %s %d %d %d %d %lf\n",buf,dec,d,m,s,ddec);*/
+	return 0;
+}
+
+
+int get_TemmaCurrentpos(char *local_buffer){
+	char buf[16];
+
+	if (portWrite("E") < 0)
+		return -1;
+
+	if(portRead(local_buffer,-1,TEMMA_TIMEOUT)==SUCCESS){
+		if(strstr(local_buffer, "E")==local_buffer){
+			strncpy(buf,local_buffer+1,6);
+			buf[6]=0;
+			extractRA(buf);
+
+			strncpy(buf,local_buffer+7,6);
+			buf[6]=0;
+			extractDEC(buf);
+			return 0;
+		}
+		else {
+			return -1;
+		}
+	}
+	
+	return 0;
+}
+
+int set_TemmaCurrentpos(void) {
+	/* Temma Sync */
+	char buf[16], sign;
+	double dec;
+
+	calcLST(buf);
+	set_TemmaLST(buf);
+	portWrite("Z");
+	calcLST(buf);
+	set_TemmaLST(buf);
+
+	dec=fabs(currentDec);
+	if (currentDec>0){
+		sign='+';
+	}
+	else {
+		sign='-';
+	}
+
+	sprintf(buffer,"%.2d%.2d%.2d%c%.2d%.2d%.1d",
+			(int)currentRA,(int)(currentRA*(double)60)%60,((int)(currentRA*(double)6000))%100,sign,
+			(int)dec,(int)(dec*(double)60)%60,((int)(dec*(double)600))%10);
+	fprintf(stderr,"sync to %s %f %f\n", buffer,currentRA,dec);
+
+	snprintf(buf, sizeof(buf), "D%s",buffer);
+	buf[13]=0;
+	portWrite(buf);
+	*buffer=0;
+
+	portRead(buffer,-1,TEMMA_TIMEOUT);
+	if(buffer[0]=='R'){
+		return 0;
+	}
+	else{
+		return -1;
+	}
+}
+
+int do_TemmaSLEW(char mode){
+  	/*char command[16];*/
+
+	sprintf(buffer,"M%c",mode); /* see bit definition in Temmadriver.h */
+
+	if (portWrite(buffer) < 0)
+		return -1;
+	
+	return 0;
+}
+
+int get_TemmaVERSION(char *local_buffer){
+	int err;
+
+	if ((err=portWrite("v")) < 0){
+		return err;
+	}
+
+	portRead(local_buffer,-1,TEMMA_TIMEOUT);
+	if(strstr(local_buffer, "ver")==local_buffer){
+		return 0;
+	}
+	else
+		return EREAD;
+}
+
+int get_TemmaGOTOstatus(char *local_buffer){
+	/* 
+	   0 no ongoing goto
+	   1 ongoing Goto
+	   -1 error
+	 */
+	if (portWrite("s") < 0)
+		return -1;
+
+	portRead(local_buffer,-1,TEMMA_TIMEOUT);
+	if(strstr(local_buffer, "s")==local_buffer){
+		return 0;
+	}
+	else
+		return -1;
+}
+
+int get_TemmaBOTHcorrspeed(char *local_buffer){
+	if (portWrite("lg") < 0)
+		return -1;
+	portRead(local_buffer,-1,TEMMA_TIMEOUT);
+	if(strstr(local_buffer, "lg")==local_buffer){
+		return 0;
+	}
+	else
+		return -1;
+}
+
+int get_TemmaDECcorrspeed(char *local_buffer){
+	if (portWrite("lb") < 0)
+		return -1;
+	portRead(local_buffer,-1,TEMMA_TIMEOUT);
+	if(strstr(local_buffer, "lb")==local_buffer){
+		return 0;
+	}
+	else
+		return -1;
+}
+
+int set_TemmaDECcorrspeed(char *local_buffer){
+	char command[16];
+
+	snprintf(command, 4, "LB%s",local_buffer);
+
+	if (portWrite(command) < 0)
+		return -1;
+	return 0;
+}
+
+int get_TemmaRAcorrspeed(char *local_buffer){
+	if (portWrite("la") < 0)
+		return -1;
+
+	portRead(local_buffer,-1,TEMMA_TIMEOUT);
+	if(strstr(local_buffer, "la")==local_buffer){
+		return 0;
+	}
+	else
+		return -1;
+}
+
+int set_TemmaRAcorrspeed(char *local_buffer){
+	char command[16];
+
+	snprintf(command, 4,"LA%s",local_buffer);
+
+	if (portWrite(command) < 0)
+		return -1;
+	return 0;
+}
+
+int get_TemmaLatitude(char *local_buffer){
+	if (portWrite("i") < 0)
+		return -1;
+	portRead(local_buffer,-1,TEMMA_TIMEOUT);
+	if(local_buffer[0]=='i'){
+		return 0;
+	}
+	else 
+		return -1;
+}
+
+int set_TemmaLatitude(char *local_buffer){
+	char command[16];
+	double lat;
+	char sign;
+
+	lat=fabs(latitude);
+	if (latitude>0){
+		sign='+';
+	}
+	else {
+		sign='-';
+	}
+
+	sprintf(command,"I%c%.2d%.2d%.1d", sign,
+			(int)lat,
+			(int)(lat*(double)60)%60,
+			((int)(lat*(double)600))%10);
+
+	if (portWrite(command) < 0)
+		return -1;
+	return 0;
+}
+
+int get_TemmaLST(char *local_buffer){
+	if (portWrite("g") < 0)
+		return -1;
+
+	portRead(local_buffer,-1,TEMMA_TIMEOUT);
+	if(local_buffer[0]=='g'){
+		return 0;
+	}
+	else 
+		return -1;
+}
+
+
+int set_TemmaLST(char *local_buffer){
+	char command[16];
+	snprintf(command,7,"T%s",local_buffer);
+
+	if (portWrite(command) < 0)
+		return -1;
+	return 0;
+}
+
+
+int get_TemmaCometTracking(char *local_buffer){
+	if (portWrite("lm") < 0)
+		return -1;
+	portRead(local_buffer,-1,TEMMA_TIMEOUT);
+	if(strstr(local_buffer, "lm")==local_buffer){
+		return 0;
+	}
+	else 
+		return -1;
+}
+
+int set_TemmaStandbyState(int on){
+	if (on){
+		return portWrite("STN-ON");
+	}
+	else{
+		return portWrite("STN-OFF");
+	}
+	return 0;
+}
+
+int get_TemmaStandbyState(unsigned char *local_buffer){
+	int nb;
+	int status;
+
+	if ((nb=portWrite("STN-COD")) < 0){
+		IDSetSwitch (&RAmotorSw, "I/O error when asking RAmotor status");
+		return -1;
+	}
+
+	if((status=portRead(local_buffer,-1,TEMMA_TIMEOUT)==SUCCESS)){
+		if(strstr(local_buffer, "stn")==local_buffer){
+			local_buffer[7]=0;
+			if (strstr(local_buffer,"on")){ /* stanby on */
+				RAmotorSw.s = IPS_OK;
+				RAmotor[0].s = ISS_OFF;
+				RAmotor[1].s = ISS_ON;
+				IDSetSwitch (&RAmotorSw, "RA motor is off.");
+			}
+			else{
+				if (strstr(local_buffer,"off")){ /* stanby off */ 
+					RAmotorSw.s = IPS_OK;
+					RAmotor[0].s = ISS_ON;
+					RAmotor[1].s = ISS_OFF;
+					IDSetSwitch (&RAmotorSw, "RA motor is on.");
+				}
+				else {
+					RAmotorSw.s = IPS_OK;
+					IDSetSwitch (&RAmotorSw, "I/O error when getting RAmotor status");
+				}
+			}
+		}
+		return 0;
+	}
+	if (status<=ETIMEOUT && status >=ECOMMAND){
+		IDSetSwitch(&RAmotorSw, "%s", errormes[ETIMEOUT - status]);
+	}
+	
+	return -1;
+}
+
+int set_TemmaCometTracking(char *local_buffer){
+	char command[16];
+
+	snprintf(command,15,"LM%s",local_buffer);
+	if (portWrite(command) < 0)
+		return -1;
+	return 0;
+}
+
+int set_TemmaSolarRate(void){
+	if (portWrite("LK") < 0)
+		return -1;
+	return 0;
+}
+
+int set_TemmaStellarRate(void){
+	if (portWrite("LL") < 0)
+		return -1;
+	return 0;
+}
+
+
+int switch_Temmamountside(void){
+	if (portWrite("PT") < 0)
+		return -1;
+	return 0;
+}
+
+/**********************************************************************
+ * Comm
+ **********************************************************************/
+
+int openPort(const char *portID) {
+	struct termios ttyOptions;
+
+	if ( (fd = open(portID, O_RDWR)) == -1)
+		return -1;
+	memset(&ttyOptions, 0, sizeof(ttyOptions));
+	tcgetattr(fd, &ttyOptions);
+
+	/* 8 bit, enable read */
+	ttyOptions.c_cflag |= CS8;
+	/* parity */
+	ttyOptions.c_cflag |= PARENB;
+	ttyOptions.c_cflag &= ~PARODD;
+	ttyOptions.c_cflag &= ~CSTOPB;
+	ttyOptions.c_cflag |= CRTSCTS;
+
+	/* set baud rate */
+	cfsetispeed(&ttyOptions, B19200);
+	cfsetospeed(&ttyOptions, B19200);
+
+	/* set input/output flags */
+	ttyOptions.c_iflag = IGNBRK;
+
+	/* Read at least one byte */
+	ttyOptions.c_cc[VMIN] = 1;
+	ttyOptions.c_cc[VTIME] = 5;
+
+	/* Misc. */
+	ttyOptions.c_lflag = 0;
+	ttyOptions.c_oflag = 0;
+
+	/* set attributes */
+	tcsetattr(fd, TCSANOW, &ttyOptions);
+
+	/* flush the channel */
+	tcflush(fd, TCIOFLUSH);
+	return (fd);
+}
+
+int portWrite(char * buf) {
+  int nbytes=strlen(buf); /*, totalBytesWritten;*/
+	int bytesWritten = 0; 
+	/*int retry=10;*/
+
+	bytesWritten = write(fd, buf, nbytes);
+	bytesWritten += write(fd, "\r\n", 2);
+	/*fprintf(stderr,"portwrite :%d octets %s\n", bytesWritten, buf);*/
+
+	if (bytesWritten!=nbytes+2){
+		perror("write error: ");
+		IDLog("Error writing to port");
+		return EWRITE;
+	}
+	return (bytesWritten);
+}
+
+int portRead(char *buf, int nbytes, int timeout) {
+	/*
+	   A very basic finite state machine monitors
+	   the bytes read ; 
+	   state 0 : read regular bytes
+	   state 1 : just read a \n, waiting for a \r
+	   state 2 : read a \n and a \r, command is over.
+
+	   Not sure it is useful here but I use a more
+	   sophisticated version of this with a GPS receiver
+	   and it is robust and reliable
+
+	   We return a null terminated string.
+	 */
+
+  int bytesRead = 0, state=0, /*i=0,*/ current=0;
+  /*int totalBytesRead = 0;*/
+	int err;
+
+	if ( (err = TemmareadOut(timeout)) ){
+		switch (err){
+			case ETIMEOUT:
+				IDLog("Error: timeout while reading");
+				return err;
+		}
+	}
+
+	while (read(fd,buf+bytesRead,1)==1){
+		/*		fprintf(stderr,"%c",buf[bytesRead]); */
+		fflush(NULL);
+		switch (state) {
+			case 0:
+				if(buf[bytesRead]==13)
+					state=1;
+				break;
+
+			case 1:
+				if(buf[bytesRead]==10)
+					state=2;
+				else
+					if(buf[bytesRead]==13)
+						state=1;
+					else
+						state=0;
+				break;
+		}
+
+		++current;
+
+		if (state==2){
+			/*process(buf);*/
+			buf[bytesRead+1]=0;
+			state=current=0;
+			return SUCCESS;
+		}
+
+		bytesRead=current;
+	}
+	return state;
+}
+
+int TemmareadOut(int timeout) {
+	struct timeval tv;
+	fd_set readout;
+	int retval;
+
+	FD_ZERO(&readout);
+	FD_SET(fd, &readout);
+
+	/* wait for 'timeout' seconds */
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+
+	/* Wait till we have a change in the fd status */
+	retval = select (fd+1, &readout, NULL, NULL, &tv);
+
+	/* Return 0 on successful fd change */
+	if (retval > 0)
+		return 0;
+	/* Return -1 due to an error */
+	else if (retval == EREAD)
+		return retval;
+	/* Return -2 if time expires before anything interesting happens */
+	else {
+		return ETIMEOUT;
+	}
+}
+
Index: /BAORadio/libindi/v1/drivers/telescope/temmadriver.h
===================================================================
--- /BAORadio/libindi/v1/drivers/telescope/temmadriver.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/telescope/temmadriver.h	(revision 500)
@@ -0,0 +1,252 @@
+/*
+	Temma INDI driver
+	Copyright (C) 2004 Francois Meyer (dulle @ free.fr)
+	Remi Petitdemange for the temma protocol
+  Reference site is http://dulle.free.fr/alidade/indi.php
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ 
+ */
+
+#ifndef TEMMADRIVER_H
+#define TEMMADRIVER_H
+#define VERSION "Temma indi driver Ver 0.0, fm-2004/10/09" 
+#if 0
+bit definition for M message : slew speed and parameters
+#endif
+#define HS 0x01   /* high speed */
+#define RR 0x02		/* RA right */
+#define RL 0x04		/* RA left */
+#define DU 0x08		/* DEC up */
+#define DD 0x10   /* DEC down */
+#define EN 0x20		/* ENC on */
+#define BB 0x40		/* Always set */
+#if 0
+(HS|RR|EN|BB)
+#endif
+#define HRAD	(M_PI/12)
+#define DEGRAD	(M_PI/180)
+#define TEMMA_TIMEOUT	1		/* FD timeout in seconds */
+
+	/* error codes */
+#define	SUCCESS (2) /* return value for successful read */
+#define ETIMEOUT (-2) 	/* timeout */
+#define EREAD (-3) 			 /* error reading from port */	
+#define EWRITE (-4) 		 /* error writing to port */
+#define ECOMMAND (-5) /* unexpected answer */
+	/* Definitions */
+
+#define	mydev	 "Temma"	/* Device name */
+#define MAIN_GROUP "Main Control"	/* Group name */
+#define COMM_GROUP "Communication"	/* Group name */
+#define MOVE_GROUP	"Movement Control"
+#define DATETIME_GROUP	"Date/Time/Location"
+
+#define SLEWSW	OnCoordSetS[0].s
+#define SYNCSW	OnCoordSetS[1].s
+#define TRACKSW	OnCoordSetS[2].s
+#define POWSW 	(power[0].s==ISS_ON)
+
+#define	SLEWRATE 1			/* slew rate, degrees/s */
+#define	POLLMS	 1000		/* poll period, ms */
+
+#define 	latitude	geo[0].value	/* scope's current rads. */
+#define 	longitude	geo[1].value	/* scope's current rads. */
+#define 	currentUTC	UTC[0].value	/* scope's current rads. */
+#define 	currentLST	STime[0].value	/* scope's current rads. */
+#define 	currentRA	eq[0].value	/* scope's current RA, rads. */
+#define 	currentDec	eq[1].value	/* scope's current Dec, rads. */
+#define 	temmaRA	eqtem[0].value	/* scope's current RA, rads. */
+#define 	temmaDec	eqtem[1].value	/* scope's current Dec, rads. */
+
+
+int openPort(const char *portID);
+int portRead(char *buf, int nbytes, int timeout);
+int portWrite(char * buf);
+int TemmareadOut(int timeout);
+static void mountInit(void);
+void ISGetProperties (const char *dev);
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+double calcLST(char *strlst);
+int TemmaConnect(const char *device) ;
+int TemmaDisconnect(void) ;
+int  set_CometTracking(int RArate, int DECrate);
+int TemmaabortSlew(void) ;
+int do_TemmaGOTO(void) ;
+int extractRA(char *buf);
+int extractDEC(char *buf);
+int get_TemmaCurrentpos(char *buffer);
+int set_TemmaCurrentpos(void) ;
+int do_TemmaSLEW(char mode);
+int get_TemmaVERSION(char *buffer);
+int get_TemmaGOTOstatus(char *buffer);
+int get_TemmaBOTHcorrspeed(char *buffer);
+int get_TemmaDECcorrspeed(char *buffer);
+int set_TemmaDECcorrspeed(char *buffer);
+int get_TemmaRAcorrspeed(char *buffer);
+int set_TemmaRAcorrspeed(char *buffer);
+int get_TemmaLatitude(char *buffer);
+int set_TemmaLatitude(char *buffer);
+int get_TemmaLST(char *buffer);
+int set_TemmaLST(char *buffer);
+int  set_TemmaStandbyState(int on);
+int  get_TemmaStandbyState(unsigned char *buffer);
+int  get_TemmaCometTracking(char *buffer);
+int  set_TemmaCometTracking(char *buffer);
+int  set_TemmaSolarRate(void);
+int  set_TemmaStellarRate(void);
+int  switch_Temmamountside(void);
+
+static void disconnectMount (void);
+static void connectMount (void);
+static void readMountcurrentpos (void *);
+
+/***************************/
+/* RA motor control switch */
+/***************************/
+static ISwitch RAmotor[] = {
+	{"RUN", "On", ISS_OFF, 0, 0}, 
+	{"STOP", "Off", ISS_ON, 0, 0} };
+
+static ISwitchVectorProperty RAmotorSw = { 
+	mydev, "RA motor", "RA motor", MOVE_GROUP, IP_RW, ISR_ATMOST1, 
+	0, IPS_IDLE, RAmotor, NARRAY(RAmotor), "", 0};
+
+/*****************************/
+/* Track mode control switch */
+/*****************************/
+static ISwitch trackmode[] = {
+	{"Sidereal", "Sidereal", ISS_ON, 0, 0}, 
+	{"Lunar", "Lunar", ISS_OFF, 0, 0}, 
+	{"Comet", "Comet", ISS_OFF, 0, 0}, };
+
+static ISwitchVectorProperty trackmodeSw = { 
+	mydev, "Tracking mode", "Tracking mode", MOVE_GROUP, IP_RW, ISR_1OFMANY, 
+	0, IPS_IDLE, trackmode, NARRAY(trackmode), "", 0};
+
+/*****************************/
+/* Power control switch 		 */
+/*****************************/
+static ISwitch power[] = {
+	{"CONNECT", "On", ISS_OFF, 0, 0}, {"DISCONNECT", "Off", ISS_ON, 0, 0}, };
+
+static ISwitchVectorProperty powSw = { 
+	mydev, "CONNECTION", "Connection", MAIN_GROUP, IP_RW, ISR_ATMOST1, 
+	0, IPS_IDLE, power, NARRAY(power), "", 0};
+
+/*******************************/
+/* Temma version text property */
+/*******************************/
+static IText TemmaVersionT[]			= {{"VERSION", "Version", 0, 0, 0, 0}};
+static ITextVectorProperty TemmaVersion		= { 
+	mydev, "VERSION", "Temma version", COMM_GROUP, IP_RO, 0,
+	IPS_OK, TemmaVersionT, NARRAY(TemmaVersionT), "", 0};
+
+
+/*******************************/
+/* Driver notes text property */
+/*******************************/
+static IText TemmaNoteT[]			= {{"Note", "", 0, 0, 0, 0}, {"Feedback", "", 0, 0,0 ,0}};
+static ITextVectorProperty TemmaNoteTP		= { mydev, "Temma Driver", "", MAIN_GROUP, IP_RO, 0, IPS_OK, TemmaNoteT, NARRAY(TemmaNoteT), "", 0};
+		
+/*******************************/
+/* Port names text property */
+/*******************************/
+static IText PortT[]			= {{"PORT", "Port", 0, 0, 0, 0}};
+static ITextVectorProperty Port		= { 
+	mydev, "DEVICE_PORT", "Ports", COMM_GROUP, 
+	IP_RW, 0, IPS_OK, PortT, NARRAY(PortT), "", 0};
+
+/*******************************/
+/* EQUATORIAL_COORD RW property */
+/*******************************/
+static INumber eq[] = {
+	{"RA"		,"RA H:M:S" , "%10.6m", 0, 24, 0, 0, 0, 0, 0},	
+	{"DEC", "Dec D:M:S", "%10.6m", -90, 90, 0, 0, 0, 0, 0}
+};
+static INumberVectorProperty eqNum = { 
+	mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", 
+	MAIN_GROUP , IP_RW, 0, IPS_IDLE, eq, NARRAY(eq), "", 0};
+
+/*******************************/
+/* MOUNT_COORD RO property */
+/*******************************/
+static INumber eqtem[] = {
+  {"RA", "RA H:M:S", "%10.6m", 0, 24, 0, 0, 0, 0, 0},
+  {"DEC", "Dec D:M:S", "%10.6m", -90, 90, 0, 0, 0, 0, 0}
+};
+static INumberVectorProperty eqTemma = { 
+	mydev, "Temma", "Mount coordinates", 
+	MAIN_GROUP , IP_RO, 0, IPS_IDLE, eqtem, NARRAY(eqtem), "", 0};
+
+
+/* Traccking correction parameters (i.e. to track comets) */
+static INumber comet[] = {
+	{"RAcorrspeed","Comet RA motion arcmin/day","%+5d",-21541,21541,0,0,0,0,0},	
+	{"DECcor rspeed", "Comet DEC motion arcmin/day", "%+4d", -600, 600,0, 0., 0, 0, 0}
+};
+
+static INumberVectorProperty cometNum = { 
+	mydev, "COMET_TRACKING", "Comet tracking parameters", 
+	MOVE_GROUP, IP_RW, 0, IPS_IDLE, comet, NARRAY(comet), "", 0};
+
+/* Date & Time */
+static INumber UTC[] = {
+	{"UTC", "UTC", "%10.6m" , 0.,0.,0.,0., 0, 0, 0}};
+INumberVectorProperty Time = { 
+	mydev, "TIME_UTC", "UTC Time", DATETIME_GROUP, 
+	IP_RW, 0, IPS_IDLE, UTC, NARRAY(UTC), "", 0};
+
+static INumber STime[] = {
+	{"LST", "Sidereal time", "%10.6m" , 
+		0.,0.,0.,0., 0, 0, 0}};
+
+INumberVectorProperty SDTime = { 
+	mydev, "TIME_LST", "Sidereal Time", 
+	DATETIME_GROUP, IP_RW, 0, IPS_IDLE, 
+	STime, NARRAY(STime), "", 0};
+
+static ISwitch OnCoordSetS[] = {
+	{"SLEW", "Goto", ISS_OFF, 0, 0 }, 
+	{"SYNC", "Sync", ISS_ON, 0 , 0},
+	{"TRACK", "Track", ISS_OFF, 0, 0 }}; 
+
+static ISwitchVectorProperty OnCoordSetSw = { 
+	mydev, "ON_COORD_SET", "On Set", 
+	MAIN_GROUP, IP_RW, ISR_1OFMANY, 0,
+	IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0};
+
+
+
+static ISwitch abortSlewS[] = {
+	{"ABORT", "Abort", ISS_OFF, 0, 0 }};
+static ISwitchVectorProperty abortSlewSw = { 
+	mydev, "ABORT_MOTION", "******* ABORT GOTO *********",
+	MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, 
+	abortSlewS, NARRAY(abortSlewS), "", 0};
+
+/* geographic location */
+static INumber geo[] = {
+	{"LAT", "Lat. D:M:S +N", "%10.6m", -90., 90., 0., 0., 0, 0, 0},
+	{"LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0., 0, 0, 0} };
+
+static INumberVectorProperty geoNum = {
+	mydev, "GEOGRAPHIC_COORD", "Geographic Location", 
+	DATETIME_GROUP, IP_RW, 0., IPS_IDLE,
+	geo, NARRAY(geo), "", 0};
+
+#endif
Index: /BAORadio/libindi/v1/drivers/video/indi_lpi.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/video/indi_lpi.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/indi_lpi.cpp	(revision 500)
@@ -0,0 +1,155 @@
+/*
+    Meade LPI Experimental driver
+    Copyright (C) 2005 by Jasem Mutlaq
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "v4ldriver.h"
+
+class Meade_LPI : public V4L_Driver
+{
+  public:
+    Meade_LPI();
+   ~Meade_LPI();
+
+  #ifdef HAVE_LINUX_VIDEODEV2_H
+  void connectCamera(void);
+  #endif
+
+};
+
+Meade_LPI::Meade_LPI() : V4L_Driver()
+{
+}
+
+Meade_LPI::~Meade_LPI()
+{
+}
+
+#ifdef HAVE_LINUX_VIDEODEV2_H
+void Meade_LPI::connectCamera()
+{
+  char errmsg[ERRMSGSIZ];
+
+  switch (PowerS[0].s)
+  {
+     case ISS_ON:
+      if (v4l_base->connectCam(PortT[0].text, errmsg, V4L2_PIX_FMT_SBGGR8, 352, 288) < 0)
+      {
+	  PowerSP.s = IPS_IDLE;
+	  PowerS[0].s = ISS_OFF;
+	  PowerS[1].s = ISS_ON;
+	  IDSetSwitch(&PowerSP, "Error: unable to open device");
+	  IDLog("Error: %s\n", errmsg);
+	  return;
+      }
+      
+      /* Sucess! */
+      PowerS[0].s = ISS_ON;
+      PowerS[1].s = ISS_OFF;
+      PowerSP.s = IPS_OK;
+      IDSetSwitch(&PowerSP, "Meade LPI is online. Retrieving basic data.");
+
+      v4l_base->registerCallback(newFrame, this);
+      
+      V4LFrame->compressedFrame = (unsigned char *) malloc (sizeof(unsigned char) * 1);
+      
+      IDLog("Meade LPI is online. Retrieving basic data.\n");
+      getBasicData();
+      
+      break;
+      
+    case ISS_OFF:
+      PowerS[0].s = ISS_OFF;
+      PowerS[1].s = ISS_ON;
+      PowerSP.s = IPS_IDLE;
+      
+      free(V4LFrame->compressedFrame);
+      V4LFrame->compressedFrame = NULL;
+      v4l_base->disconnectCam();
+      
+      IDSetSwitch(&PowerSP, "Meade LPI is offline.");
+      
+      break;
+     }
+
+}
+#endif
+
+Meade_LPI *MainCam = NULL;		/* Main and only camera */
+
+/* send client definitions of all properties */
+void ISInit()
+{
+  if (MainCam == NULL)
+  {
+    MainCam = new Meade_LPI();
+    MainCam->initProperties("Meade LPI");
+    MainCam->initCamBase();
+  }
+}
+    
+void ISGetProperties (const char *dev)
+{ 
+   ISInit();
+  
+  MainCam->ISGetProperties(dev);
+}
+
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	
+  ISInit();
+  
+  MainCam->ISNewSwitch(dev, name, states, names, n);
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+  
+   ISInit();
+   
+   MainCam->ISNewText(dev, name, texts, names, n);
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+      
+  ISInit();
+  
+  MainCam->ISNewNumber(dev, name, values, names, n);
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+
Index: /BAORadio/libindi/v1/drivers/video/indi_philips.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/video/indi_philips.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/indi_philips.cpp	(revision 500)
@@ -0,0 +1,71 @@
+#if 0
+    V4L INDI Driver
+    INDI Interface for V4L devices (Philips)
+    Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include "v4lphilips.h"
+
+V4L_Philips *MainCam = NULL;		/* Main and only camera */
+
+/* send client definitions of all properties */
+void ISInit()
+{
+  if (MainCam == NULL)
+  {
+    MainCam = new V4L_Philips();
+    MainCam->initProperties("Philips Webcam");
+    MainCam->initCamBase();
+  }
+}
+    
+void ISGetProperties (const char *dev)
+{ 
+   ISInit();
+  
+  MainCam->ISGetProperties(dev);
+}
+
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	
+  ISInit();
+  
+  MainCam->ISNewSwitch(dev, name, states, names, n);
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+  
+   ISInit();
+   
+   MainCam->ISNewText(dev, name, texts, names, n);
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+      
+  ISInit();
+  
+  MainCam->ISNewNumber(dev, name, values, names, n);
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
+void ISSnoopDevice (XMLEle *root) {}
Index: /BAORadio/libindi/v1/drivers/video/indi_v4l.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/video/indi_v4l.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/indi_v4l.cpp	(revision 500)
@@ -0,0 +1,71 @@
+#if 0
+    V4L INDI Driver
+    INDI Interface for V4L devices
+    Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include "v4ldriver.h"
+
+V4L_Driver *MainCam = NULL;		/* Main and only camera */
+
+/* send client definitions of all properties */
+void ISInit()
+{
+  if (MainCam == NULL)
+  {
+    MainCam = new V4L_Driver();
+    MainCam->initProperties("Video4Linux Generic Device");
+    MainCam->initCamBase();
+  }
+}
+    
+void ISGetProperties (const char *dev)
+{ 
+   ISInit();
+  
+  MainCam->ISGetProperties(dev);
+}
+
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	
+  ISInit();
+  
+  MainCam->ISNewSwitch(dev, name, states, names, n);
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+  
+   ISInit();
+   
+   MainCam->ISNewText(dev, name, texts, names, n);
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+      
+  ISInit();
+  
+  MainCam->ISNewNumber(dev, name, values, names, n);
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
+void ISSnoopDevice (XMLEle *root) {}
Index: /BAORadio/libindi/v1/drivers/video/stv.c
===================================================================
--- /BAORadio/libindi/v1/drivers/video/stv.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/stv.c	(revision 500)
@@ -0,0 +1,1934 @@
+#if 0
+    STV Driver
+    Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+/* Standard headers */
+
+#include <string.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <zlib.h>
+#include <unistd.h>
+
+#ifndef _WIN32
+#include <termios.h>
+#endif
+
+/* INDI Core headers */
+
+#include "indidevapi.h"
+
+/* INDI Eventloop mechanism */
+
+#include "eventloop.h"
+
+/* INDI Common Routines/RS232 */
+
+#include "indicom.h"
+
+/* Config parameters */
+#include <config.h>
+
+/* Fits */
+
+#include <fitsio.h>
+
+/* STV's definitions */
+
+#include "stvdriver.h"
+
+/* Definitions */
+
+#define mydev	           "STV Guider"     /* Device name */
+#define CONNECTION_GROUP   "Connection"     /* Group name */
+#define SETTINGS_GROUP     "Setings"        /* Group name */
+#define BUTTONS_GROUP      "Buttons and Knobs"        /* Button Pannel */
+#define IMAGE_GROUP        "Download"        /* Button Pannel */
+
+#define currentBuffer             BufferN[0].value
+#define currentX                  WindowingN[0].value
+#define currentY                  WindowingN[1].value
+#define currentLines              WindowingN[2].value
+#define currentLength             WindowingN[3].value
+
+#define currentCompression        CompressionS[0].s
+ 
+static int compression= OFF ;
+static int acquiring=   OFF ;
+static int guiding=     OFF ; 
+static int processing=  OFF ;
+
+/* Fits (fli_ccd project) */
+enum STVFrames { LIGHT_FRAME = 0, BIAS_FRAME, DARK_FRAME, FLAT_FRAME };
+#define TEMPFILE_LEN	16
+
+
+/* Image (fli_ccd project)*/
+
+typedef struct {
+int  width;
+int  height;
+int  frameType;
+int  expose;
+unsigned short  *img;
+} img_t;
+
+static img_t *STVImg;
+
+/* Function adapted from fli_ccd project */
+
+void addFITSKeywords(fitsfile *fptr, IMAGE_INFO *image_info) ;
+int  writeFITS(const char* filename, IMAGE_INFO *image_info, char errmsg[]) ;
+void uploadFile(const char* filename) ;
+
+/* File descriptor and call back id */
+int fd ;
+static int cb= -1 ;
+char tracking_buf[1024] ;
+
+
+/* Function prototypes */
+int ISTerminateTXDisplay(void) ;
+int ISRestoreTXDisplay(void) ;
+int ISMessageImageInfo( int buffer, IMAGE_INFO *image_info) ;
+int ISRequestImageData( int compression, int buffer, int x_offset, int y_offset, int length, int lines) ;
+
+int STV_LRRotaryDecrease(void) ;
+int STV_LRRotaryIncrease(void) ;
+int STV_UDRotaryDecrease(void) ;
+int STV_UDRotaryIncrease(void) ;
+
+int STV_AKey(void) ;
+int STV_BKey(void) ;
+int STV_Setup(void) ;
+int STV_Interrupt(void) ;
+int STV_Focus(void) ;
+int STV_Image(void) ;
+int STV_Monitor(void) ;
+int STV_Calibrate(void) ;
+int STV_Track(void) ;
+int STV_Display(void) ;
+int STV_FileOps(void) ;
+int STV_RequestImageInfo(int imagebuffer, IMAGE_INFO *image_info) ;
+int STV_BufferStatus(int buffer) ;
+int STV_RequestImage( int compression, int buffer, int x_offset, int y_offset, int *length, int *lines, int image[][320], IMAGE_INFO *image_info) ;
+int STV_Download( void) ;
+int STV_TXDisplay(void) ;
+int STV_TerminateTXDisplay(void) ;
+int STV_RequestAck(void) ;
+unsigned int STV_GetBits( unsigned int x, int p, int n) ;
+int STV_PrintBuffer( unsigned char *cmdbuf, int n ); 
+void handleError(ISwitchVectorProperty *svp, int err, const char *msg) ;
+static void ISInit() ;
+void ISCallBack(void) ;
+
+
+int init_serial(char *device_name, int bit_rate, int word_size, int parity, int stop_bits) ;
+int STV_ReceivePacket( unsigned char *buf, int mode) ;
+int STV_Connect( char *device, int baud) ;
+#ifdef HAVE_NOVA_H
+int STV_SetDateTime( char *times) ;
+#endif
+double STV_SetCCDTemperature(double set_value) ;
+
+
+
+
+static IText StatusT[]= {
+  {"STATUS", "This driver", "is experimental, contact markus.wildi@datacomm.ch", 0, 0, 0},
+};
+
+static ITextVectorProperty StatusTP= { 
+  mydev, "STAUS", "Status", CONNECTION_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, StatusT, NARRAY(StatusT), "", 0
+} ;
+
+/* RS 232 Connection */
+
+static ISwitch PowerS[] = {  
+  {"CONNECT", "Connect", ISS_OFF, 0, 0},                         
+  {"DISCONNECT", "Disconnect", ISS_OFF, 0, 0},
+};
+
+static ISwitchVectorProperty PowerSP = { 
+  mydev, "CONNECTION", "Connection", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0
+};	
+
+/* Serial Port */
+
+static IText PortT[]= {
+  {"PORT", "Port", NULL, 0, 0, 0},
+  {"SPEED", "Speed", NULL, 0, 0, 0}
+}; 
+
+static ITextVectorProperty PortTP= { 
+  mydev, "DEVICE_PORT", "Port", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, PortT, NARRAY(PortT), "", 0
+} ;
+
+static ISwitch TXDisplayS[]= {
+
+  {"1", "On",   ISS_ON, 0, 0}, 
+  {"2", "Off",  ISS_OFF, 0, 0}, 
+};
+
+static ISwitchVectorProperty TXDisplaySP= { 
+  mydev, "Update Display",  "Update Display", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TXDisplayS, NARRAY(TXDisplayS), "", 0 
+} ;
+
+static IText DisplayCT[]= {
+
+  {"DISPLAYC1", "Line 1", NULL, 0, 0, 0},
+  {"DISPLAYC2", "Line 2", NULL, 0, 0, 0}
+}; 
+
+static ITextVectorProperty DisplayCTP= { 
+  mydev, "DISPLAYC", "Display", CONNECTION_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayCT, NARRAY(DisplayCT), "", 0
+} ;
+
+static IText DisplayBT[]= {
+
+  {"DISPLAYB1", "Line 1", NULL, 0, 0, 0},
+  {"DISPLAYB2", "Line 2", NULL, 0, 0, 0}
+}; 
+
+static ITextVectorProperty DisplayBTP= { 
+  mydev, "DISPLAYB", "Display", BUTTONS_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayBT, NARRAY(DisplayBT), "", 0
+    } ;
+
+static IText DisplayDT[]= {
+
+  {"DISPLAYD1", "Line 1", NULL, 0, 0, 0},
+  {"DISPLAYD2", "Line 2", NULL, 0, 0, 0}
+}; 
+
+static ITextVectorProperty DisplayDTP= { 
+  mydev, "DISPLAYD", "Display", IMAGE_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayDT, NARRAY(DisplayDT), "", 0
+} ;
+
+
+/* Setings */
+
+static IText UTCT[] = {{"UTC", "UTC", NULL, 0, 0, 0}};
+ITextVectorProperty UTCTP = { mydev, "TIME_UTC", "UTC Time", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, UTCT, NARRAY(UTCT), "", 0};
+
+static INumber SetCCDTemperatureN[]= {
+  { "TEMPERATURE", "Cel. -55.1, +25.2", "%6.1f", -55.8, 25.2, 0.,16., 0, 0, 0},
+
+} ;
+
+static INumberVectorProperty SetCCDTemperatureNP= { 
+  mydev, "CCD_TEMPERATURE", "CCD Temperature",  SETTINGS_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, SetCCDTemperatureN, NARRAY(SetCCDTemperatureN), "", 0
+} ;
+
+
+/* Buttons */
+static ISwitch ControlS[]= {
+
+  {"1", "Parameter", ISS_OFF, 0, 0}, 
+  {"2", "Increase",  ISS_OFF, 0, 0}, 
+  {"3", "Decrease",  ISS_OFF, 0, 0},
+ 
+};
+
+static ISwitchVectorProperty ControlSP= { 
+  mydev, "ParaButtons", "Control", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ControlS, NARRAY(ControlS), "",  0 
+} ;
+
+static ISwitch ValueS[]= {
+
+  {"1", "Value",    ISS_OFF, 0, 0}, 
+  {"2", "Increase", ISS_OFF, 0, 0}, 
+  {"3", "Decrease", ISS_OFF, 0, 0}, 
+};
+
+static ISwitchVectorProperty ValueSP= { 
+  mydev, "ValueButtons", "Control", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ValueS, NARRAY(ValueS), "", 0 
+} ;
+
+static ISwitch AuxiliaryS[]= {
+
+  {"1", "Setup",     ISS_OFF, 0, 0}, 
+  {"2", "Interrupt", ISS_OFF, 0, 0}, 
+
+};
+
+static ISwitchVectorProperty AuxiliarySP= { 
+  mydev, "Auxilliary",  "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AuxiliaryS, NARRAY(AuxiliaryS), "", 0 
+} ;
+
+
+static ISwitch AcquireS[]= {
+
+  {"1", "Focus",   ISS_OFF, 0, 0}, 
+  {"2", "Image",   ISS_OFF, 0, 0}, 
+  {"3", "Monitor", ISS_OFF, 0, 0}, 
+};
+
+static ISwitchVectorProperty AcquireSP= { 
+  mydev, "Acquire",  "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AcquireS, NARRAY(AcquireS), "", 0 
+} ;
+
+static ISwitch GuideS[]= {
+
+  {"1", "Calibrate", ISS_OFF, 0, 0}, 
+  {"2", "Track",     ISS_OFF, 0, 0}, 
+};
+
+static ISwitchVectorProperty GuideSP= { 
+  mydev, "Guide",  "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, GuideS, NARRAY(GuideS), "", 0 
+} ;
+
+static ISwitch ProcessS[]= {
+
+  {"1", "Display/Crosshairs", ISS_OFF, 0, 0}, 
+  {"2", "File Ops",           ISS_OFF, 0, 0}, 
+};
+
+static ISwitchVectorProperty ProcessSP= { 
+  mydev, "Process",  "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ProcessS, NARRAY(ProcessS), "", 0 
+} ;
+
+static ISwitch CompressionS[]= {
+
+  {"1", "On",   ISS_OFF, 0, 0}, 
+  {"2", "Off",  ISS_OFF, 0, 0}, 
+};
+
+static ISwitchVectorProperty CompressionSP= { 
+  mydev, "Compression",  "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, CompressionS, NARRAY(CompressionS), "", 0 
+} ;
+
+static ISwitch BufferStatusS[]= {
+
+  {"1", "Status",   ISS_OFF, 0, 0},  
+};
+
+static ISwitchVectorProperty BufferStatusSP= { 
+  mydev, "Buffers",  "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, BufferStatusS, NARRAY(BufferStatusS), "", 0 
+} ;
+
+static INumber BufferN[]= {
+  { "A0", "Number 1 - 32", "%6.0f", 1., 32., 0.,32., 0, 0, 0}, 
+} ;
+
+static INumberVectorProperty BufferNP= { 
+  mydev, "BUFFER_Number", "Buffer", IMAGE_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, BufferN, NARRAY(BufferN), "", 0
+} ;
+
+static INumber WindowingN[]= {
+
+  { "X", "Offset x", "%6.0f", 0., 199., 0., 0., 0, 0, 0}, 
+  { "Y", "Offset y", "%6.0f", 0., 319., 0., 0., 0, 0, 0}, 
+  { "HEIGHT", "Lines",    "%6.0f", 1., 200., 0., 200., 0, 0, 0},
+  { "WIDTH", "Length",   "%6.0f", 1., 320., 0., 320., 0, 0, 0}, 
+} ;
+
+static INumberVectorProperty WindowingNP= { 
+  mydev, "CCD_FRAME", "Windowing", IMAGE_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, WindowingN, NARRAY(WindowingN), "", 0
+} ;
+
+static ISwitch ImageInfoS[]= {
+
+  {"1", "One Image",  ISS_OFF, 0, 0}, 
+  {"2", "All Images", ISS_OFF, 0, 0}, 
+};
+
+static ISwitchVectorProperty ImageInfoSP= { 
+  mydev, "Information",  "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ImageInfoS, NARRAY(ImageInfoS), "", 0 
+} ;
+
+static ISwitch DownloadS[]= {
+
+  {"1", "One Image",   ISS_OFF, 0, 0}, 
+  {"2", "All Images",  ISS_OFF, 0, 0}, 
+};
+
+static ISwitchVectorProperty DownloadSP= { 
+  mydev, "Download",  "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DownloadS, NARRAY(DownloadS), "", 0 
+} ;
+
+/* BLOB for sending image */
+
+static IBLOB imageB= {"CCD1", "Image", "", 0, 0, 0, 0, 0, 0, 0};
+
+static IBLOBVectorProperty imageBP= {mydev, "Image", "Image", IMAGE_GROUP, IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0};
+
+
+
+/* Initlization routine */
+
+static void ISInit() {
+
+  static int isInit= 0; 
+  
+  if( isInit)  return;
+  
+  IUSaveText( &PortT[0],  "/dev/ttyUSB0"); 
+  IUSaveText( &PortT[1],  "115200"); 
+
+  if((  DisplayCT[0].text= malloc( 1024))== NULL){
+    fprintf(stderr,"3:Memory allocation error");
+    return;
+  }
+  if((DisplayCT[1].text = malloc( 1024))== NULL){
+    fprintf(stderr,"4:Memory allocation error");
+    return;
+  }
+  if(( DisplayBT[0].text= malloc( 1024))== NULL){
+    fprintf(stderr,"5:Memory allocation error");
+    return;
+  }
+  if(( DisplayBT[1].text= malloc( 1024))== NULL){
+    fprintf(stderr,"5:Memory allocation error");
+    return;
+  }
+  if(( DisplayDT[0].text= malloc( 1024))== NULL){
+    fprintf(stderr,"7:Memory allocation error");
+    return;
+  }
+  if(( DisplayDT[1].text= malloc( 1024))== NULL){
+    fprintf(stderr,"8:Memory allocation error");
+    return;
+  }
+
+  if(( STVImg= malloc( sizeof(img_t)))== NULL){
+    fprintf(stderr,"9:Memory allocation error");
+    return;
+  }
+
+  isInit = 1;
+}
+
+void ISResetButtons( char *message) {
+
+  ControlSP.s= IPS_IDLE ;
+  IUResetSwitch(&ControlSP);
+  IDSetSwitch(&ControlSP, NULL);
+  
+  ValueSP.s= IPS_IDLE ;
+  IUResetSwitch(&ValueSP);
+  IDSetSwitch(&ValueSP, NULL);
+
+  AuxiliarySP.s= IPS_IDLE ;
+  IUResetSwitch(&AuxiliarySP);
+  IDSetSwitch(&AuxiliarySP, NULL);
+
+  AcquireSP.s= IPS_IDLE ;
+  IUResetSwitch(&AcquireSP);
+  IDSetSwitch(&AcquireSP, NULL);
+
+  GuideSP.s= IPS_IDLE ;
+  IUResetSwitch(&GuideSP);
+  IDSetSwitch(&GuideSP, NULL);
+
+  ProcessSP.s= IPS_IDLE ;
+  IUResetSwitch(&ProcessSP);
+  IDSetSwitch(&ProcessSP, NULL);
+
+  ImageInfoSP.s= IPS_IDLE ;
+  IUResetSwitch(&ImageInfoSP);
+  IDSetSwitch(&ImageInfoSP, NULL);
+
+  BufferStatusSP.s= IPS_IDLE ;
+  IUResetSwitch(&BufferStatusSP);
+  IDSetSwitch(&BufferStatusSP, NULL);
+
+/*   SP.s= IPS_IDLE ; */
+/*   IUResetSwitch(&SP); */
+/*   IDSetSwitch(&SP, NULL); */
+
+  DownloadSP.s= IPS_IDLE ;
+  IUResetSwitch(&DownloadSP);
+
+  IDSetSwitch(&DownloadSP, "%s", message);
+    
+  return ;
+}
+
+/* This function is called when ever the file handle fd provides data */
+void ISCallBack() {
+
+  int res ;
+  int k,l,m ;
+
+  unsigned char buf[1024] ;
+
+
+  IERmCallback( cb) ;
+  cb = -1 ;
+
+/*   fprintf( stderr, "ISCallBack\n") ; */
+/*   if(( counter++ % 4) ==0){ */
+/*   fprintf( stderr, ".") ; */
+/*   } */
+
+  if( PowerS[0].s == ISS_ON) {
+
+
+    res= STV_ReceivePacket( buf, guiding) ;
+
+ 
+/*     res= STV_PrintBuffer(buf,res) ; */
+
+    DisplayCTP.s= IPS_IDLE ;
+    IDSetText( &DisplayCTP, NULL) ;
+    DisplayBTP.s= IPS_IDLE ;
+    IDSetText( &DisplayBTP, NULL) ;
+    DisplayDTP.s= IPS_IDLE ;
+    IDSetText( &DisplayDTP, NULL) ;
+
+    switch ((int) buf[1]) {       /* STV cmd byte */
+ 
+    case DISPLAY_ECHO:
+
+      if( res < 0 ) { 
+	
+	DisplayCTP.s= IPS_ALERT ;
+	IDSetText( &DisplayCTP, NULL) ;
+	DisplayBTP.s= IPS_ALERT ;
+	IDSetText( &DisplayBTP, NULL) ;
+	DisplayDTP.s= IPS_ALERT ;
+	IDSetText( &DisplayDTP, NULL) ;
+	IDMessage(mydev, "Error while reading, continuing\n");
+	
+      } else {
+
+	l= 0 ;
+	m= 0 ;
+	/* replace unprintable characters and format the string */
+	for( k= 0; k < 24; k++) {
+  
+	  if( buf[k+ 6]== 0x5e) { /* first line */
+	    
+	    DisplayCT[0].text[l-1]= 0x50 ;   /* P */
+	    DisplayCT[0].text[l++]  = 0x6b ; /* k */
+	    
+	  } else if( buf[k+ 6]== 0xd7) {
+	    
+	    DisplayCT[0].text[l++]= 0x28 ; /* "(x,y) " */
+	    DisplayCT[0].text[l++]= 0x78 ;
+	    DisplayCT[0].text[l++]= 0x2c ;
+	    DisplayCT[0].text[l++]= 0x79 ;
+	    DisplayCT[0].text[l++]= 0x29 ;
+	    DisplayCT[0].text[l++]= 0x20 ;
+
+	  } else if( buf[k+ 6] >29 &&  buf[k+ 6] < 127) {
+					    
+	    DisplayCT[0].text[l++]= buf[k+ 6] ;
+
+	  } else {
+	    
+	    /* fprintf(stderr, "LINE 1%2x, %2x, %2x, %c %c %c\n", buf[k+ 5], buf[k+ 6], buf[k+ 7], buf[k+ 5], buf[k+ 6], buf[k+ 7]) ; */
+	    DisplayCT[0].text[l++]= 0x20 ;
+	    
+	  }
+	  if( buf[k+ 30]== 0xb0){ /* second line */
+
+	    DisplayCT[1].text[m++]= 0x43 ; /* Celsius */
+
+	  } else if( buf[k+ 30] >29 &&  buf[k +30] < 127) {
+	    
+	    DisplayCT[1].text[m++]=buf[k + 30] ;
+	  } else {
+	    
+	    /* fprintf(stderr, "LINE 2 %2x, %2x, %2x, %c %c %c\n", buf[k+ 29], buf[k+ 30], buf[k+ 31], buf[k+ 29], buf[k+ 30], buf[k+ 31]) ; */
+	    DisplayCT[1].text[m++]= 0x20 ; 
+	  }
+	}
+	DisplayCT[0].text[l]= 0 ;
+	DisplayCT[1].text[m]= 0 ;
+
+
+	strcpy(DisplayBT[0].text, DisplayCT[0].text) ;
+	strcpy(DisplayBT[1].text, DisplayCT[1].text) ;
+	strcpy(DisplayDT[0].text, DisplayCT[0].text) ;
+	strcpy(DisplayDT[1].text, DisplayCT[1].text) ;
+      
+	DisplayCTP.s= IPS_OK ;
+	IDSetText( &DisplayCTP, NULL) ;
+	DisplayBTP.s= IPS_OK ;
+	IDSetText( &DisplayBTP, NULL) ;
+	DisplayDTP.s= IPS_OK ;
+	IDSetText( &DisplayDTP, NULL) ;
+      }
+      break ;
+    case REQUEST_DOWNLOAD:
+
+      /* fprintf(stderr, "STV says REQUEST_DOWNLOAD\n") ; */
+
+      if(  TXDisplayS[0].s == ISS_ON) {
+
+	res= STV_Download() ;
+
+	imageB.blob = NULL;
+	imageB.bloblen = 0;
+	imageB.size = 0;
+
+      
+	imageBP.s = IPS_ALERT;
+	IDSetBLOB (&imageBP, NULL);
+	
+	IDMessage( mydev, "Switch off display read out manually first (Update Display: Off\n)") ;
+
+      } else {
+
+	tcflush(fd, TCIOFLUSH);
+	usleep( 100000) ;
+     
+	res= ISRequestImageData( 1, 31, 0, 0, 320, 200) ; /* Download the on screen image (buffer 32 -1) */
+      }
+      /*fprintf(stderr, "STV END REQUEST_DOWNLOAD\n") ;  */
+      break ;	
+    case REQUEST_DOWNLOAD_ALL:
+     
+      IDMessage(mydev,  "REQUEST_DOWNLOAD_ALL initiated at the STV not implemented")  ;
+      break ;	
+    case ACK:
+     
+      if( cb == -1)  {
+					  
+	strcpy(DisplayCT[0].text, "Key press acknowledged") ;
+	strcpy(DisplayBT[0].text, DisplayCT[0].text) ;
+	strcpy(DisplayDT[0].text, DisplayCT[0].text) ;
+     
+	DisplayCTP.s= IPS_OK ;
+	IDSetText( &DisplayCTP, NULL) ;
+	DisplayBTP.s= IPS_OK ;
+	IDSetText( &DisplayBTP, NULL) ;
+	DisplayDTP.s= IPS_OK ;
+	IDSetText( &DisplayDTP, NULL) ;
+      }
+      break ;
+    case NACK:
+
+      /*fprintf(stderr, "STV says NACK!!") ;   */
+      IDMessage(mydev, "STV says NACK!") ;
+      break ;
+    case REQUEST_BUFFER_STATUS:
+
+      IDMessage(mydev, "Request Buffer status seen, ignoring\n") ;
+      break ;
+    default:
+
+      if( guiding== ON) {/* While STV is tracking, it send time, brightnes, centroid x,y */
+
+	IDMessage( mydev, "Tracking: %s", tracking_buf) ;
+      } else {
+
+	/*fprintf(stderr, "STV ISCallBack: Unknown response 0x%2x\n",  buf[1]) ;  */
+	IDLog("ISCallBack: Unknown response 0x%2x\n",  buf[1]) ;
+      }
+     break ;
+    }
+  }
+  cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ;
+}
+
+/* Client retrieves properties */
+void ISGetProperties (const char *dev) {
+
+  /* #1 Let's make sure everything has been initialized properly */
+   ISInit();
+  /* #2 Let's make sure that the client is asking for the properties of our device, otherwise ignore */
+  if (dev && strcmp (mydev, dev))
+    return;
+    
+  /* #3 Tell the client to create new properties */
+
+  /* Connection tab */
+
+ 
+  IDDefText(&DisplayCTP, NULL) ;
+  IDDefSwitch(&PowerSP, NULL) ;
+  IDDefText(&PortTP, NULL) ;
+  IDDefSwitch(&TXDisplaySP, NULL) ;
+  IDDefText(&StatusTP, NULL) ;
+
+  /* Settings Tab */
+  IDDefText(&UTCTP, NULL) ;
+  IDDefNumber(&SetCCDTemperatureNP, NULL) ;
+
+  /* Buttons tab */
+  IDDefText(&DisplayBTP, NULL) ;
+  IDDefSwitch(&ControlSP, NULL) ;
+  IDDefSwitch(&ValueSP, NULL) ;
+  IDDefSwitch(&AuxiliarySP, NULL) ;
+  IDDefSwitch(&AcquireSP, NULL) ;
+  IDDefSwitch(&GuideSP, NULL) ;
+  IDDefSwitch(&ProcessSP, NULL) ;
+
+  /* Image tab */
+  IDDefText(&DisplayDTP, NULL) ;
+  /* "direct" read out does not work well IDDefSwitch(&BufferStatusSP, NULL) ; */
+  IDDefSwitch(&BufferStatusSP, NULL) ;
+  IDDefSwitch(&ImageInfoSP, NULL);
+  IDDefNumber(&BufferNP, NULL);
+
+  IDDefSwitch(&DownloadSP, NULL) ;
+  IDDefSwitch(&CompressionSP, NULL) ;
+  IDDefNumber(&WindowingNP, NULL);
+  IDDefBLOB(&imageBP, NULL);
+} 
+
+/* Client sets new switch */
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) {
+
+  int i, j ;
+  int res = 0;
+  int baud ;
+  IMAGE_INFO image_info ;
+  ISwitch *sp ;
+  int lower_buffer = 0;
+  int upper_buffer = 0 ;
+
+  /*fprintf(stderr, "ISNewSwitch\n") ; */
+
+  /* #1 Let's make sure everything has been initialized properly */
+  
+  ISInit();
+	
+  /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */
+  
+  if (dev && strcmp (dev, mydev))
+    return;
+	    
+  /* #3 Now let's check if the property the client wants to change is the PowerSP (name: CONNECTION) property*/
+  
+  if( !strcmp (name, PowerSP.name)) {
+	  
+    /* A. We reset all switches (in this case CONNECT and DISCONNECT) to ISS_OFF */
+    
+    IUResetSwitch(&PowerSP);
+
+    /* B. We update the switches by sending their names and updated states IUUpdateSwitch function */
+    
+    IUUpdateSwitch(&PowerSP, states, names, n);
+	  
+    /* C. We try to establish a connection to our device or terminate it*/
+
+    int res= 0 ;
+    switch (PowerS[0].s) {
+    case ISS_ON:
+	
+      if(( res= strcmp( "9600", PortT[1].text)) ==0) {
+
+	baud= 9600 ;
+      } else if(( res= strcmp( "19200", PortT[1].text)) ==0) {
+	baud= 19200 ;
+      } else if( (res= strcmp( "38400", PortT[1].text)) ==0) {
+	baud= 38400 ;
+      } else if(( res= strcmp( "57600", PortT[1].text)) ==0) {
+	baud= 57600 ;
+      } else if(( res= strcmp( "115200", PortT[1].text)) ==0) {
+	baud= 115200 ;
+      } else {
+
+	IUSaveText(&PortT[1], "9600");
+	IDSetText(&PortTP, "Wrong RS 232 value: %s, defaulting to 9600 baud",  PortT[1].text);
+	return ;
+      }
+		    
+      if(( fd= STV_Connect( PortT[0].text, baud))== -1) {
+
+	PowerSP.s = IPS_ALERT;
+	IUResetSwitch( &PowerSP);
+	IDSetSwitch( &PowerSP, "Error connecting to port %s", PortT[0].text);
+
+	return;
+      } else {
+
+	cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ;
+	
+	/* The SBIG manual says one can request an ACK, never saw it, even not on a RS 232 tester */
+	if(( res= STV_RequestAck()) != 0) {
+	  fprintf( stderr, "COULD not write an ACK\n") ;
+	} 
+	/* Second trial: start reading out the display  */
+	if((res= STV_TXDisplay()) != 0) {
+	  
+	  fprintf(stderr, "STV: Could not write  %d\n", res) ;
+	  return ;
+	}
+      }
+
+      PowerSP.s = IPS_OK ;
+      IDSetSwitch(&PowerSP, "STV is online, port: %s, baud rate: %s", PortT[0].text, PortT[1].text) ;
+      
+      PortTP.s = IPS_OK ;
+      IDSetText(&PortTP, NULL);
+
+      break;    
+
+    case ISS_OFF:
+
+      IERmCallback( cb) ;
+      cb = -1 ;
+
+      /* Close the serial port */
+		
+      tty_disconnect(fd);
+
+      ISResetButtons(NULL) ;
+	
+      GuideSP.s= IPS_IDLE ;
+      IUResetSwitch(&GuideSP);
+      IDSetSwitch(&GuideSP, NULL);
+
+      TXDisplaySP.s= IPS_IDLE ;
+      IUResetSwitch(&TXDisplaySP);
+      IDSetSwitch(&TXDisplaySP, NULL);
+      
+      DisplayCTP.s = IPS_IDLE;
+      IDSetText (&DisplayCTP, NULL);
+
+      DisplayBTP.s = IPS_IDLE;
+      IDSetText (&DisplayBTP, NULL);
+
+      DisplayDTP.s = IPS_IDLE;
+      IDSetText (&DisplayDTP, NULL);
+      
+      PortTP.s = IPS_IDLE ;
+      IDSetText(&PortTP, NULL) ;
+      
+      imageB.blob = NULL;
+      imageB.bloblen = 0;
+      imageB.size = 0;
+
+      
+      imageBP.s = IPS_IDLE;
+      IDSetBLOB (&imageBP, NULL);
+
+      PowerSP.s = IPS_IDLE;
+      IUResetSwitch(&PowerSP);
+      IDSetSwitch(&PowerSP, "STV is offline");
+
+      break;
+    }
+    return ;
+
+  } else if( !strcmp (name, AuxiliarySP.name)) {
+
+    /* Setup und interrupt buttons */
+
+    ISResetButtons(NULL) ;
+    IUResetSwitch(&AuxiliarySP);
+    IUUpdateSwitch(&AuxiliarySP, states, names, n);
+
+    for( i = 0; i < n; i++) {
+      
+      sp = IUFindSwitch (&AuxiliarySP, names[i]) ;
+
+      if( sp == &AuxiliaryS[0]){
+	
+	res= STV_Setup() ;
+	
+      } else if( sp == &AuxiliaryS[1]){
+
+	res= STV_Interrupt() ;
+      }
+    }
+    if( res== 0) {
+
+      AuxiliarySP.s= IPS_OK ;
+      IUResetSwitch(&AuxiliarySP) ;
+      IDSetSwitch(&AuxiliarySP, NULL) ;
+
+    } else {
+
+      AuxiliarySP.s= IPS_ALERT ;
+      IUResetSwitch(&AuxiliarySP) ;
+      IDSetSwitch(&AuxiliarySP, "Check connection") ;
+    }
+
+  } else if( !strcmp (name, ControlSP.name)) {
+
+    /* Parameter, value and the rotary knobs */
+    ISResetButtons(NULL) ;
+    IUResetSwitch(&ControlSP);
+    IUUpdateSwitch(&ControlSP, states, names, n);
+
+    acquiring=   OFF ;
+    guiding=     OFF ; 
+    processing=  OFF ;
+
+    for( i = 0; i < n; i++) {
+      
+      sp = IUFindSwitch (&ControlSP, names[i]) ;
+      
+      /* If the state found is ControlS[0] then process it */
+      
+      if( sp == &ControlS[0]){
+
+	res= STV_AKey() ;
+
+      } else if( sp == &ControlS[1]){
+
+	res= STV_UDRotaryIncrease() ;
+
+      } else if( sp == &ControlS[2]){
+
+	res= STV_UDRotaryDecrease() ;
+      }
+    }
+    if( res== 0) {
+
+      ControlSP.s= IPS_OK ;
+      IUResetSwitch(&ControlSP) ;
+      IDSetSwitch(&ControlSP, NULL) ;
+
+    } else {
+
+      ControlSP.s= IPS_ALERT ;
+      IUResetSwitch(&ControlSP) ;
+      IDSetSwitch(&ControlSP, "Check connection") ;
+    }
+  } else if( !strcmp (name, ValueSP.name)) {
+
+    /* Button Value, left/right knob */
+    ISResetButtons(NULL) ;
+    IUResetSwitch(&ValueSP);
+    IUUpdateSwitch(&ValueSP, states, names, n);
+
+    acquiring=   OFF ;
+    guiding=     OFF ; 
+    processing=  OFF ;
+
+    for( i = 0; i < n; i++) {
+      
+      sp = IUFindSwitch (&ValueSP, names[i]) ;
+  
+      if( sp == &ValueS[0]){
+
+	res= STV_BKey() ;
+
+      } else if( sp == &ValueS[1]){
+
+	res= STV_LRRotaryIncrease() ;
+
+      } else if( sp == &ValueS[2]){
+
+	res= STV_LRRotaryDecrease() ;
+      }
+    }
+
+    if( res== 0) {
+
+      ValueSP.s= IPS_OK ;
+      IUResetSwitch(&ValueSP) ;
+      IDSetSwitch(&ValueSP, NULL) ;
+
+    } else {
+
+      ValueSP.s= IPS_ALERT ;
+      IUResetSwitch(&ValueSP) ;
+      IDSetSwitch(&ValueSP, "Check connection") ;
+    }
+  } else if( !strcmp (name, AcquireSP.name)) {
+
+    /* Focus, Image Monitor buttons */
+    ISResetButtons(NULL) ;
+    IUResetSwitch(&AcquireSP);
+    IUUpdateSwitch(&AcquireSP, states, names, n);
+
+    acquiring=  ON  ;
+    guiding=    OFF ;
+    processing= OFF ;
+
+    for( i = 0; i < n; i++) {
+      
+      sp = IUFindSwitch (&AcquireSP, names[i]) ;
+  
+      if( sp == &AcquireS[0]){
+
+	res= STV_Focus() ;
+
+      } else if( sp == &AcquireS[1]){
+
+	res= STV_Image() ;
+
+      } else if( sp == &AcquireS[2]){
+
+	res= STV_Monitor() ;
+      }
+    }
+    if( res== 0) {
+
+      AcquireSP.s= IPS_OK ;
+      IUResetSwitch(&AcquireSP) ;
+      IDSetSwitch(&AcquireSP, NULL) ;
+
+    } else {
+
+      AcquireSP.s= IPS_ALERT ;
+      IUResetSwitch(&AcquireSP) ;
+      IDSetSwitch(&AcquireSP, "Check connection") ;
+    }
+
+  } else if( !strcmp (name, GuideSP.name)) {
+
+    /* Calibrate, Track buttons */
+    ISResetButtons(NULL) ;
+    IUResetSwitch(&GuideSP);
+    IUUpdateSwitch(&GuideSP, states, names, n);
+
+    acquiring=  OFF  ;
+    guiding=    ON ;
+    processing= OFF ;
+
+    for( i = 0; i < n; i++) {
+      
+      sp = IUFindSwitch (& GuideSP, names[i]) ;
+  
+      if( sp == & GuideS[0]){
+
+	res= STV_Calibrate() ;
+
+      } else if( sp == &GuideS[1]){
+
+	res= STV_Track() ;
+      } 
+    }
+    if( res== 0) {
+
+      GuideSP.s= IPS_OK ;
+      IUResetSwitch(&GuideSP) ;
+      IDSetSwitch(&GuideSP, NULL) ;
+
+    } else {
+
+      GuideSP.s= IPS_ALERT ;
+      IUResetSwitch(&GuideSP) ;
+      IDSetSwitch(&GuideSP, "Check connection") ;
+    }
+  } else if( !strcmp (name, ProcessSP.name)) {
+
+    ISResetButtons(NULL) ;
+    IUResetSwitch(&ProcessSP);
+    IUUpdateSwitch(&ProcessSP, states, names, n);
+
+    acquiring=  OFF ;
+    guiding=    OFF ;
+    processing= ON  ;
+
+    for( i = 0; i < n; i++) {
+      
+      sp = IUFindSwitch (&ProcessSP, names[i]) ;
+  
+      if( sp == &ProcessS[0]){
+
+	res= STV_Display() ;
+
+      } else if( sp == &ProcessS[1]){
+
+	res= STV_FileOps() ;
+      }
+    }
+    if( res== 0) {
+
+      ProcessSP.s= IPS_OK ;
+      IUResetSwitch(&ProcessSP) ;
+      IDSetSwitch(&ProcessSP, NULL) ;
+
+    } else {
+
+      ProcessSP.s= IPS_ALERT ;
+      IUResetSwitch(&ProcessSP) ;
+      IDSetSwitch(&ProcessSP, "Check connection") ;
+    }
+  } else if( !strcmp (name, ImageInfoSP.name)) {
+
+    acquiring=   OFF ;
+    guiding=     OFF ; 
+    processing=  OFF ;
+
+    /* Read out the image buffer and display a short message if it is empty or not */
+    res= ISTerminateTXDisplay() ;
+
+    for( i = 0; i < n; i++) {
+       
+      sp = IUFindSwitch( &ImageInfoSP, names[i]) ;
+  
+      if( sp == &ImageInfoS[0]){
+
+ 	if(( res= STV_RequestImageInfo( currentBuffer- 1, &image_info))== 0 ) {
+	  
+	  ISMessageImageInfo( (int)currentBuffer- 1, &image_info) ;
+	} else {
+	  IDMessage( mydev, "Buffer %2d is empty", (int)currentBuffer) ;
+
+	}
+	break ;
+      } else if( sp == &ImageInfoS[1]){
+
+	for( i= 0; i < 32 ; i++) {
+
+	  if(( res= STV_RequestImageInfo( i, &image_info))== 0 ) {
+	    ISMessageImageInfo( i, &image_info) ;
+	  } else {
+	    IDMessage( mydev, "Buffer %2d is empty", i+ 1) ;
+	  }
+	}
+	break ;
+      } 
+    }
+    if( res== 0) {
+
+      ImageInfoSP.s= IPS_OK ;
+      IUResetSwitch( &ImageInfoSP) ;
+      IDSetSwitch( &ImageInfoSP, NULL) ;
+
+    } else {
+
+      ImageInfoSP.s= IPS_ALERT ;
+      IUResetSwitch( &ImageInfoSP) ;
+      /*IDSetSwitch( &ImageInfoSP, "Check connection") ; */
+      IDSetSwitch( &ImageInfoSP, NULL) ;
+    }
+    res= STV_Interrupt() ; /* STV initiates a download that we do not want */
+    res= ISRestoreTXDisplay() ;
+
+  } else if( !strcmp (name, CompressionSP.name)) {
+
+
+    acquiring=   OFF ;
+    guiding=     OFF ; 
+    processing=  OFF ;
+
+    /* Enable or disable compression for image download */
+    ISResetButtons(NULL) ;
+    IUResetSwitch(&CompressionSP);
+    IUUpdateSwitch(&CompressionSP, states, names, n);
+
+    for( i = 0; i < n; i++) {
+      
+      sp = IUFindSwitch (&CompressionSP, names[i]) ;
+  
+      if( sp == &CompressionS[0]){
+
+        CompressionS[0].s= ISS_ON ;
+      } else if( sp == &CompressionS[1]){
+
+        CompressionS[1].s= ISS_ON ;
+      }
+    }
+
+    CompressionSP.s= IPS_OK ;
+    IDSetSwitch(&CompressionSP, NULL) ;
+
+  } else if( !strcmp (name, BufferStatusSP.name)) {
+
+
+    ISResetButtons(NULL) ;
+
+    BufferStatusSP.s= IPS_ALERT ;
+    IUResetSwitch(&BufferStatusSP) ;
+    IDSetSwitch(&BufferStatusSP, "Wait...") ;
+     
+    if( ( AcquireSP.s != OFF) || ( GuideSP.s != OFF) || ( ProcessSP.s != OFF)) {
+   
+      acquiring=  OFF ;
+      guiding=    OFF ;
+      processing= OFF ;
+
+      ISResetButtons( "Interrupting ongoing image acquisition, calibration or tracking\n") ;
+
+      AcquireSP.s= IPS_IDLE ;
+      IUResetSwitch(&AcquireSP);
+      IDSetSwitch(&AcquireSP, NULL);
+
+      GuideSP.s= IPS_IDLE ;
+      IUResetSwitch(&GuideSP);
+      IDSetSwitch(&GuideSP, NULL);
+
+      ProcessSP.s= IPS_IDLE ;
+      IUResetSwitch(&ProcessSP);
+      IDSetSwitch(&ProcessSP, NULL);
+
+      ImageInfoSP.s= IPS_IDLE ;
+      IUResetSwitch(&ImageInfoSP);
+      IDSetSwitch(&ImageInfoSP, NULL);
+
+      res= STV_Interrupt() ;
+      usleep(100000) ;
+      res= STV_Interrupt() ;
+    }
+    acquiring=  OFF ;
+    guiding=    OFF ;
+    processing= OFF ;
+
+    sp = IUFindSwitch (&BufferStatusSP, names[0]) ;
+ 
+    if((res= ISTerminateTXDisplay()) != 0) {
+
+      fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ;
+    }
+
+    if( sp == &BufferStatusS[0]) {
+
+      for( i= 31; i > -1; i--) {
+    
+	usleep( 50000) ;
+	if(( res= STV_BufferStatus( i))== 0) {
+	  IDMessage( mydev, "Buffer %2d: image present", i+ 1) ;
+	} else {
+	  IDMessage( mydev, "Buffer %2d: empty", i+ 1) ;
+	}
+      }
+    }
+
+    BufferStatusS[0].s= ISS_OFF ;
+
+    if( 0 <= res) { 
+
+      BufferStatusSP.s= IPS_OK ;
+      IUResetSwitch(&BufferStatusSP) ;
+      IDSetSwitch(&BufferStatusSP, NULL) ;
+    } else {
+
+      BufferStatusSP.s= IPS_ALERT ;
+      IUResetSwitch(&BufferStatusSP) ;
+      IDSetSwitch(&BufferStatusSP, "Check connection") ;
+    }
+ 
+    res= ISRestoreTXDisplay() ;
+    res= STV_Interrupt() ;
+
+  } else if( !strcmp (name, DownloadSP.name)) {
+
+    /* Download images */
+    /* Downloading while the STV is occupied is not working */
+    if( ( AcquireSP.s != OFF) || ( GuideSP.s != OFF) || ( ProcessSP.s != OFF)) {
+   
+
+      ISResetButtons( "Interrupting ongoing image acquisition, calibration or tracking\n") ;
+
+      AcquireSP.s= IPS_IDLE ;
+      IUResetSwitch(&AcquireSP);
+      IDSetSwitch(&AcquireSP, NULL);
+
+      GuideSP.s= IPS_IDLE ;
+      IUResetSwitch(&GuideSP);
+      IDSetSwitch(&GuideSP, NULL);
+
+      ProcessSP.s= IPS_IDLE ;
+      IUResetSwitch(&ProcessSP);
+      IDSetSwitch(&ProcessSP, NULL);
+
+      ImageInfoSP.s= IPS_IDLE ;
+      IUResetSwitch(&ImageInfoSP);
+      IDSetSwitch(&ImageInfoSP, NULL);
+
+      res= STV_Interrupt() ;
+      usleep(100000) ;
+      res= STV_Interrupt() ;
+    }
+    acquiring=  OFF ;
+    guiding=    OFF ;
+    processing= OFF  ;
+   
+    if((res= ISTerminateTXDisplay()) != 0) {
+
+      fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ;
+    }
+
+    DownloadSP.s= IPS_ALERT ;
+    IUResetSwitch(&DownloadSP) ;
+    IDSetSwitch(&DownloadSP, NULL) ;
+
+    compression= OFF ;
+    if( CompressionS[0].s ==  ISS_ON) {
+
+      compression= ON ;
+    } 
+    for( i = 0; i < n; i++) {
+      
+      sp = IUFindSwitch (&DownloadSP, names[i]) ;
+  
+      if( sp == &DownloadS[0]){
+
+	lower_buffer=  currentBuffer- 2 ;
+	upper_buffer=  currentBuffer- 1 ;
+
+      } else if( sp == &DownloadS[1]){
+
+	lower_buffer=  -1 ;
+	upper_buffer=  31 ;
+      }
+    }
+    for( j= upper_buffer ; j> lower_buffer ; j--) {
+	 
+      if((res= ISRequestImageData( compression, j, currentX, currentY, currentLength, currentLines)) != 0) {
+	if( res== 1) {
+
+	  IDMessage( mydev, "Buffer %2.0f: empty", (double)(j+ 1)) ;
+	} else {
+	  break ;
+	}
+      }
+    }
+    if( res== 0) {
+ 
+      IDMessage( mydev, "STV waits for SYNC TIME Do it! Setting time, PLEASE WAIT!") ;
+
+      #ifdef HAVE_NOVA_H
+      if((res= STV_SetDateTime(NULL)) == 0) {
+      
+	UTCTP.s= IPS_OK ;
+	IDSetText( &UTCTP, "Time set to UTC now") ;
+      } else {
+ 
+	UTCTP.s= IPS_ALERT ;
+	IDSetText( &UTCTP, "Error setting time, check connection") ;
+      }
+      #endif
+
+      DownloadSP.s= IPS_OK ;
+      IUResetSwitch(&DownloadSP) ;
+      IDSetSwitch(&DownloadSP, NULL) ;
+
+    } else { /* res could be -1 (STV_RequestImageData) */
+
+      DownloadSP.s= IPS_ALERT ;
+      IUResetSwitch(&DownloadSP) ;
+      IDSetSwitch(&DownloadSP, "Check connection") ;
+      IDSetSwitch(&DownloadSP, NULL) ;
+    }
+
+    res= ISRestoreTXDisplay() ;
+    res= STV_Interrupt() ;
+    IDMessage( mydev, "You may continue NOW") ;
+
+  } else if( !strcmp (name, TXDisplaySP.name)) {
+
+    acquiring=  OFF ;
+    guiding=    OFF ;
+    processing= OFF  ;
+
+    ISResetButtons(NULL) ;
+    IUResetSwitch(&TXDisplaySP);
+    IUUpdateSwitch(&TXDisplaySP, states, names, n);
+
+    for( i = 0; i < n; i++) {
+      
+      sp= IUFindSwitch (&TXDisplaySP, names[i]) ;
+      
+      if( sp == &TXDisplayS[0]){
+
+	if((res= STV_TXDisplay()) == 0) {
+	  
+	  TXDisplaySP.s= IPS_OK ;
+	  IDSetSwitch( &TXDisplaySP, "Reading out display") ;
+
+	  DisplayCTP.s = IPS_OK ;
+	  IDSetText( &DisplayCTP, NULL);
+
+	  DisplayBTP.s = IPS_OK ;
+	  IDSetText( &DisplayBTP, NULL);
+
+	  DisplayDTP.s = IPS_OK ;
+	  IDSetText( &DisplayDTP, NULL);
+	}
+	
+      } else if( sp== &TXDisplayS[1]){
+
+	DisplayCTP.s = IPS_IDLE ;
+	DisplayBTP.s = IPS_IDLE ;
+	DisplayDTP.s = IPS_IDLE ;
+	
+	if((res= STV_TerminateTXDisplay()) == 0) {
+	  TXDisplaySP.s = IPS_OK ;
+	  IDSetSwitch( &TXDisplaySP, "Stopping display read out") ;
+
+	  DisplayCTP.s = IPS_IDLE ;
+	  IUSaveText(&DisplayCT[0], "                        "); /* reset client's display */
+	  IUSaveText(&DisplayCT[1], "                        ");
+	  IDSetText( &DisplayCTP, NULL);
+	  
+	  DisplayBTP.s = IPS_IDLE ;
+	  IUSaveText(&DisplayBT[0], "                        "); /* reset client's display */
+	  IUSaveText(&DisplayBT[1], "                        ");
+	  IDSetText( &DisplayBTP, NULL); 
+
+	  DisplayDTP.s = IPS_IDLE ;
+	  IUSaveText(&DisplayDT[0], "                        "); /* reset client's display */
+	  IUSaveText(&DisplayDT[1], "                        ");
+	  IDSetText( &DisplayDTP, NULL); 
+	}
+      }
+    }
+    if( res != 0) {
+
+      TXDisplaySP.s= IPS_ALERT ;
+      IUResetSwitch(&TXDisplaySP) ;
+      IDSetSwitch(&TXDisplaySP, "Check connection") ;
+    }
+
+  }
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) {
+
+  int res ;
+  IText *tp ;
+
+  /*fprintf(stderr, "ISNewText\n") ; */
+
+  /* #1 Let's make sure everything has been initialized properly */
+  ISInit();
+	
+  /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */
+  if ( dev && strcmp( dev, mydev))
+    return;
+
+  if( !strcmp (name, PortTP.name)) {
+
+    if (IUUpdateText(&PortTP, texts, names, n) < 0)
+	return;
+
+    PortTP.s = IPS_OK;
+
+    if (PowerS[0].s == ISS_ON){
+      
+      PortTP.s = IPS_ALERT;
+      IDSetText(&PortTP, "STV is already online");
+    }
+
+    /* JM: Don't forget to send acknowledgment */
+    IDSetText(&PortTP, NULL);
+
+  } else if( !strcmp (name, UTCTP.name)) {
+
+    ISResetButtons(NULL) ;
+   
+    tp= IUFindText (&UTCTP, names[0]) ;
+ 
+    if((res= ISTerminateTXDisplay()) != 0) {
+
+      fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ;
+    }
+     
+    if( tp == &UTCT[0]) {    
+
+      #ifdef HAVE_NOVA_H
+      if((res= STV_SetDateTime(NULL)) == 0) {
+	  
+	UTCTP.s= IPS_OK ;
+	IDSetText( &UTCTP, "Time set to UTC") ;
+      } else {
+
+	UTCTP.s= IPS_ALERT ;
+	IDSetText( &UTCTP, "Error setting time, check connection") ;
+      }
+      #endif 
+    }
+    res= ISRestoreTXDisplay() ;
+  }  
+}
+/* Client sets new number */
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) {
+
+  int res ; 
+  double ccd_temperature ;
+  /*fprintf(stderr, "ISNewNumber\n") ; */
+
+  /* #1 Let's make sure everything has been initialized properly */
+  ISInit();
+	
+  /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */
+  if ( dev && strcmp( dev, mydev))
+    return;
+
+  if (PowerS[0].s != ISS_ON){
+      
+    PowerSP.s = IPS_ALERT;
+    IDSetSwitch( &PowerSP, NULL) ;
+    IDMessage("STV is offline", NULL);
+    return ;
+  }
+
+  if( !strcmp (name, BufferNP.name)) {
+
+    INumber *buffer = IUFindNumber( &BufferNP, names[0]) ;
+
+    if( buffer == &BufferN[0]) {
+      
+      currentBuffer=  values[0] ;
+    
+      /* Check the boundaries, this is incomplete at the moment */
+      BufferNP.s = IPS_OK ;
+      IDSetNumber(&BufferNP, NULL) ; 
+    }  
+  } else  if( !strcmp (name, WindowingNP.name)) {
+
+    INumber *buffer = IUFindNumber( &WindowingNP, names[0]) ;
+
+    if( buffer == &WindowingN[0]) {
+      
+      currentX     =  values[0] ;
+      currentY     =  values[1] ;
+      currentLines =  values[2] ;
+      currentLength=  values[3] ;
+
+      WindowingNP.s = IPS_OK ;
+      IDSetNumber(&WindowingNP, NULL) ; 
+    }
+  } else if( !strcmp (name, SetCCDTemperatureNP.name)) {
+
+    if((res= ISTerminateTXDisplay()) != 0) {
+
+      fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ;
+    }
+
+    INumber *np= IUFindNumber (&SetCCDTemperatureNP, names[0]) ;
+      
+    if( np == &SetCCDTemperatureN[0]) {
+
+      if((ccd_temperature= STV_SetCCDTemperature(values[0])) != 0) { /* STV has no 0 C setting */
+	
+	SetCCDTemperatureNP.s= IPS_OK ;
+        SetCCDTemperatureN[0].value=  ccd_temperature;
+	IDSetNumber( &SetCCDTemperatureNP, "CCD Temperature set to %g", SetCCDTemperatureN[0].value) ;
+
+      } else {
+	SetCCDTemperatureNP.s= IPS_ALERT ;
+	IDSetNumber( &SetCCDTemperatureNP, "Error setting CCD temperature, check connection") ;
+      } 
+    } 
+    res= ISRestoreTXDisplay() ;
+  }
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
+{
+  INDI_UNUSED(dev);
+  INDI_UNUSED(name);
+  INDI_UNUSED(sizes);
+  INDI_UNUSED(blobsizes);
+  INDI_UNUSED(blobs);
+  INDI_UNUSED(formats);
+  INDI_UNUSED(names);
+  INDI_UNUSED(n);
+}
+void ISSnoopDevice (XMLEle *root) 
+{
+  INDI_UNUSED(root);
+}
+
+int writeFITS(const char* filename, IMAGE_INFO *image_info, char errmsg[])
+{
+
+  fitsfile *fptr;       /* pointer to the FITS file; defined in fitsio.h */
+  int status;
+  long  fpixel = 1, naxis = 2, nelements;
+  long  naxes[2];
+  char filename_rw[TEMPFILE_LEN+1];
+
+  naxes[0] = STVImg->width;
+  naxes[1] = STVImg->height;
+
+  /* Append ! to file name to over write it.*/
+  snprintf(filename_rw, TEMPFILE_LEN+1, "!%s", filename);
+
+  status = 0;         /* initialize status before calling fitsio routines */
+  fits_create_file(&fptr, filename_rw, &status);   /* create new file */
+
+  /* Create the primary array image (16-bit short integer pixels */
+  fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status);
+
+  addFITSKeywords(fptr, image_info);
+
+  nelements = naxes[0] * naxes[1];          /* number of pixels to write */
+
+  /* Write the array of integers to the image */
+  fits_write_img(fptr, TUSHORT, fpixel, nelements, STVImg->img, &status);
+
+  fits_close_file(fptr, &status);            /* close the file */
+
+  fits_report_error(stderr, status);  /* print out any error messages */
+
+  /* Success */
+  /*ExposeTimeNP.s = IPS_OK; */
+  /*IDSetNumber(&ExposeTimeNP, NULL); */
+  uploadFile(filename);
+ 
+  return status;
+}
+
+void addFITSKeywords(fitsfile *fptr, IMAGE_INFO *image_info)
+{
+  int status=0; 
+  char binning_s[32];
+  char frame_s[32];
+  char date_obs_s[64] ;
+  char tmp[32] ;
+ 
+
+  image_info->pixelSize= 7.4 ; /* microns */
+
+  if( image_info->binning== 1) {
+    snprintf(binning_s, 32, "(%1.0f x %1.0f)", 1., 1.);
+  } else if( image_info->binning== 2) {
+    snprintf(binning_s, 32, "(%1.0f x %1.0f)", 2., 2.);
+  } else if( image_info->binning== 3) {
+    snprintf(binning_s, 32, "(%1.0f x %1.0f)", 3., 3.);
+  } else {
+    fprintf( stderr, "Error in binning information: %d\n", image_info->binning) ; 
+  }
+  
+
+  strcpy(frame_s, "Light");
+
+  /* ToDo: assign the frame type */
+/*   switch (STVImg->frameType) */
+/*   { */
+/*     case LIGHT_FRAME: */
+/*       	strcpy(frame_s, "Light"); */
+/* 	break; */
+/*     case BIAS_FRAME: */
+/*         strcpy(frame_s, "Bias"); */
+/* 	break; */
+/*     case FLAT_FRAME: */
+/*         strcpy(frame_s, "Flat Field"); */
+/* 	break; */
+/*     case DARK_FRAME: */
+/*         strcpy(frame_s, "Dark"); */
+/* 	break; */
+/*   } */
+
+  
+  fits_update_key(fptr, TDOUBLE, "CCD-TEMP", &(image_info->ccdTemp), "CCD Temperature (Celcius)", &status);
+  fits_update_key(fptr, TDOUBLE, "EXPOSURE", &(image_info->exposure ), "Total Exposure Time (ms)", &status); 
+  fits_update_key(fptr, TDOUBLE, "PIX-SIZ",  &(image_info->pixelSize), "Pixel Size (microns)", &status);
+  fits_update_key(fptr, TSTRING, "BINNING",  binning_s, "Binning HOR x VER", &status);
+  fits_update_key(fptr, TSTRING, "FRAME",    frame_s, "Frame Type", &status);
+  fits_update_key(fptr, TDOUBLE, "DATAMIN",  &(image_info->minValue), "Minimum value", &status);
+  fits_update_key(fptr, TDOUBLE, "DATAMAX",  &(image_info->maxValue), "Maximum value", &status);
+  fits_update_key(fptr, TSTRING, "INSTRUME", "SBIG STV", "CCD Name", &status);
+
+  sprintf( tmp, "%4d-",image_info->year) ; 
+  strcpy( date_obs_s,tmp ) ;
+
+  if( image_info->month< 10) {
+    sprintf( tmp, "0%1d-", image_info->month) ; 
+  } else {
+    sprintf( tmp, "%2d-",  image_info->month) ; 
+  }
+  strcat( date_obs_s, tmp) ;
+
+  if( image_info->day< 10) {
+    sprintf( tmp, "0%1dT", image_info->day) ; 
+  } else {
+    sprintf( tmp, "%2dT",  image_info->day) ; 
+  } 
+  strcat( date_obs_s, tmp) ;
+
+  if( image_info->hours< 10) {
+    sprintf( tmp, "0%1d:", image_info->hours) ; 
+  } else {
+    sprintf( tmp, "%2d:",  image_info->hours) ; 
+  }  
+  strcat( date_obs_s, tmp) ;
+
+  if( image_info->minutes< 10) {
+    sprintf( tmp, "0%1d:",image_info->minutes) ; 
+  } else {
+    sprintf( tmp, "%2d:", image_info->minutes) ; 
+  }  
+  strcat( date_obs_s, tmp) ;
+
+  if( image_info->seconds< 10) {
+    sprintf( tmp, "0%1d:", image_info->seconds) ; 
+  } else {
+    sprintf( tmp, "%2d:",  image_info->seconds) ; 
+  }  
+  strcat( date_obs_s, tmp) ;
+
+  fits_update_key(fptr, TSTRING, "DATE-OBS", date_obs_s, "Observing date (YYYY-MM-DDThh:mm:ss UT", &status);
+  
+  fits_write_date(fptr, &status);
+
+}
+
+void uploadFile(const char* filename)
+{
+   FILE * fitsFile;
+   unsigned char *fitsData, *compressedData;
+   int r=0;
+   unsigned int i =0, nr = 0;
+   uLongf compressedBytes=0;
+   uLong  totalBytes;
+   struct stat stat_p; 
+ 
+   if ( -1 ==  stat (filename, &stat_p))
+   { 
+     IDLog("Error occurred attempting to stat file.\n"); 
+     return; 
+   }
+   
+   totalBytes     = stat_p.st_size;
+
+
+   fitsData       = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes);
+   compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
+
+
+   
+   if (fitsData == NULL || compressedData == NULL) {
+     if (fitsData) free(fitsData);
+     if (compressedData) free(compressedData);
+     IDLog("Error! low memory. Unable to initialize fits buffers.\n");
+     return;
+   }
+   
+   fitsFile = fopen(filename, "r");
+   
+   if (fitsFile == NULL)
+    return;
+   
+   /* #1 Read file from disk */ 
+   for (i=0; i < totalBytes; i+= nr)
+   {
+      nr = fread(fitsData + i, 1, totalBytes - i, fitsFile);
+     
+     if (nr <= 0)
+     {
+        IDLog("Error reading temporary FITS file.\n");
+        return;
+     }
+   }
+   fclose(fitsFile);
+   
+   compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
+    
+   /* #2 Compress it */ 
+   r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9);
+   if (r != Z_OK)
+   {
+ 	/* this should NEVER happen */
+ 	IDLog("internal error - compression failed: %d\n", r);
+	return;
+   }
+   
+   /* #3 Send it */
+   imageB.blob = compressedData;
+   imageB.bloblen = compressedBytes;
+   imageB.size = totalBytes;
+   strcpy(imageB.format, ".fits.z");
+
+   imageBP.s = IPS_OK;
+   IDSetBLOB (&imageBP, NULL);
+   
+   free (fitsData);   
+   free (compressedData);
+   
+}
+
+int ISTerminateTXDisplay(void) {
+
+  int res = 0;
+  res= STV_Interrupt() ; /* with out it hangs */
+  usleep(100000) ;
+
+  IERmCallback( cb) ;
+  cb = -1 ;
+
+  if( TXDisplayS[0].s == ISS_ON) {
+
+    TXDisplaySP.s = IPS_BUSY ;
+    IDSetSwitch(&TXDisplaySP, "Stopping display read out");
+
+    DisplayCTP.s = IPS_IDLE ;
+    IUSaveText(&DisplayCT[0], "                        "); /* reset client's display */
+    IUSaveText(&DisplayCT[1], "                        ");
+    IDSetText( &DisplayCTP, NULL);
+	  
+    DisplayBTP.s = IPS_IDLE ;
+    IUSaveText(&DisplayBT[0], "                        "); /* reset client's display */
+    IUSaveText(&DisplayBT[1], "                        ");
+    IDSetText( &DisplayBTP, NULL); 
+
+    DisplayDTP.s = IPS_IDLE ;
+    IUSaveText(&DisplayDT[0], "                        "); /* reset client's display */
+    IUSaveText(&DisplayDT[1], "                        ");
+    IDSetText( &DisplayDTP, NULL); 
+
+    if(( res= STV_TerminateTXDisplay()) != 0){
+
+      fprintf( stderr, "STV: error writing TTXD %d\n", res) ;
+    }
+  } else {
+
+    res= 0 ;
+  }
+  usleep(500000) ; /* make sure that everything is discarded */
+  tcflush(fd, TCIOFLUSH);
+
+  return res ;
+}
+
+int ISRestoreTXDisplay(void) {
+
+  int res ;
+
+  cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ;
+
+  if( TXDisplayS[0].s == ISS_ON) {
+
+    usleep(500000) ; /* STV need a little rest */
+    res= STV_TXDisplay() ;
+
+    TXDisplaySP.s = IPS_OK ;
+    IDSetSwitch(&TXDisplaySP, "Starting Display read out");
+
+    DisplayCTP.s = IPS_OK;
+    IDSetText (&DisplayCTP, NULL);
+    
+    DisplayBTP.s = IPS_OK;
+    IDSetText (&DisplayBTP, NULL);
+
+    DisplayDTP.s = IPS_OK;
+    IDSetText (&DisplayDTP, NULL);
+   
+  }
+  return res ;
+}
+
+int ISMessageImageInfo( int buffer,  IMAGE_INFO *image_info) {
+
+  buffer++ ;
+ 
+/*     IDMessage( mydev, "B%2d: descriptor:%d\n", buffer, image_info->descriptor) ; */
+/*     IDMessage( mydev, "B%2d: height:%d\n", buffer, image_info->height) ; */
+/*     IDMessage( mydev, "B%2d: width:%d\n", buffer, image_info->width) ; */
+/*     IDMessage( mydev, "B%2d: top:%d\n", buffer, image_info->top) ; */
+/*     IDMessage( mydev, "B%2d: left:%d\n", buffer, image_info->left) ; */
+  IDMessage( mydev, "B%2d: Exposure:%6.3f, Height:%2d, Width:%2d, CCD Temperature:%3.1f\n", buffer, image_info->exposure, image_info->height, image_info->width, image_info->ccdTemp) ;
+/*     IDMessage( mydev, "B%2d: noExposure:%d\n", buffer, image_info->noExposure) ; */
+/*     IDMessage( mydev, "B%2d: analogGain:%d\n", buffer, image_info->analogGain) ; */
+/*     IDMessage( mydev, "B%2d: digitalGain:%d\n", buffer, image_info->digitalGain) ; */
+/*     IDMessage( mydev, "B%2d: focalLength:%d\n", buffer, image_info->focalLength) ; */
+/*     IDMessage( mydev, "B%2d: aperture:%d\n", buffer, image_info->aperture) ; */
+/*     IDMessage( mydev, "B%2d: packedDate:%d\n", buffer, image_info->packedDate) ; */
+  IDMessage( mydev, "B%2d: Year:%4d, Month: %2d, Day:%2d\n", buffer, image_info->year, image_info->month, image_info->day) ;
+/*     IDMessage( mydev, "B%2d: Day:%d\n", buffer, image_info->day) ; */
+/*     IDMessage( mydev, "B%2d: Month:%d\n", buffer, image_info->month) ; */
+/*     IDMessage( mydev, "B%2d: packedTime:%d\n", buffer, image_info->packedTime) ; */
+/*     IDMessage( mydev, "B%2d: Seconds:%d\n", buffer, image_info->seconds) ; */
+/*     IDMessage( mydev, "B%2d: minutes:%d\n", buffer, image_info->minutes) ; */
+  IDMessage( mydev, "B%2d: Hours:%2d, Minutes:%2d, Seconds:%d\n", buffer, image_info->hours, image_info->minutes, image_info->seconds) ;
+
+/*     IDMessage( mydev, "B%2d: ccdTemp:%f\n", buffer, image_info->ccdTemp) ; */
+/*     IDMessage( mydev, "B%2d: siteID:%d\n", buffer, image_info->siteID) ; */
+/*     IDMessage( mydev, "B%2d: eGain:%d\n", buffer, image_info->eGain) ; */
+/*     IDMessage( mydev, "B%2d: background:%d\n", buffer, image_info->background) ; */
+/*     IDMessage( mydev, "B%2d: range :%d\n", buffer, image_info->range ) ;   */
+/*     IDMessage( mydev, "B%2d: pedestal:%d\n", buffer, image_info->pedestal) ; */
+/*     IDMessage( mydev, "B%2d: ccdTop  :%d\n", buffer, image_info->ccdTop) ; */
+/*     IDMessage( mydev, "B%2d: ccdLeft:%d\n", buffer, image_info->ccdLeft) ; */
+  return 0 ;
+}
+
+
+int ISRequestImageData( int compression, int buffer, int x_offset, int y_offset, int length, int lines) {
+
+  int res ;
+  int i, k ;
+  int img_size ;
+  char errmsg[1024] ;
+  int image[320][320] ;
+  IMAGE_INFO image_info ;
+
+  for(i= 0 ; i < 320 ; i++) {
+    for(k= 0 ; k < 320 ; k++) {
+      image[i][k]= -1 ;
+    }
+  }
+  
+
+  res= STV_RequestImage( compression, buffer, x_offset, y_offset, &length, &lines, image, &image_info) ;
+ 
+  if( res== 0) {
+
+    STVImg->width= length;
+    STVImg->height= lines ;
+
+    img_size =   STVImg->width * STVImg->height * sizeof(unsigned short);
+
+    STVImg->img= malloc (img_size);
+  
+    for(i= 0 ; i < STVImg->height ; i++) { /* x */
+      for(k= 0 ; k < STVImg->width ; k++) { /* y */
+
+	STVImg->img[ STVImg->width* i + k]= (unsigned short)image[i][k] ;
+	/* Uncomment this line in case of doubts about decompressed values and compare */
+        /* both sets. */
+	/*fprintf( stderr, "Line: %d %d %d %d\n", i, k, image[i][k], STVImg->img[ STVImg->width* i + k]) ; */
+
+	if(STVImg->img[ STVImg->width* i + k] < image_info.minValue) {
+	  
+	  image_info.minValue= STVImg->img[ STVImg->width* i + k] ;
+	}
+	if(STVImg->img[ STVImg->width* i + k] > image_info.maxValue) {
+	  
+	  image_info.maxValue= STVImg->img[ STVImg->width* i + k] ;
+	}
+      }
+    }
+    writeFITS( "FITS.fits", &image_info, errmsg) ;
+    /*fprintf( stderr, "Fits writing message: %s\n", errmsg) ;	 */
+    free( STVImg->img) ;
+  }
+  return res ;
+}
+
+void ISUpdateDisplay( int buffer, int line) {
+
+  if( !(( line+1) % 10)) {
+  
+    sprintf( DisplayCT[0].text, "Buffer %2d line: %3d", buffer+1, line+ 1) ;
+    strcpy( DisplayBT[0].text, DisplayCT[0].text) ;
+    strcpy( DisplayDT[0].text, DisplayCT[0].text) ;
+   
+    DisplayCTP.s= IPS_OK ;
+    IDSetText( &DisplayCTP, NULL) ;
+    DisplayBTP.s= IPS_OK ;
+    IDSetText( &DisplayBTP, NULL) ;
+    DisplayDTP.s= IPS_OK ;
+    IDSetText( &DisplayDTP, NULL) ;
+
+  } else if(( line+1)== 1) { /* first time  */
+
+    IDMessage( mydev, "Image download started") ;
+
+  } else if( line < 0) { /* last line */
+
+    line= -line ;
+
+    sprintf( DisplayCT[0].text, "Buffer %2d line: %3d", buffer+1, line+ 1) ;
+    strcpy( DisplayBT[0].text, DisplayCT[0].text) ;
+    strcpy( DisplayDT[0].text, DisplayCT[0].text) ;
+
+    DisplayCTP.s= IPS_OK ;
+    IDSetText( &DisplayCTP, NULL) ;
+    DisplayBTP.s= IPS_OK ;
+    IDSetText( &DisplayBTP, NULL) ;
+    DisplayDTP.s= IPS_OK ;
+    IDSetText( &DisplayDTP, NULL) ;
+    IDMessage( mydev, "Image download ended, buffer %2d line: %3d", buffer+1, line) ;
+  }
+}
Index: /BAORadio/libindi/v1/drivers/video/stvdriver.c
===================================================================
--- /BAORadio/libindi/v1/drivers/video/stvdriver.c	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/stvdriver.c	(revision 500)
@@ -0,0 +1,1584 @@
+#if 0
+    STV Low Level Driver
+    Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch 
+    The initial work is based on the program STVremote by Shashikiran Ganesh.
+    email: gshashikiran_AT_linuxmail_dot_org
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+#include <unistd.h> 
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h> 
+#include <time.h>
+#include <stdlib.h>
+
+#include "stvdriver.h"
+
+/* Config parameters */
+#include <config.h>
+
+#ifdef HAVE_NOVA_H
+#include <libnova.h>
+#endif
+    
+#ifndef _WIN32
+#include <termios.h>
+#endif
+
+/* INDI Common Routines/RS232 */
+
+#include "indicom.h"
+
+extern int fd ;
+extern char tracking_buf[] ;
+struct termios orig_tty_setting;    /* old serial port setting to restore on close */
+struct termios tty_setting;         /* new serial port setting */
+
+
+#define FALSE 0
+#define TRUE 1
+
+/*int tty_read( int fd, char *buf, int nbytes, int timeout, int *nbytes_read) ; */
+/*int tty_write( int fd, const char *buffer, int *nbytes_written) ; */
+void ISUpdateDisplay( int buffer, int line) ;
+
+int STV_portWrite( char *buf, int nbytes) ;
+int STV_TXDisplay( void) ;
+int STV_TerminateTXDisplay( void) ;
+int STV_FileStatus( int) ;
+int STV_DownloadComplete( void) ;
+int STV_RequestImage( int compression,  int buffer, int x_offset, int y_offset, int *length, int *lines, int image[][320], IMAGE_INFO *image_info) ;
+int STV_RequestImageData( int compression, int *data, int j, int length, int *values) ;
+int STV_Download( void) ;
+int STV_DownloadAll( void) ;
+int STV_RequestAck( void) ;
+int STV_CheckHeaderSum( unsigned char *buf) ;
+int STV_CheckDataSum( unsigned char *data) ;
+int STV_PrintBuffer( unsigned char *buf, int n ) ;
+int STV_PrintBufferAsText( unsigned char *buf, int n ) ;
+int STV_CheckAck( unsigned char *buf) ;
+int STV_SendPacket( int cmd, int *data, int n) ;
+int STV_ReceivePacket( unsigned char *buf, int mode) ;
+int STV_DecompressData( unsigned char *data, int *values, int length, int expected_n_values) ;
+int STV_BufferStatus( int buffer) ;
+void STV_PrintBits( unsigned int x, int n) ;
+
+unsigned int STV_RecombineInt( unsigned char low_byte, unsigned char high_byte) ;
+unsigned int STV_GetBits( unsigned int x, int p, int n) ;
+
+int STV_MenueSetup( int delay) ;
+int STV_MenueDateTime( int delay) ;
+int STV_MenueCCDTemperature( int delay) ;
+
+typedef struct {
+
+  double ccd_temperature ;
+  
+} DISPLAY_INFO ;
+
+DISPLAY_INFO di ;
+
+
+/* STV Buttons */
+
+int STV_LRRotaryDecrease(void) {
+  int data[]={LR_ROTARY_DECREASE_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_LRRotaryIncrease(void) {
+  int data[]={ LR_ROTARY_INCREASE_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_UDRotaryDecrease(void) {
+  int data[]={UD_ROTARY_DECREASE_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_UDRotaryIncrease(void) {
+  int data[]={UD_ROTARY_INCREASE_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_AKey(void) { /* Parameter button */
+  int data[]={A_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_BKey(void) { /* Value Button */
+  int data[]={ B_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_Setup(void) {
+  int data[]={SETUP_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1);
+}
+
+int STV_Interrupt(void) {
+  int data[]={INT_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_Focus(void) {
+  int data[]= {FOCUS_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_Image(void) {
+  int data[]={IMAGE_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_Monitor(void) {
+  int data[]={MONITOR_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_Calibrate(void) {
+  int data[]={CAL_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_Track(void) {
+  int data[]={TRACK_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_Display(void) {
+  int data[]={DISPLAY_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_FileOps(void) {
+  int data[]={FILEOPS_KEY_PATTERN} ;
+  return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ;
+}
+
+int STV_RequestImageInfo(int buffer, IMAGE_INFO *image_info) {
+
+  int i ;
+  int length ;
+  int res ;
+  int data[]= {buffer} ; 
+  unsigned char buf[1024] ;
+  unsigned int value[21] ;
+
+  if(( res= STV_BufferStatus( buffer)) != 0) {
+    
+    if( res== 1) {
+      /*fprintf( stderr," STV_RequestImageInfo buffer empty %d\n", buffer) ; */
+      return res ; /* Buffer is empty */
+    } else {
+      fprintf( stderr," STV_RequestImageInfo error %d\n", res) ;
+      return res ;
+    } 
+  }
+
+  res= STV_SendPacket( REQUEST_IMAGE_INFO, data, 1) ;
+  usleep(50000) ;
+  res= STV_ReceivePacket( buf, 0) ;
+
+  if(buf[1] != REQUEST_IMAGE_INFO) {
+
+    /*length= buf[3] * 0x100 + buf[2] ; */
+    /*res= STV_PrintBuffer(buf, 6+ length+ 2) ; */
+
+AGAINI:    if(( res= STV_ReceivePacket( buf, 0)) < 0) { /* STV answers with a packet 0x03 sometimes, should be 0x04 */
+      return -1 ;;
+    }
+    if(buf[1] != REQUEST_IMAGE_INFO) { /* Second try */
+      fprintf( stderr, "STV_RequestImageInfo: expected REQUEST_IMAGE_INFO, received %d, try again\n", buf[1]) ;
+      goto AGAINI ;
+    }
+  }
+
+  length= buf[3] * 0x100 + buf[2]; 
+
+  /* DECODE it */
+
+  for( i= 6;  i < length; i+= 2) {
+    value[( i- 6)/2]= STV_RecombineInt( buf[ i], buf[ i+1]) ;
+  }
+ 
+  image_info->descriptor = value[0] ; 
+
+
+  /* Decode the descriptor */
+
+  /*STV_PrintBits(( unsigned int)value[0], 16) ; */
+
+  if(( image_info->descriptor & ID_BITS_MASK)== ID_BITS_10) {
+
+    /*    fprintf( stderr, "ADC Resolution: 10 bits\n") ; */
+
+  } else if(( image_info->descriptor & ID_BITS_MASK )== ID_BITS_8) {
+
+    /*fprintf( stderr, "Resolution: 8 bits (focus mode only)\n") ; */
+  }
+
+  if(( image_info->descriptor & ID_UNITS_MASK)== ID_UNITS_INCHES) {
+
+    /*fprintf( stderr, "Units: inch\n") ; */
+
+  } else if(( image_info->descriptor & ID_UNITS_MASK)== ID_UNITS_CM) {
+
+    /*fprintf( stderr, "Unis: cm\n") ;  */
+  } 
+
+  if(( image_info->descriptor & ID_SCOPE_MASK)== ID_SCOPE_REFRACTOR) {
+ 
+    /*fprintf( stderr, "Refractor\n") ;  */
+  } else if(( image_info->descriptor & ID_SCOPE_MASK)== ID_SCOPE_REFLECTOR) {
+
+    /*fprintf( stderr, "Reflector\n") ;  */
+  }
+
+
+  if(( image_info->descriptor & ID_DATETIME_MASK)== ID_DATETIME_VALID) {
+
+    /*fprintf( stderr, "Date and time valid\n") ;  */
+  } else if(( image_info->descriptor & ID_DATETIME_MASK)== ID_DATETIME_INVALID) {
+
+    /*fprintf( stderr, "Date and time invalid\n") ;  */
+  }
+
+
+  if(( image_info->descriptor & ID_BIN_MASK)== ID_BIN_1X1) {
+
+    image_info->binning=1 ; 
+  } else if(( image_info->descriptor & ID_BIN_MASK)== ID_BIN_2X2) {
+
+    image_info->binning=2 ; 
+  } else if(( image_info->descriptor & ID_BIN_MASK)== ID_BIN_3X3) {
+
+    image_info->binning=3 ; 
+  }
+
+  if(( image_info->descriptor & ID_PM_MASK)== ID_PM_PM) {
+
+    /*fprintf( stderr, "Time: PM\n") ;  */
+  } else if(( image_info->descriptor & ID_PM_MASK)== ID_PM_AM) {
+
+    /*fprintf( stderr, "Time: AM\n") ;  */
+  }
+
+  /* ToDo: Include that to the fits header */
+  if(( image_info->descriptor & ID_FILTER_MASK)== ID_FILTER_LUNAR) {
+    /*fprintf( stderr, "Filter: Lunar\n") ;  */
+  } else if(( image_info->descriptor & ID_FILTER_MASK)== ID_FILTER_NP ) {
+    /*fprintf( stderr, "Filter: clear\n") ;  */
+  }
+
+  /* ToDo: Include that to the fits header */
+  if(( image_info->descriptor & ID_DARKSUB_MASK )== ID_DARKSUB_YES) {
+
+    /*fprintf( stderr, "Drak sub yes\n") ;  */
+  } else if(( image_info->descriptor & ID_DARKSUB_MASK )== ID_DARKSUB_NO) {
+
+    /*fprintf( stderr, "Dark sub no\n") ;  */
+  }
+
+  if(( image_info->descriptor & ID_MOSAIC_MASK)== ID_MOSAIC_NONE) {
+
+    /*fprintf( stderr, "Is NOT a mosaic\n") ;  */
+  } else if(( image_info->descriptor & ID_MOSAIC_MASK)== ID_MOSAIC_SMALL) {
+
+    /*fprintf( stderr, "Is a small mosaic\n") ;  */
+  } else if(( image_info->descriptor & ID_MOSAIC_MASK)== ID_MOSAIC_LARGE) {
+
+    /*fprintf( stderr, "Is a large mosaic\n") ;  */
+  }
+
+  image_info->height     = value[1] ; 
+  image_info->width      = value[2] ; 
+  image_info->top        = value[3] ; 
+  image_info->left       = value[4] ; 
+
+  /* Exposure time */
+
+  if((value[5]>= 100 ) && (value[5]<= 60000)) {
+
+    image_info->exposure   = ((float)value[5]) * 0.01; 
+
+  } else if((value[5]>= 60001 ) && (value[5]<= 60999)){
+
+    image_info->exposure   = (( float)value[5]- 60000.) *.001 ;
+  } else {
+    fprintf( stderr, "Error Exposure time %d\n", value[5]) ;
+    image_info->exposure   = -1. ;
+  }
+
+  image_info->noExposure = value[6] ; 
+  image_info->analogGain = value[7] ; 
+  image_info->digitalGain= value[8] ; 
+  image_info->focalLength= value[9] ; 
+  image_info->aperture   = value[10] ; 
+
+
+  image_info->packedDate = value[11] ; 
+  image_info->year  = STV_GetBits( value[11], 6, 7) + 1999;
+  image_info->day   = STV_GetBits( value[11], 11, 5) ;
+  image_info->month = STV_GetBits( value[11], 15, 4) ;
+
+  image_info->packedTime = value[12];
+  image_info->seconds    = STV_GetBits( value[12], 5, 6) ;
+  image_info->minutes    = STV_GetBits( value[12], 11, 6) ;
+  image_info->hours      = STV_GetBits( value[12], 15, 4) ;
+
+  if(( image_info->descriptor & ID_PM_PM) > 0) {
+
+    image_info->hours += 12 ;
+  }
+  
+  if((value[13] & 0x8000)== 0x8000) {
+    
+    image_info->ccdTemp=  (float)(0xffff - value[13]) /100. ;
+   
+  } else {
+
+    image_info->ccdTemp=   (float)value[13]/100. ; 
+  }
+
+  image_info->siteID     = value[14] ; 
+  image_info->eGain      = value[15] ; 
+  image_info->background = value[16] ; 
+  image_info->range      = value[17] ; 
+  image_info->pedestal   = value[18] ; 
+  image_info->ccdTop     = value[19] ; 
+  image_info->ccdLeft    = value[20] ; 
+
+
+/*   fprintf( stderr, "descriptor:%d 0x%2x 0x%2x\n", image_info->descriptor, buf[6], buf[6+1]) ; */
+/*   fprintf( stderr, "height:%d\n", image_info->height) ; */
+/*   fprintf( stderr, "width:%d\n", image_info->width) ; */
+/*   fprintf( stderr, "top:%d\n", image_info->top) ; */
+/*   fprintf( stderr, "left:%d\n", image_info->left) ; */
+/*   fprintf( stderr, "exposure:%f\n", image_info->exposure) ; */
+/*   fprintf( stderr, "noExposure:%d\n", image_info->noExposure) ; */
+/*   fprintf( stderr, "analogGain:%d\n", image_info->analogGain) ; */
+/*   fprintf( stderr, "digitalGain:%d\n", image_info->digitalGain) ; */
+/*   fprintf( stderr, "focalLength:%d\n", image_info->focalLength) ; */
+/*   fprintf( stderr, "aperture:%d\n", image_info->aperture) ; */
+/*   fprintf( stderr, "packedDate:%d\n", image_info->packedDate) ; */
+/*   fprintf( stderr, "Year:%d\n", image_info->year) ; */
+/*   fprintf( stderr, "Day:%d\n", image_info->day) ; */
+/*   fprintf( stderr, "Month:%d\n", image_info->month) ; */
+/*   fprintf( stderr, "packedTime:%d\n", image_info->packedTime) ; */
+/*   fprintf( stderr, "Seconds:%d\n", image_info->seconds) ; */
+/*   fprintf( stderr, "minutes:%d\n", image_info->minutes) ; */
+/*   fprintf( stderr, "hours:%d\n", image_info->hours) ; */
+/*   fprintf( stderr, "ccdTemp:%f\n", image_info->ccdTemp) ; */
+/*   fprintf( stderr, "siteID:%d\n", image_info->siteID) ; */
+/*   fprintf( stderr, "eGain:%d\n", image_info->eGain) ; */
+/*   fprintf( stderr, "background:%d\n", image_info->background) ; */
+/*   fprintf( stderr, "range :%d\n", image_info->range ) ; */
+/*   fprintf( stderr, "pedestal:%d\n", image_info->pedestal) ; */
+/*   fprintf( stderr, "ccdTop  :%d\n", image_info->ccdTop) ; */
+/*   fprintf( stderr, "ccdLeft:%d\n", image_info->ccdLeft) ; */
+
+  return 0 ;
+}
+
+int STV_RequestImage( int compression, int buffer, int x_offset, int y_offset, int *length, int *lines, int image[][320], IMAGE_INFO *image_info) {
+
+  int i, j ;
+  int res ;
+  int n_values ; 
+  unsigned char buf[0xffff] ;
+  int values[1024] ;
+  int data[]= { 0, y_offset, *length, buffer} ;  /* Offset row, Offset line, length, buffer number */
+  int XOFF ;
+
+  /* fprintf(stderr, "STV_RequestImage: --------------------------------buffer= %d, %d\n", buffer, lines) ; */
+
+  if(( res= STV_RequestImageInfo( buffer, image_info)) != 0) {  /* Trigger for download */
+    /* buffer empty */
+    return res ;
+  } 
+  res= STV_BKey() ; /* "press" the STV Value button */ 
+  usleep(50000) ;
+  res= STV_ReceivePacket(buf, 0) ;
+
+  /* Check the boundaries obtained from the image data versus windowing */
+  /* Take the smaller boundaries in each direction */
+
+  if( x_offset > image_info->height) {
+    x_offset= image_info->height ;
+  }
+  XOFF=  image_info->top +  x_offset ;
+
+  if( y_offset > image_info->width) {
+    y_offset= image_info->width ;
+  }
+  data[1]=  image_info->left +  y_offset ;
+
+  if( *length > image_info->width- y_offset) {
+    *length= image_info->width- y_offset  ;
+  }
+  data[2]= *length ;
+
+  if( *lines > image_info->height- x_offset) {
+    *lines= image_info->height- x_offset  ;
+  }
+ 
+  /*fprintf(stderr, "STV_RequestImage: DATA 0=%d, 1=%d, 2=%d, 3=%d, length=%d, lines=%d\n", data[0], data[1], data[2], data[3], *length, *lines) ; */
+
+  for( j= 0 ; j < *lines ; j++) {
+
+    data[0]=  j + XOFF; /*line */
+  
+    if(( n_values= STV_RequestImageData( compression, data, j, *length, values)) < 0) {
+      fprintf(stderr, "STV_RequestImage: Calling STV_RequestImageData failed %d\n", n_values) ; 
+      return n_values ;
+    } else {
+      for( i= 0; i < n_values ; i++) {
+
+	image[j][i]= values[i] ;
+      }
+      ISUpdateDisplay( buffer, j) ;
+    }
+  }
+  /* Read the 201th line, see mosaic mode */
+
+  /* ToDo: analyze/display the data or use them in the fits header(s) */
+  data[0]=  200; /*line */
+
+  if(( res= STV_RequestImageData( 1, data, 200, *length, values)) < 0) {
+
+    return res ;
+  } else {
+    for( i= 0 ; i< n_values ; i++) {
+
+      /* fprintf( stderr, "%d: %d ", i, values[i]) ; */
+    }
+    /* fprintf( stderr, "\n") ; */
+  }
+  res= STV_DownloadComplete() ; 
+  ISUpdateDisplay( buffer,  -j) ;
+  return  0 ;
+}
+
+int STV_RequestImageData( int compression, int *data, int j, int length, int *values) {
+
+  int i ;
+  int res ; 
+  int data_length ;
+  int n_values ;
+  unsigned char buf[0xffff] ;
+
+  data_length= -1 ;
+ 
+  if( compression== ON) { /* compressed download */
+  
+    if(( res= STV_SendPacket( REQUEST_COMPRESSED_IMAGE_DATA, data, 4)) != 0){
+
+      fprintf(stderr, "STV_RequestImageData: could not write\n") ;
+      return -1 ;
+    } 
+
+AGAINC:    if(( res= STV_ReceivePacket(buf, 0)) > 0) {
+
+
+      if( buf[1] != REQUEST_COMPRESSED_IMAGE_DATA) {
+
+	if( buf[1] != DISPLAY_ECHO) {
+	  if( buf[1] != ACK) {
+	    fprintf(stderr, "STV_RequestImageData: expected REQUEST_COMPRESSED_IMAGE_DATA, received %2x\n",  buf[1]) ;
+	  }
+	}
+	goto AGAINC ;
+      }
+
+      data_length= (int)buf[3] * 0x100 + (int)buf[2] ;
+      
+      if(( n_values= STV_DecompressData((buf+6), values, data_length, length)) < 0 ) {
+
+	n_values= -n_values ;
+	fprintf( stderr, "SEVERE ERROR on Line %d, pixel position=%d\n", j, n_values) ;
+	_exit( -1) ;
+      }
+
+      if( n_values == length) {
+
+        return n_values ;
+      } else {
+
+	fprintf( stderr, "SEVERE Error: Length not equal, Line: %d, %d != %d, data %2x %2x, values %d, %d\n", j, n_values, length, buf[ 6+ length -2], buf[ 6+ length -1], values[n_values-2], values[n_values-1]) ;
+	_exit( 1) ;
+      }
+    } else {
+      fprintf( stderr, "Error: waiting for data on the serial port at line %d\n", j) ;
+      return -1 ;
+    }
+  } else { /* uncompressed download */
+
+    if(( res= STV_SendPacket( REQUEST_IMAGE_DATA, data, 4))== 0) {
+
+AGAINU:      if(( res= STV_ReceivePacket(buf, 0)) > 0) {
+
+	if( buf[1] != REQUEST_IMAGE_DATA) {
+	  if( buf[1] != DISPLAY_ECHO) {
+	    if( buf[1] != ACK) {
+	      fprintf(stderr, "STV_RequestImageData: expected REQUEST_IMAGE_DATA, received %2x\n",  buf[1]) ;
+	    }
+	  }
+	  goto AGAINU ;
+	}
+
+	data_length= (int)buf[3] * 0x100 + (int)buf[2] ;
+
+	for( i= 0; i < data_length ; i += 2) {
+
+	  values[i/2]= STV_RecombineInt(buf[6 + i], buf[7 + i]) ;
+	}
+	return 	data_length/2 ;
+	/*ISUpdateDisplay( buffer, j) ; */ /* Update the display of the INDI client */
+      } else {
+	fprintf( stderr, "Error: waiting for data on the serial port at line %d\n", j) ;
+	return -1 ;
+      } 
+    } else {
+      fprintf( stderr, "STV_RequestImageData: error writing %d\n",  res) ;
+    }
+  } 
+  return 0 ;
+}
+int STV_DecompressData( unsigned char *data, int *values, int length, int expected_n_values) {
+
+  int i, n_values ;
+  int value ;
+  int base ;
+ 
+  base= STV_RecombineInt( data[0], data[1]) ; /*STV Manual says: MSB then LSB! */
+
+  values[0]= base ;
+  i= 2 ;
+  n_values= 1 ;
+
+  while( i < length ) {
+   
+    if( (( data[ i] & 0xc0))== 0x80) { /*two bytes, first byte: bit 7 set, 6 cleared, 14 bits data */
+
+      if(( data[ i] & 0x20)== 0x20) { /* minus sign set? */
+
+	value= - ((int)(( (~data[ i] & 0x1f)) * 0x100) + (((int) (~data[ i+ 1])) & 0xff))- 1 ; /* value without sign */
+      } else {
+
+	value=   (int) (( data[ i] & 0x1f) * 0x100) + (int) (data[ i + 1]) ;
+      }      
+
+      base= value + base ; /* new base value */
+      values[n_values++]= base ; /*pixel data */
+      i += 2 ;
+
+    } else if((( data[ i] & 0x80))== 0) { /* one byte: bit 7 clear (7 bits data) */
+
+      if(( data[ i] & 0x40)== 0x40) { /* minus sign set? */
+	
+	value= - (int) ( (~(data[ i])) & 0x3f) - 1 ; /* value without sign */
+      } else {
+
+	value=   (int) ( data[ i] & 0x3f) ;
+	/*fprintf( stderr, "Value 7P: %d, pixel value: %d, length %d, pix=%d\n", value, value+ base, length, n_values) ; */
+      }
+      /* Sometimes the STV send a 0 at the end, thats not very likely a pixel to pixel variation */
+      /* I checked the last decompressed pixel value against the last uncompressed pixel value */
+      /* with different images - it seems to be ok.    */
+      if(( value == 0) &&( n_values== expected_n_values)){
+	/*fprintf( stderr, "Ignoring byte %d, Zero difference obtained values: %d\n", i, n_values) ; */
+      } else {
+	base= value + base ;
+	values[n_values++]= base ; 
+      }
+      i++ ;
+    } else if( (( data[ i] & 0xc0))== 0xc0) { /*two bytes, values= pixel_n/4  */
+
+
+      /*STV_PrintBits(  data[ i], 8) ; */
+      /*STV_PrintBits(  data[ i+ 1], 8) ; */
+
+
+      value=  4* ((int) (( data[ i] & 0x3f) * 0x100) + (int) (data[ i + 1])) ;
+      /*fprintf( stderr, "Value 14P: %d, pixel value: %d, length %d, pix=%d\n", value, value+ base, length, n_values) ; */
+    
+      base= value ;
+      values[n_values++]= value ;
+ 
+      i += 2 ;
+      /*return -n_values ; */
+    } else {
+
+      fprintf( stderr, "Unknown compression case: %2x, length %d, i=%d\n",  data[ i], length, i) ;
+      return -n_values ; /* exit */
+    }
+  }
+  return n_values ;
+}
+
+int STV_TXDisplay(void) {
+
+  int data[]={TRUE} ;
+  return  STV_SendPacket( DISPLAY_ECHO, data, 1);
+}
+
+int STV_TerminateTXDisplay(void) {
+  int res ;
+  int data[]={FALSE} ;
+
+  res= STV_SendPacket( DISPLAY_ECHO, data, 1); 
+
+  /* Despite the manual says so, I not always see an ACK packet */
+  /* So i flush it for the moment */
+
+  tcflush(fd, TCIOFLUSH);
+  return res ;
+}
+
+int STV_FileStatus(int status) {
+
+  int data[]= {status} ;
+  return STV_SendPacket( FILE_STATUS, data, 1);
+}
+
+int STV_DownloadComplete(void) {
+
+  return STV_SendPacket( DOWNLOAD_COMPLETE, NULL, 0);
+}
+
+int STV_Download(void) {
+  
+  return STV_SendPacket( REQUEST_DOWNLOAD, NULL, 0) ;
+}
+
+int STV_DownloadAll(void) {
+ 
+ return STV_SendPacket( REQUEST_DOWNLOAD_ALL, NULL, 0);
+}
+
+int STV_RequestAck(void) {
+  int data[]={0x06,0x06,0x06 } ;
+  /* SBIG manual says contains data, which? */
+  return STV_SendPacket( REQUEST_ACK, data, 3) ;
+}
+
+int STV_BufferStatus( int buffer){
+
+  unsigned char buf[1024];
+  int buffers ;
+  int res ;
+  int val ;
+
+  /*fprintf(stderr, "STV_BufferStatus entering\n") ; */
+  usleep(50000) ;
+  if(( res= STV_SendPacket( REQUEST_BUFFER_STATUS, NULL, 0)) < 0) {
+    fprintf( stderr, "STV_BufferStatus: Error requesting buffer status: %d\n", buffer) ;
+    return -1 ;
+  } else {
+    /*fprintf( stderr, "STV_BufferStatus %2d\n", buffer) ; */
+  }
+ 
+AGAIN: if(( res= STV_ReceivePacket( buf, 0)) < 0) { 
+          fprintf( stderr, "STV_BufferStatus: Error reading: %d\n", res) ;
+          return -1 ;;
+       } 
+
+  if( buf[1]== REQUEST_BUFFER_STATUS) {
+
+    buffers= STV_RecombineInt( buf[6], buf[7]) * 0x10000 + STV_RecombineInt( buf[8], buf[9]) ;
+
+    if(( val= STV_GetBits( buffers, buffer, 1))== 1) {
+
+      res= 0 ; /* image present */
+    } else {
+      
+      /*fprintf( stderr, "STV_BufferStatus %2d is empty\n", buffer) ; */
+      res= 1 ; /* empty */
+    }
+  } else {
+    /* The SBIG manual does not specify an ACK, but it is there (at least sometimes) */
+    if(( val= STV_CheckAck( buf))== 0) {
+      /*fprintf( stderr, "STV_BufferStatus SAW ACK, reading again\n") ; */
+      goto AGAIN ;
+    } 
+    /* The SBIG manual does not specify the cmd in the answer */
+    if( buf[1] !=  DISPLAY_ECHO) {
+      fprintf( stderr, "STV_BufferStatus: unexpected cmd byte received %d\n", buf[1]) ;
+      val=  STV_RecombineInt(buf[2], buf[3]) ;
+      res= STV_PrintBuffer( buf, 6+ val + 2) ;
+      return -1 ;
+    } else {
+      /* a display packet is silently ignored, there are many of this kind */
+      fprintf( stderr, "STV_BufferStatus  DISPLAY_ECHO received, try again\n") ;
+      return -1 ;
+    }
+  }
+  /* fprintf(stderr, "STV_BufferStatus leaving\n") ; */
+  return  res;
+}
+/* Low level communication */
+/*  STV_ReceivePacket n_bytes read */
+int STV_ReceivePacket( unsigned char *buf, int mode) {
+
+  int i,j,k ;
+  int n_bytes=0 ;
+  int length=0 ;
+  int res ;
+  int trb=0 ;
+  int pos=0 ;
+  char display1[25] ;
+  char display2[25] ;
+ 
+  j= 0 ;
+  tracking_buf[ 0]= 0 ;
+
+  /*fprintf( stderr,"R") ; */
+
+  while(pos < 6) { 
+
+    /* Read the header first, calculate length of data */
+    /* At higher speeds the data arrives in smaller chunks, assembling the packet */
+    if(( trb= read( fd, (char *)(buf + pos), 1))== -1) {
+      fprintf(stderr, "Error, %s\n", strerror(errno)) ;	
+    }
+    
+    if(buf[0]== 0xa5) { 
+
+      if( pos== 5) {
+
+	pos++ ;
+	break ;
+      } else {    
+
+	pos+= trb ; /* could be zero */
+      }
+    } else { 
+      /* In tracking mode the STV sends raw data (time, brightnes, centroid x,y). */
+      /* Under normal operation here appear pieces of a packet. This could happen */
+      /* on start up or if something goes wrong. */
+
+      tracking_buf[ j++]= buf[pos] ;
+      /*fprintf(stderr, "READ: %d, read %d, pos %d,  0x%2x< %c\n", j, trb, pos, buf[pos], buf[pos]) ;  */
+    }
+  }
+
+
+  if( j> 0) { 
+    /* Sometimes the packets are corrupt, e.g. at the very beginning */
+    /* Or it is tracking information */
+
+    tracking_buf[ j]= 0 ;
+
+    if( mode== ON) { /* Tracking mode */
+    
+      fprintf(stderr, "%s\n", tracking_buf) ;
+    } else {
+
+      for( k= 0 ; k< j; k++) {
+	if(!( tracking_buf[ k] >29 &&  tracking_buf[ k] < 127)) {
+	  tracking_buf[ k]= 0x20 ; /* simply */
+	}
+      }
+      fprintf(stderr, "Not a packet: length: %d >%s<\n", j, tracking_buf) ;
+    }
+  }
+
+  n_bytes= pos ; 
+      
+  if(( buf[0]== 0xa5) && ( pos== 6)) { /* Check the sanity of the header part */
+    if((res= STV_CheckHeaderSum( buf))== 0) {
+
+      length= (int)buf[3] * 0x100 + (int)buf[2]; ;
+    
+      if( length >0) {
+
+        trb= 0 ;
+	while( pos < 6 + length + 2) { /* header, data, check sum */
+
+	  /* At higher speeds the data arrives in smaller chunks, assembling the packet */
+	 
+	  if(( trb= read(fd, (char *)(buf + pos), (6 + length + 2)- pos))== -1) {
+
+	    fprintf(stderr, "STV_ReceivePacket: Error reading at serial port, %s\n", strerror( errno)) ;	
+	    return -1 ;
+	  }
+	  pos += trb ;
+	}
+	n_bytes += pos ;
+	/*fprintf(stderr, "STV_ReceivePacket: LEAVING LOOP length %d, to read %d, read %d, pos %d\n",  length, (6 + length + 2)- pos, trb, pos) ; */
+      }
+    } else {    
+
+      fprintf(stderr, "STV_ReceivePacket: Header check failed\n") ;
+      return -1 ;
+    }
+  } else if( pos >0) {
+    
+    for(i= 0 ; i < 6 ; i++) { 
+      if( buf[i]==0xa5){
+	 fprintf(stderr, "STV_ReceivePacket: pos= %d, saw 0xa5 at %d\n", pos, i) ;
+      }
+    }
+    return -1 ;
+  } else {
+    
+    fprintf(stderr, "STV_ReceivePacket: NO 0xa5 until pos= %d\n", pos) ; 
+    return -1 ;
+  }
+
+  if( length > 0) { /* Check the sanity of the data */
+
+    if((res= STV_CheckDataSum( buf))== -1) {
+      return -1 ;
+    }
+  }
+  /* Analyse the display and retrieve the values */
+  if( buf[1]== DISPLAY_ECHO) {
+
+    for( i=0 ; i< 24; i++) {
+
+      display1[i]= buf[i+6] ;
+      if(  display1[i]== 0 ){
+	display1[i]= 0x32 ;
+      }
+      display2[i]= buf[i+30] ;
+      if(  display2[i]== 0 ){
+	display2[i]= 0x32 ;
+      }
+    }
+    display1[24]= 0 ;
+    display2[24]= 0 ;
+		   
+    /*fprintf(stderr, "STV_ReceivePacket: DISPLAY1 %s<\n", display1) ; */
+    /*fprintf(stderr, "STV_ReceivePacket: DISPLAY2 %s<\n", display2) ; */
+
+    /* CCD temperature */ 
+    if(( res= strncmp( "CCD Temp.", display2, 9)) ==0) {
+      float t ;
+      res= sscanf( display2, "CCD Temp.          %f", &t) ;
+      di.ccd_temperature= (double) t;
+      /*fprintf(stderr, "STV_ReceivePacket: Read from DISPLAY2 %g<\n", di.ccd_temperature ) ; */
+    }/* further values can be stored here */
+  } 
+  return n_bytes ;
+}
+
+
+int STV_CheckHeaderSum( unsigned char *buf) {
+ 
+  int sum   =  buf[0] + buf[1] + buf[2] + buf[3] ; /* Calculated header sum */
+  int sumbuf=  STV_RecombineInt( buf[4],buf[5]) ;  /* STV packet header sum */
+
+  if(buf[0] != 0xa5) {
+
+    fprintf(stderr, "STV_CheckHeaderSum:  Wrong start byte, skipping\n") ;
+    return -1 ;
+  }
+
+  if( sum != sumbuf) {
+
+    fprintf(stderr, "STV_CheckHeaderSum: NOK: %d==%d\n", sum, sumbuf ) ;
+    return -1 ;
+  }
+  return 0 ;
+}
+
+int STV_CheckDataSum( unsigned char *buf) {
+  /* *buf points to the beginning of the packet */
+
+  int j, n ; 
+  int sum= 0 ;
+  int sumbuf=0  ;
+
+  n= STV_RecombineInt( buf[2], buf[3]) ;
+
+  if( n== 0) {
+    fprintf(stderr, "STV_CheckDataSum: No data present\n") ;
+    return 0 ;    
+  }
+  sumbuf=  STV_RecombineInt( buf[6 + n], buf[6 + n +1]) ;
+
+  for( j=0; j < n ; j++) {
+
+    sum += (int)buf[6 + j] ;
+  }
+  sum= sum & 0xffff ; 
+ 
+  if( sum != sumbuf)  {
+
+   fprintf(stderr, "DATA SUM NOK: %d !=%d\n",  sum, sumbuf) ;
+   return -1 ;
+  }
+  return 0 ;
+}
+
+int STV_PrintBuffer( unsigned char *buf, int n ) {
+  /* For debugging purposes only */
+  int i ;
+
+  fprintf(stderr, "\nHEADER: %d bytes ", n) ;
+  for(i=0; i < n; i++) {
+
+    if( i==6) {
+      fprintf(stderr, "\nDATA  : ") ;
+    }
+    fprintf(stderr, "%d:0x%2x<>%c<  >>", i, (unsigned char)buf[i], (unsigned char)buf[i]) ;
+    /*STV_PrintBits((unsigned int) buf[i], 8) ; */
+  }
+  fprintf(stderr, "\n") ;
+
+  return 0 ;
+}
+int STV_PrintBufferAsText( unsigned char *buf, int n ) {
+  /* For debugging purposes only */
+  int i ;
+
+  fprintf(stderr, "\nHEADER: %d bytes ", n) ;
+  for(i=0; i < n; i++) {
+
+    if( i==6) {
+      fprintf(stderr, "\nDATA  : ") ;
+    }
+    fprintf(stderr, "%c", (unsigned char)buf[i]) ;
+  }
+  fprintf(stderr, "\n") ;
+
+  return 0 ;
+}
+/* Aggregates a STV command packet */
+
+int STV_SendPacket( int cmd, int *data, int n) {
+
+  char buf[1024];
+ 
+  int j,l ; 
+  int res ;
+  int sum ; /* check sum */
+
+  /* Header section */
+  buf[0] = (unsigned char) 0xa5;	/* start byte */
+  buf[1] = (unsigned char) cmd;	        /* command byte */
+  buf[2] = (unsigned char) 2 * n;	/* data length N (low byte) */
+  buf[3] = (unsigned char) 0x00;	/* data length N (high byte) */
+
+  sum = buf[0] + buf[1] + buf[2] + buf[3]; /* header checksum */
+  buf[4] = (unsigned char) sum % 0x100;    /* header checksum low byte */
+  buf[5] = (unsigned char) (sum / 0x100);  /* header checksum high byte */
+
+  /* DATA section */
+  l= 0 ;
+  if( n > 0) {
+
+    l= 2 ; /* Two bytes per value are sent to STV */
+    for( j=0; j < 2 * n ; j += 2) {
+      buf[6+ j] = (unsigned char) (data[j/2] % 0x100); /* data low byte */
+      buf[7+ j] = (unsigned char) (data[j/2] / 0x100); /* data high byte */
+    }
+
+    sum = 0 ;
+    for( j=0; j < 2 * n ; j++) {
+
+      if((int)buf[6+ j] < 0 ) {
+
+	sum = sum + 0xff+ (int)buf[6+ j] + 1 ;
+
+      } else {
+	
+	sum = sum + (int)buf[6+ j] ;
+      }  
+    }
+    buf[6 + 2 * n ] = (unsigned char) (sum  % 0x10000) ;   /* data checksum (low byte) */
+    buf[7 + 2 * n ] = (unsigned char) (sum  / 0x100) ;     /* data checksum (high byte) */
+  }
+  if(( res= STV_CheckHeaderSum( (unsigned char *) buf)) != 0) { /* Check outgoing packet as well */
+    
+    fprintf(stderr, "STV_SendPacket: corrupt header\n") ;
+
+    if(n > 0) { 
+      if(( res= STV_CheckDataSum( (unsigned char *) buf)) != 0) {
+	fprintf(stderr, "STV_SendPacket: corrupt data\n") ;
+      }
+    }
+  }
+  return STV_portWrite( buf, 8 + l * n ) ;
+}
+
+/* Returns 0 or -1 in case of an error */
+
+int STV_portWrite( char *buf, int nbytes){
+
+  int bytesWritten = 0;   
+
+  /*fprintf( stderr,"w") ; */
+  while (nbytes > 0) {
+    
+    if((bytesWritten = write(fd, buf, nbytes)) == -1) {
+      fprintf(stderr, "STV_portWrite: Error writing at serial port, %s\n", strerror( errno)) ;
+      /* return -1 ; */
+    }
+
+    if (bytesWritten < 0) {
+
+      fprintf( stderr, "STV_portWrite: Error writing\n") ;
+      return -1;
+    } else {
+
+      buf += bytesWritten;
+      nbytes -= bytesWritten;
+    }
+  }
+  return nbytes ;
+}
+
+int STV_CheckAck( unsigned char *buf) {
+  /* Watch out for an ACK, for debugging purposes only */
+  int i ;
+  unsigned char ackseq[]= {0xa5, 0x06, 0x00, 0x00, 0xab, 0x00} ;
+
+  for(i= 0; i < 6; i++ ) {
+
+    if( buf[i] != ackseq[i] ) {
+      return -1 ;
+    }
+  }
+  return 0 ;
+}
+
+unsigned int STV_RecombineInt( unsigned char low_byte, unsigned char high_byte) {
+
+  return (unsigned int) high_byte * (unsigned int)0x100 + (unsigned int)low_byte ;
+}
+
+unsigned int STV_GetBits( unsigned int x, int p, int n){ /* from the C book */
+ 
+  return ( x >> (p+ 1-n)) & ~(~0 << n) ;
+}
+
+void STV_PrintBits( unsigned int x, int n) {
+  /* debugging purposes only */
+  int i ;
+  int res ;
+  fprintf( stderr, "STV_PrintBits:\n") ;
+
+  if( n> 8) {
+
+    fprintf( stderr, "54321098 76543210\n") ;
+
+  } else {
+    fprintf( stderr, "76543210\n") ;
+  }
+
+  for( i= n; i >0 ; i--) {
+
+    if(( i==8) && (n> 8)) {
+      fprintf( stderr, " ") ;
+    }
+    if(( res=STV_GetBits( x, i-1, 1))==0) {
+      fprintf( stderr, "0") ; 
+    } else {
+       fprintf( stderr, "1") ; 
+    }
+  }
+  fprintf( stderr, "\n") ;
+}
+
+double STV_SetCCDTemperature( double set_value) {
+
+  int i ;
+  int res ;
+  int delay= 40000 ;
+  unsigned char buf[1024] ;
+  /* 1st step */
+  res= STV_Interrupt() ; /* Reset Display */
+  tcflush(fd, TCIOFLUSH);
+  usleep( 100000) ;
+  
+  STV_MenueCCDTemperature( delay) ;
+ 
+  for( i=0 ; i< 100  ; i++) { /* Change to the highest temperature */
+    res= STV_LRRotaryIncrease() ;
+    tcflush(fd, TCIOFLUSH);
+    usleep( delay) ;
+  }
+
+  di.ccd_temperature= 25.2 ; /* The actual value is set in STV_ReceivePacket, needed to enter the while() loop */
+  i= 0 ;
+  while( set_value < di.ccd_temperature) {
+
+    /*fprintf( stderr, "STV_SetCCDTemperature %g %g\n", set_value, di.ccd_temperature) ; */
+    res= STV_LRRotaryDecrease() ; /* Lower CCD temperature */
+    /*fprintf(stderr, ":") ; */
+    usleep( 10000) ; 
+    res= STV_TerminateTXDisplay();
+    usleep( 10000) ; 
+    res= STV_TXDisplay(); /* That's the trick, STV sends at least one display */
+    res= STV_ReceivePacket( buf, 0) ; /* discard it */
+    
+    /*STV_PrintBufferAsText( buf, res) ; */
+    if(( res != 62) || ( i++ > 100)) { /* why 56 + 6?, 6 + 48 + 6 */
+      STV_PrintBuffer( buf, res) ;
+      /*STV_PrintBufferAsText( buf, res) ; */
+      return 0.0 ;
+    }
+  }
+  res= STV_Interrupt() ;
+
+  return di.ccd_temperature ;
+}
+
+int STV_MenueCCDTemperature( int delay) {
+
+  int res ;
+
+  res= STV_MenueSetup( delay) ;
+  usleep( delay) ;
+  res= STV_UDRotaryIncrease() ; /* Change to CCD Temperature */
+  /*usleep( delay) ; */
+  tcflush(fd, TCIOFLUSH);
+  return 0 ;
+}
+
+#ifdef HAVE_NOVA_H
+int STV_SetDateTime( char *times) 
+{
+  int i ;
+  int res ;
+  int turn ;
+  struct ln_date utm;
+  int delay= 20000 ;
+  /*fprintf(stderr, "STV_SetTime\n") ; */
+  
+  if((times== NULL) || (( res= strlen(times))==0)) 
+	ln_get_date_from_sys(&utm);
+  else
+   {
+      if( extractISOTime( times, &utm) < 0) 
+      {
+	      fprintf( stderr, "Bad time string %s\n", times) ;
+      	      return -1 ;
+      }
+   }
+  /* Print out the date and time in the standard format. */
+  /*fprintf( stderr, "TIME %s\n", asctime (utc)) ; */
+
+  /* 1st step */
+  res= STV_Interrupt() ; /* Reset Display */
+  usleep( delay) ;
+  tcflush(fd, TCIOFLUSH);
+
+  res= STV_MenueDateTime( delay) ;
+  usleep( delay) ;
+  res= STV_MenueDateTime( delay) ; /* This not an error */
+  usleep( delay) ;
+
+  for( i=0 ; i< 13  ; i++) { /* Reset Month menu to the lef most position */
+    res= STV_LRRotaryDecrease() ; 
+    usleep( delay) ;
+  }
+
+  for( i=0 ; i< utm.months  ; i++) { /* Set Month menu */
+    res= STV_LRRotaryIncrease() ; 
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+  res=  STV_AKey() ; /* Press the Parameter button */
+  usleep( delay) ;
+  tcflush(fd, TCIOFLUSH);
+
+  for( i=0 ; i< 32 ; i++) { /* Reset Day menu to the lef most position */
+    res= STV_LRRotaryDecrease() ; 
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+
+  for( i= 0; i< utm.days-1  ; i++) { /* Set Day menu -1? */
+    res= STV_LRRotaryIncrease() ; 
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+  res=  STV_AKey() ; /* Press the Parameter button */
+  usleep( delay) ;
+  tcflush(fd, TCIOFLUSH);
+
+  for( i=0 ; i< 128  ; i++) { /* Reset Year menu to the lef most position, ATTENTION */
+    res= STV_LRRotaryDecrease() ; 
+    
+    usleep( delay) ; /* sleep a 1/100 second */
+    tcflush(fd, TCIOFLUSH);
+  }
+ 
+  /* JM: Is this how you want not? Please verify the code! */
+  int ymenu = utm.years % 100;
+
+  for( i=0 ; i< ymenu  ; i++) { /* Set Year menu */
+    res= STV_LRRotaryIncrease() ;   
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+  res=  STV_AKey() ; /* Press the Parameter button */
+  usleep( delay) ;
+ tcflush(fd, TCIOFLUSH);
+
+  for( i=0 ; i< 25  ; i++) { /* Reset Hour menu to the lef most position, ATTENTION */
+    res= STV_LRRotaryDecrease() ; 
+    usleep( delay) ; 
+    tcflush(fd, TCIOFLUSH);
+  }
+  for( i=0 ; i< utm.hours ; i++) { /* Set Hour menu */
+    res= STV_LRRotaryIncrease() ; 
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+  res=  STV_AKey() ; /* Press the Parameter button */
+  usleep( delay) ;
+  tcflush(fd, TCIOFLUSH);
+
+  for( i=0 ; i< 61  ; i++) { /* Reset Minute menu to the lef most position, ATTENTION */
+    res= STV_LRRotaryDecrease() ; 
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+  for( i=0 ; i< utm.minutes  ; i++) { /* Set Minute menu */
+    res= STV_LRRotaryIncrease() ; 
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+  res=  STV_AKey() ; /* Press the Parameter button */
+  tcflush(fd, TCIOFLUSH); 
+  for( i=0 ; i< 5  ; i++) { /* Reset Seconds menu to the lef most position, ATTENTION */
+    res= STV_LRRotaryDecrease() ; 
+    usleep( delay) ; 
+    tcflush(fd, TCIOFLUSH);
+  }
+
+  if ( utm.seconds < 15) {
+    turn= 0 ;
+  } else if ( utm.seconds < 30) {
+    turn= 1 ;
+  } else if ( utm.seconds < 45) {
+    turn= 2 ;
+  } else {
+    turn= 3 ;
+  }
+
+  for( i=0 ; i< turn  ; i++) { /* Set Seconds menu, steps of 15 seconds */
+    res= STV_LRRotaryIncrease() ;
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+  res=  STV_AKey() ; /* Press the Parameter button */
+  usleep( delay) ;
+  tcflush(fd, TCIOFLUSH);
+
+  res=  STV_BKey() ; /* Press the Parameter button */
+  usleep( delay) ;
+ tcflush(fd, TCIOFLUSH);
+  res= STV_Interrupt() ;
+  return 0 ;
+}
+#endif
+
+int STV_MenueDateTime( int delay) {
+
+  int i ;
+  int res ;
+
+  res= STV_MenueSetup( delay) ;
+  usleep( delay) ;
+  res=  STV_BKey() ; /* Press the Value button */
+  usleep( delay) ;
+
+  for( i=0 ; i< 8  ; i++) { /* Reset Date menu to the lef most position */
+ 
+   res= STV_UDRotaryDecrease() ; 
+   usleep( delay) ;
+   tcflush(fd, TCIOFLUSH);
+  }
+  return 0 ;
+}
+
+int STV_MenueSetup( int delay) {
+
+  int i ;
+  int res ;
+
+  res= STV_Setup() ;    /* Change to Setup */
+  usleep( delay) ;
+  
+  for( i=0 ; i< 16  ; i++) { /* Reset Setup menu to the lef most position */
+    res= STV_UDRotaryDecrease() ;
+    usleep( delay) ;
+    tcflush(fd, TCIOFLUSH);
+  }
+  return 0 ;
+}
+
+int STV_Connect( char *device, int baud) {
+
+
+  /*fprintf( stderr, "STV_Connect\n") ; */
+  if(( fd= init_serial( device, baud, 8, 0, 1))== -1) {
+    fprintf(stderr, "Error on port %s, %s\n", device, strerror(errno)) ;	
+    return -1 ;
+  }
+
+  return fd ;
+}
+
+/******************************************************************************
+ * shutdown_serial(..)
+ ******************************************************************************
+ * Restores terminal settings of open serial port device and close the file.
+ * Arguments:
+ *   fd: file descriptor of open serial port device.
+ *****************************************************************************/
+void
+shutdown_serial(int fd)
+{
+  if (fd > 0) {
+    if (tcsetattr(fd, TCSANOW, &orig_tty_setting) < 0) {
+      perror("shutdown_serial: can't restore serial device's terminal settings.");
+    }
+    close(fd);
+  }
+}
+/******************************************************************************
+ * init_serial(..)
+ ******************************************************************************
+ * Opens and initializes a serial device and returns it's file descriptor.
+ * Arguments:
+ *   device_name : device name string of the device to open (/dev/ttyS0, ...)
+ *   bit_rate    : bit rate
+ *   word_size   : number of data bits, 7 or 8, USE 8 DATA BITS with modbus
+ *   parity      : 0=no parity, 1=parity EVEN, 2=parity ODD
+ *   stop_bits   : number of stop bits : 1 or 2
+ * Return:
+ *   file descriptor  of successfully opened serial device
+ *   or -1 in case of error.
+ *****************************************************************************/
+int
+init_serial(char *device_name, int bit_rate, int word_size,
+            int parity, int stop_bits)
+{
+  int fd;
+  char *msg;
+
+  /* open serial device */
+  fd = open(device_name, O_RDWR | O_NOCTTY);
+  if (fd < 0) {
+    if (asprintf(&msg, "init_serial: open %s failed", device_name) < 0)
+      perror(NULL);
+    else
+      perror(msg);
+
+    return -1;
+  }
+
+  /* save current tty settings */
+  if (tcgetattr(fd, &orig_tty_setting) < 0) {
+    perror("init_serial: can't get terminal parameters.");
+    return -1;
+  }
+
+
+  /* Control Modes */
+  /* Set bps rate */
+  int bps;
+  switch (bit_rate) {
+    case 0:
+      bps = B0;
+      break;
+    case 50:
+      bps = B50;
+      break;
+    case 75:
+      bps = B75;
+      break;
+    case 110:
+      bps = B110;
+      break;
+    case 134:
+      bps = B134;
+      break;
+    case 150:
+      bps = B150;
+      break;
+    case 200:
+      bps = B200;
+      break;
+    case 300:
+      bps = B300;
+      break;
+    case 600:
+      bps = B600;
+      break;
+    case 1200:
+      bps = B1200;
+      break;
+    case 1800:
+      bps = B1800;
+      break;
+    case 2400:
+      bps = B2400;
+      break;
+    case 4800:
+      bps = B4800;
+      break;
+    case 9600:
+      bps = B9600;
+      break;
+    case 19200:
+      bps = B19200;
+      break;
+    case 38400:
+      bps = B38400;
+      break;
+    case 57600:
+      bps = B57600;
+      break;
+    case 115200:
+      bps = B115200;
+      break;
+    case 230400:
+      bps = B230400;
+      break;
+    default:
+      if (asprintf(&msg, "init_serial: %d is not a valid bit rate.", bit_rate) < 0)
+        perror(NULL);
+      else
+        perror(msg);
+      return -1;
+  }
+  if ((cfsetispeed(&tty_setting, bps) < 0) ||
+      (cfsetospeed(&tty_setting, bps) < 0))
+  {
+    perror("init_serial: failed setting bit rate.");
+    return -1;
+  }
+
+  /* Control Modes */
+  /* set no flow control word size, parity and stop bits. */
+  /* Also don't hangup automatically and ignore modem status. */
+  /* Finally enable receiving characters. */
+  tty_setting.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | HUPCL | CRTSCTS);
+  /*  #ifdef CBAUDEX */
+  /*tty_setting.c_cflag &= ~(CBAUDEX); */
+  /*#endif */
+  /*#ifdef CBAUDEXT */
+  /*tty_setting.c_cflag &= ~(CBAUDEXT); */
+  /*#endif */
+  tty_setting.c_cflag |= (CLOCAL | CREAD);
+
+  /* word size */
+  switch (word_size) {
+    case 5:
+      tty_setting.c_cflag |= CS5;
+      break;
+    case 6:
+      tty_setting.c_cflag |= CS6;
+      break;
+    case 7:
+      tty_setting.c_cflag |= CS7;
+      break;
+    case 8:
+      tty_setting.c_cflag |= CS8;
+      break;
+    default:
+
+      fprintf( stderr, "Default\n") ;
+      if (asprintf(&msg,
+                   "init_serial: %d is not a valid data bit count.",
+                    word_size) < 0)
+        perror(NULL);
+      else
+        perror(msg);
+
+      return -1;
+  }
+
+  /* parity */
+  switch (parity) {
+    case PARITY_NONE:
+      break;
+    case PARITY_EVEN:
+      tty_setting.c_cflag |= PARENB;
+      break;
+    case PARITY_ODD:
+      tty_setting.c_cflag |= PARENB | PARODD;
+      break;
+    default:
+
+   fprintf( stderr, "Default1\n") ;
+      if (asprintf(&msg,
+                   "init_serial: %d is not a valid parity selection value.",
+                    parity) < 0)
+        perror(NULL);
+      else
+        perror(msg);
+
+      return -1;
+  }
+
+  /* stop_bits */
+  switch (stop_bits) {
+    case 1:
+      break;
+    case 2:
+      tty_setting.c_cflag |= CSTOPB;
+      break;
+    default:
+   fprintf( stderr, "Default2\n") ;
+      if (asprintf(&msg,
+                   "init_serial: %d is not a valid stop bit count.",
+                    stop_bits) < 0)
+        perror(NULL);
+      else
+        perror(msg);
+
+      return -1;
+  }
+  /* Control Modes complete */
+
+  /* Ignore bytes with parity errors and make terminal raw and dumb. */
+  tty_setting.c_iflag &= ~(PARMRK | ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON | IXANY);
+  tty_setting.c_iflag |= INPCK | IGNPAR | IGNBRK;
+
+  /* Raw output. */
+  tty_setting.c_oflag &= ~(OPOST | ONLCR);
+
+  /* Local Modes */
+  /* Don't echo characters. Don't generate signals. */
+  /* Don't process any characters. */
+  tty_setting.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN | NOFLSH | TOSTOP);
+  tty_setting.c_lflag |=  NOFLSH;
+
+  /* blocking read until 1 char arrives */
+  tty_setting.c_cc[VMIN]  = 1;
+  tty_setting.c_cc[VTIME] = 0;
+
+  /* now clear input and output buffers and activate the new terminal settings */
+  tcflush(fd, TCIOFLUSH);
+  if (tcsetattr(fd, TCSANOW, &tty_setting)) {
+    perror("init_serial: failed setting attributes on serial port.");
+    shutdown_serial(fd);
+    return -1;
+  }
+  return fd;
+}
Index: /BAORadio/libindi/v1/drivers/video/stvdriver.h
===================================================================
--- /BAORadio/libindi/v1/drivers/video/stvdriver.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/stvdriver.h	(revision 500)
@@ -0,0 +1,188 @@
+#if 0
+    STV driver
+    Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#endif
+
+#define OFF 0 
+#define ON  1 
+
+#define REQUEST_DOWNLOAD              0x00
+#define REQUEST_DOWNLOAD_ALL          0x01
+#define DOWNLOAD_COMPLETE             0x02
+#define REQUEST_BUFFER_STATUS         0x03
+#define REQUEST_IMAGE_INFO            0x04
+#define REQUEST_IMAGE_DATA            0x05
+#define ACK                           0x06
+#define REQUEST_COMPRESSED_IMAGE_DATA 0x07
+#define SEND_KEY_PATTERN              0x08
+#define DISPLAY_ECHO                  0x09
+#define FILE_STATUS                   0x0b
+#define REQUEST_ACK                   0x10
+#define NACK                          0x15
+
+/* Rotary Knob Key Patterns */
+#define LR_ROTARY_DECREASE_PATTERN    0x8000
+#define LR_ROTARY_INCREASE_PATTERN    0x4000
+#define UD_ROTARY_DECREASE_PATTERN    0x2000
+#define UD_ROTARY_INCREASE_PATTERN    0x1000
+#define SHIFT_PATTERN                 0x0008  /* increases rotary speed when 1 */
+
+/* Mode Key Patterns */
+#define CAL_KEY_PATTERN               0x0100
+#define TRACK_KEY_PATTERN             0x0200
+#define DISPLAY_KEY_PATTERN           0x0400
+#define FILEOPS_KEY_PATTERN           0x0800
+#define A_KEY_PATTERN                 0x0010
+#define SETUP_KEY_PATTERN             0x0020
+#define B_KEY_PATTERN                 0x0040
+#define INT_KEY_PATTERN               0x0080
+#define FOCUS_KEY_PATTERN             0x0001
+#define IMAGE_KEY_PATTERN             0x0002
+#define MONITOR_KEY_PATTERN           0x0004
+
+/* The following bit masks have been take from Sbig's documentation */
+#define  ID_BITS_MASK         0x0001 /* mask for no bits*/
+#define  ID_BITS_10           0x0001 /*       image is full 10 bits*/
+#define  ID_BITS_8            0x0000 /*       image from focus, only 8 bits*/
+#define  ID_UNITS_MASK        0x0002 /* mask for units for scope*/
+#define  ID_UNITS_INCHES      0x0002 /*       units were inches*/
+#define  ID_UNITS_CM          0x0000 /*       units were cm*/
+#define  ID_SCOPE_MASK        0x0004 /* mask for telescope type*/
+#define  ID_SCOPE_REFRACTOR   0x0004 /*       scope was refractor*/
+#define  ID_SCOPE_REFLECTOR   0x0000 /*       scope was reflector*/
+#define  ID_DATETIME_MASK     0x0008 /* mask for date/time valid*/
+#define  ID_DATETIME_VALID    0x0008 /*       date/time was set*/
+#define  ID_DATETIME_INVALID  0x0000 /*       date/time was not set*/
+#define  ID_BIN_MASK          0x0030 /* mask for binning mode*/
+#define  ID_BIN_1X1           0x0010 /*       binning was 1x1*/
+#define  ID_BIN_2X2           0x0020 /*       binning was 2x2*/
+#define  ID_BIN_3X3           0x0030 /*       binning was 3x3*/
+#define  ID_PM_MASK           0x0400 /* mask for am/pm in time*/
+#define  ID_PM_PM             0x0400 /*       time was pm, add 12 hours*/
+#define  ID_PM_AM             0x0000 /*       time was am, don;t add 12 hours*/
+#define  ID_FILTER_MASK       0x0800 /* mask for filter status*/
+#define  ID_FILTER_LUNAR      0x0800 /*       lunar filter was used for image*/
+#define  ID_FILTER_NP         0x0000 /*       no filter was used for image*/
+#define  ID_DARKSUB_MASK      0x1000 /* mask for dark subtraction*/
+#define  ID_DARKSUB_YES       0x1000 /*       image was dark subtracted*/
+#define  ID_DARKSUB_NO        0x0000 /*       image was not dark subtracted*/
+#define  ID_MOSAIC_MASK       0x6000 /* mask for mosaic status*/
+#define  ID_MOSAIC_NONE       0x0000 /*       no mosaic, one image per frame*/
+#define  ID_MOSAIC_SMALL      0x2000 /*       small mosaic: 40x40 pixels/image*/
+#define  ID_MOSAIC_LARGE      0x4000 /*       large mosaic: 106x100 pixels/image*/
+
+
+/* IMAGE_INFO - data for the image
+
+   Notes:
+   height     - 0 or 0xFFFF if no data present
+   exposure   - 100-60000 = 1.00 - 600 secs by 0.01
+                60001-60999 = 0.001 - 0.999 secs by 0.001
+   packedDate - bits  6-0  = year - 1999 (0 -127)
+                bits 11-7  = day ( 1-31)
+                bits 15-12 = month (1-12)
+   packedTime - bits  6-0  = seconds (0-59)
+                bits 7-12  = minutes (0-59)
+                bits 15-13 = hours mod 12 (0-11)
+                             + bit in descriptor can add 12
+*/
+
+typedef struct {
+
+  unsigned int descriptor ;    /* set of bits*/
+  unsigned int height, width;  /* image sze */
+  unsigned int top, left ;     /* position in buffer */
+  double       exposure ;      /* exposure time */
+  unsigned int noExposure ;    /* number of exposures added */
+  unsigned int analogGain ;    /*analog gain */
+  int          digitalGain ;   /* digital gain */
+  unsigned int focalLength ;   /*focal length of telescope */
+  unsigned int aperture ;      /* aperture diameter */
+  unsigned int packedDate ;    /* date of image */
+  unsigned int year ;
+  unsigned int month ;
+  unsigned int day ;
+  unsigned int packedTime ;    /* time of image */
+  unsigned int seconds  ;      /* time of image */
+  unsigned int minutes ;       /* time of image */
+  unsigned int hours ;         /* time of image */
+  double       ccdTemp ;       /* temperature of ccd in 1/100 deg C */
+  unsigned int siteID;         /* site id */
+  unsigned int eGain ;         /* eGain in 1/100th e/ADU */
+  unsigned int background ;    /* background for display */
+  unsigned int range ;         /* range for display */
+  unsigned int pedestal ;      /* Track and Accumulate pedestal */
+  unsigned int ccdTop, ccdLeft ; /* position of pixels on CCD array */
+  unsigned int adcResolution ; /* value, 8 or 10 bits */
+  unsigned int units ;         /* 0= cm, 1=inch */
+  unsigned int telescopeType ; /* 0=refractor, 1= reflector */
+  unsigned int dateTimeValid ; /* 0= valid */
+  unsigned int binning ;       /* 1x1=1, 2x2=2, 3x3=3 */ 
+  unsigned int filterStatus ;  /* 0= no filter, 1= lunar filter */
+  unsigned int darkFrameSuntracted ; /* 0= no, 1= yes */
+  unsigned int imageIsMosaic ; /* 0=no, 1=40x40 pixels, 2=106x100 pixels */
+  double       pixelSize ;     /* 7.4 um */
+  double       minValue ;      /* Pixel Contents */
+  double       maxValue ; 
+  
+} IMAGE_INFO ;
+/*
+ * $Id: serial.h 49 2006-08-25 18:07:14Z lukas $
+ *
+ * Copyright (C) 2006, Lukas Zimmermann, Basel, Switzerland.
+ *
+ *
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+   Or visit http://www.gnu.org/licenses/gpl.html.
+*/
+
+#ifndef __serial_h__
+#define __serial_h__
+
+#define PARITY_NONE    0
+#define PARITY_EVEN    1
+#define PARITY_ODD     2
+
+typedef unsigned char byte;         /* define byte type */
+
+/* Restores terminal settings of open serial port device and close the file. */
+void shutdown_serial(int fd);
+
+/* Opens and initializes a serial device and returns it's file descriptor. */
+int init_serial(char *device_name, int bit_rate, int word_size,
+                int parity, int stop_bits);
+
+/* Calculates the 16 bit CRC of an array of bytes and returns it. */
+unsigned int calc_crc(byte byte_array[], int size);
+
+
+#endif          /*#ifndef __serial_h__*/
+
+
Index: /BAORadio/libindi/v1/drivers/video/v4ldriver.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/video/v4ldriver.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/v4ldriver.cpp	(revision 500)
@@ -0,0 +1,839 @@
+#if 0
+    V4L INDI Driver
+    INDI Interface for V4L devices
+    Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include "v4ldriver.h"
+
+V4L_Driver::V4L_Driver()
+{
+  allocateBuffers();
+
+  camNameT[0].text  = NULL; 
+  PortT[0].text     = NULL;
+  IUSaveText(&PortT[0], "/dev/video0");
+
+  divider = 128.;
+}
+
+V4L_Driver::~V4L_Driver()
+{
+  releaseBuffers();
+}
+
+
+void V4L_Driver::initProperties(const char *dev)
+{
+  
+  strncpy(device_name, dev, MAXINDIDEVICE);
+ 
+  /* Connection */
+  IUFillSwitch(&PowerS[0], "CONNECT", "Connect", ISS_OFF);
+  IUFillSwitch(&PowerS[1], "DISCONNECT", "Disconnect", ISS_ON);
+  IUFillSwitchVector(&PowerSP, PowerS, NARRAY(PowerS), dev, "CONNECTION", "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+
+ /* Port */
+  IUFillText(&PortT[0], "PORT", "Port", "/dev/video0");
+  IUFillTextVector(&PortTP, PortT, NARRAY(PortT), dev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE);
+
+ /* Video Stream */
+  IUFillSwitch(&StreamS[0], "ON", "Stream On", ISS_OFF);
+  IUFillSwitch(&StreamS[1], "OFF", "Stream Off", ISS_ON);
+  IUFillSwitchVector(&StreamSP, StreamS, NARRAY(StreamS), dev, "VIDEO_STREAM", "Video Stream", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+
+  /* Compression */
+  IUFillSwitch(&CompressS[0], "ON", "", ISS_ON);
+  IUFillSwitch(&CompressS[1], "OFF", "", ISS_OFF);
+  IUFillSwitchVector(&CompressSP, CompressS, NARRAY(StreamS), dev, "Compression", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+
+  /* Image type */
+  IUFillSwitch(&ImageTypeS[0], "Grey", "", ISS_ON);
+  IUFillSwitch(&ImageTypeS[1], "Color", "", ISS_OFF);
+  IUFillSwitchVector(&ImageTypeSP, ImageTypeS, NARRAY(ImageTypeS), dev, "Image Type", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+
+  /* Camera Name */
+  IUFillText(&camNameT[0], "Model", "", "");
+  IUFillTextVector(&camNameTP, camNameT, NARRAY(camNameT), dev, "Camera Model", "", COMM_GROUP, IP_RO, 0, IPS_IDLE);
+  
+  /* Expose */
+  IUFillNumber(&ExposeTimeN[0], "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., 0.5, 1.);
+  IUFillNumberVector(&ExposeTimeNP, ExposeTimeN, NARRAY(ExposeTimeN), dev, "CCD_EXPOSURE", "Expose", COMM_GROUP, IP_RW, 60, IPS_IDLE);
+
+/* Frame Rate */
+  IUFillNumber(&FrameRateN[0], "RATE", "Rate", "%0.f", 1., 50., 1., 10.);
+  IUFillNumberVector(&FrameRateNP, FrameRateN, NARRAY(FrameRateN), dev, "FRAME_RATE", "Frame Rate", COMM_GROUP, IP_RW, 60, IPS_IDLE);
+
+  /* Frame dimension */
+  IUFillNumber(&FrameN[0], "X", "X", "%.0f", 0., 0., 0., 0.);
+  IUFillNumber(&FrameN[1], "Y", "Y", "%.0f", 0., 0., 0., 0.);
+  IUFillNumber(&FrameN[2], "WIDTH", "Width", "%.0f", 0., 0., 10., 0.);
+  IUFillNumber(&FrameN[3], "HEIGHT", "Height", "%.0f", 0., 0., 10., 0.);
+  IUFillNumberVector(&FrameNP, FrameN, NARRAY(FrameN), dev, "CCD_FRAME", "Frame", IMAGE_GROUP, IP_RW, 60, IPS_IDLE);
+
+  /*IUFillNumber(&ImageSizeN[0], "WIDTH", "Width", "%0.f", 0., 0., 10., 0.);
+  IUFillNumber(&ImageSizeN[1], "HEIGHT", "Height", "%0.f", 0., 0., 10., 0.);
+  IUFillNumberVector(&ImageSizeNP, ImageSizeN, NARRAY(ImageSizeN), dev, "IMAGE_SIZE", "Image Size", IMAGE_GROUP, IP_RW, 60, IPS_IDLE);*/
+  
+  #ifndef HAVE_LINUX_VIDEODEV2_H
+  IUFillNumber(&ImageAdjustN[0], "Contrast", "", "%0.f", 0., 256., 1., 0.);
+  IUFillNumber(&ImageAdjustN[1], "Brightness", "", "%0.f", 0., 256., 1., 0.);
+  IUFillNumber(&ImageAdjustN[2], "Hue", "", "%0.f", 0., 256., 1., 0.);
+  IUFillNumber(&ImageAdjustN[3], "Color", "", "%0.f", 0., 256., 1., 0.);
+  IUFillNumber(&ImageAdjustN[4], "Whiteness", "", "%0.f", 0., 256., 1., 0.);
+  IUFillNumberVector(&ImageAdjustNP, ImageAdjustN, NARRAY(ImageAdjustN), dev, "Image Adjustments", "", IMAGE_GROUP, IP_RW, 60, IPS_IDLE);
+  #else
+  IUFillNumberVector(&ImageAdjustNP, NULL, 0, dev, "Image Adjustments", "", IMAGE_GROUP, IP_RW, 60, IPS_IDLE);
+  #endif 
+
+  // We need to setup the BLOB (Binary Large Object) below. Using this property, we can send FITS to our client
+  strcpy(imageB.name, "CCD1");
+  strcpy(imageB.label, "Feed");
+  strcpy(imageB.format, "");
+  imageB.blob    = 0;
+  imageB.bloblen = 0;
+  imageB.size    = 0;
+  imageB.bvp     = 0;
+  imageB.aux0    = 0;
+  imageB.aux1    = 0;
+  imageB.aux2    = 0;
+  
+  strcpy(imageBP.device, dev);
+  strcpy(imageBP.name, "Video");
+  strcpy(imageBP.label, "Video");
+  strcpy(imageBP.group, COMM_GROUP);
+  strcpy(imageBP.timestamp, "");
+  imageBP.p       = IP_RO;
+  imageBP.timeout = 0;
+  imageBP.s       = IPS_IDLE;
+  imageBP.bp	  = &imageB;
+  imageBP.nbp     = 1;
+  imageBP.aux     = 0;
+
+}
+
+void V4L_Driver::initCamBase()
+{
+   #ifndef HAVE_LINUX_VIDEODEV2_H
+    v4l_base = new V4L1_Base();
+   #else
+    v4l_base = new V4L2_Base();
+   #endif
+}
+
+void V4L_Driver::ISGetProperties (const char *dev)
+{ 
+
+  if (dev && strcmp (device_name, dev))
+    return;
+
+  /* COMM_GROUP */
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefText(&PortTP, NULL);
+  IDDefText(&camNameTP, NULL);
+  IDDefSwitch(&StreamSP, NULL);
+  #ifndef HAVE_LINUX_VIDEODEV2_H
+  IDDefNumber(&FrameRateNP, NULL);
+  #endif
+  IDDefNumber(&ExposeTimeNP, NULL);
+  IDDefBLOB(&imageBP, NULL);
+  
+  /* Image properties */
+  IDDefSwitch(&CompressSP, NULL);
+  IDDefSwitch(&ImageTypeSP, NULL);
+  IDDefNumber(&FrameNP, NULL);
+  
+  #ifndef HAVE_LINUX_VIDEODEV2_H
+  IDDefNumber(&ImageAdjustNP, NULL);
+  #endif
+
+
+  
+}
+ 
+void V4L_Driver::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	char errmsg[ERRMSGSIZ];
+
+	/* ignore if not ours */
+	if (dev && strcmp (device_name, dev))
+	    return;
+	    
+     /* Connection */
+     if (!strcmp (name, PowerSP.name))
+     {
+          IUResetSwitch(&PowerSP);
+	  IUUpdateSwitch(&PowerSP, states, names, n);
+   	  connectCamera();
+	  return;
+     }
+
+     /* Compression */
+     if (!strcmp(name, CompressSP.name))
+     {
+       IUResetSwitch(&CompressSP);
+       IUUpdateSwitch(&CompressSP, states, names, n);
+       CompressSP.s = IPS_OK;
+       
+       IDSetSwitch(&CompressSP, NULL);
+       return;
+     }    
+
+     /* Image Type */
+     if (!strcmp(name, ImageTypeSP.name))
+     {
+       IUResetSwitch(&ImageTypeSP);
+       IUUpdateSwitch(&ImageTypeSP, states, names, n);
+       ImageTypeSP.s = IPS_OK;
+       
+       IDSetSwitch(&ImageTypeSP, NULL);
+       return;
+     }
+     
+     /* Video Stream */
+     if (!strcmp(name, StreamSP.name))
+     {
+     
+      if (checkPowerS(&StreamSP))
+         return;
+       
+       IUResetSwitch(&StreamSP);
+       IUUpdateSwitch(&StreamSP, states, names, n);
+       StreamSP.s = IPS_IDLE;
+       
+          
+       if (StreamS[0].s == ISS_ON)
+       {
+         frameCount = 0;
+         IDLog("Starting the video stream.\n");
+	 StreamSP.s  = IPS_BUSY; 
+	 v4l_base->start_capturing(errmsg);
+       }
+       else
+       {
+         IDLog("The video stream has been disabled. Frame count %d\n", frameCount);
+         v4l_base->stop_capturing(errmsg);
+       }
+       
+       IDSetSwitch(&StreamSP, NULL);
+       return;
+     }
+     
+}
+
+void V4L_Driver::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int /*n*/)
+{
+	IText *tp;
+
+
+       /* ignore if not ours */ 
+       if (dev && strcmp (device_name, dev))
+         return;
+
+	if (!strcmp(name, PortTP.name) )
+	{
+	  PortTP.s = IPS_OK;
+	  tp = IUFindText( &PortTP, names[0] );
+	  if (!tp)
+	   return;
+
+          IUSaveText(tp, texts[0]);
+	  IDSetText (&PortTP, NULL);
+	  return;
+	}
+}
+
+void V4L_Driver::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+      char errmsg[ERRMSGSIZ];
+
+	/* ignore if not ours */
+	if (dev && strcmp (device_name, dev))
+	    return;
+	    
+    
+    /* Frame Size */
+    if (!strcmp (FrameNP.name, name))
+    {
+      if (checkPowerN(&FrameNP))
+        return;
+	
+       int oldW = (int) FrameN[2].value;
+       int oldH = (int) FrameN[3].value;
+
+      FrameNP.s = IPS_OK;
+      
+      if (IUUpdateNumber(&FrameNP, values, names, n) < 0)
+       return;
+      
+      if (v4l_base->setSize( (int) FrameN[2].value, (int) FrameN[3].value) != -1)
+      {
+         FrameN[2].value = v4l_base->getWidth();
+	 FrameN[3].value = v4l_base->getHeight();
+	 V4LFrame->width = (int) FrameN[2].value;
+	 V4LFrame->height= (int) FrameN[3].value;
+         IDSetNumber(&FrameNP, NULL);
+	 return;
+      }
+      else
+      {
+        FrameN[2].value = oldW;
+	FrameN[3].value = oldH;
+        FrameNP.s = IPS_ALERT;
+	IDSetNumber(&FrameNP, "Failed to set a new image size.");
+      }
+      
+      return;
+   }
+
+   #ifndef HAVE_LINUX_VIDEODEV2_H
+   /* Frame rate */
+   if (!strcmp (FrameRateNP.name, name))
+   {
+     if (checkPowerN(&FrameRateNP))
+      return;
+      
+     FrameRateNP.s = IPS_IDLE;
+     
+     if (IUUpdateNumber(&FrameRateNP, values, names, n) < 0)
+       return;
+       
+     v4l_base->setFPS( (int) FrameRateN[0].value );
+     
+     FrameRateNP.s = IPS_OK;
+     IDSetNumber(&FrameRateNP, NULL);
+     return;
+   }
+   #endif
+   
+   
+   if (!strcmp (ImageAdjustNP.name, name))
+   {
+     if (checkPowerN(&ImageAdjustNP))
+       return;
+       
+     ImageAdjustNP.s = IPS_IDLE;
+     
+     if (IUUpdateNumber(&ImageAdjustNP, values, names, n) < 0)
+       return;
+     
+     #ifndef HAVE_LINUX_VIDEODEV2_H
+     v4l_base->setContrast( (int) (ImageAdjustN[0].value * divider));
+     v4l_base->setBrightness( (int) (ImageAdjustN[1].value * divider));
+     v4l_base->setHue( (int) (ImageAdjustN[2].value * divider));
+     v4l_base->setColor( (int) (ImageAdjustN[3].value * divider));
+     v4l_base->setWhiteness( (int) (ImageAdjustN[4].value * divider));
+     
+     ImageAdjustN[0].value = v4l_base->getContrast() / divider;
+     ImageAdjustN[1].value = v4l_base->getBrightness() / divider;
+     ImageAdjustN[2].value = v4l_base->getHue() / divider;
+     ImageAdjustN[3].value = v4l_base->getColor() / divider;
+     ImageAdjustN[4].value = v4l_base->getWhiteness() / divider;
+
+     #else
+     unsigned int ctrl_id;
+     for (int i=0; i < ImageAdjustNP.nnp; i++)
+     {
+         ctrl_id = *((unsigned int *) ImageAdjustNP.np[i].aux0);
+         if (v4l_base->setINTControl( ctrl_id , ImageAdjustNP.np[i].value, errmsg) < 0)
+         {
+            ImageAdjustNP.s = IPS_ALERT;
+            IDSetNumber(&ImageAdjustNP, "Unable to adjust setting. %s", errmsg);
+            return;
+         }
+     }
+     #endif
+     
+     ImageAdjustNP.s = IPS_OK;
+     IDSetNumber(&ImageAdjustNP, NULL);
+     return;
+   }
+   
+   
+    /* Exposure */
+    if (!strcmp (ExposeTimeNP.name, name))
+    {
+       
+       if (checkPowerN(&ExposeTimeNP))
+         return;
+    
+        if (StreamS[0].s == ISS_ON) 
+          v4l_base->stop_capturing(errmsg);
+
+	StreamS[0].s  = ISS_OFF;
+	StreamS[1].s  = ISS_ON;
+	StreamSP.s    = IPS_IDLE;
+	IDSetSwitch(&StreamSP, NULL);
+        
+	V4LFrame->expose = 1000;
+
+        ExposeTimeNP.s   = IPS_BUSY;
+	IDSetNumber(&ExposeTimeNP, NULL);
+
+	time(&capture_start);
+	v4l_base->start_capturing(errmsg);
+	
+        return;
+    } 
+      
+  
+  	
+}
+
+void V4L_Driver::newFrame(void *p)
+{
+  ((V4L_Driver *) (p))->updateFrame();
+}
+
+void V4L_Driver::updateFrame()
+{
+  char errmsg[ERRMSGSIZ];
+  static const unsigned int FRAME_DROP = 2;
+  static int dropLarge = FRAME_DROP;
+
+  if (StreamSP.s == IPS_BUSY)
+  {
+	// Ad hoc way of dropping frames
+	frameCount++;
+        dropLarge--;
+        if (dropLarge == 0)
+        {
+          dropLarge = (int) (((ImageTypeS[0].s == ISS_ON) ? FRAME_DROP : FRAME_DROP*3) * (FrameN[2].value / 160.0));
+	  updateStream();
+          return;
+        }
+  }
+  else if (ExposeTimeNP.s == IPS_BUSY)
+  {
+     V4LFrame->Y      = v4l_base->getY();
+     v4l_base->stop_capturing(errmsg);
+     time(&capture_end);
+     IDLog("Capture of ONE frame took %g seconds.\n", difftime(capture_end, capture_start));
+     grabImage();
+  }
+
+}
+
+void V4L_Driver::updateStream()
+{
+ 
+   int width  = v4l_base->getWidth();
+   int height = v4l_base->getHeight();
+   uLongf compressedBytes = 0;
+   uLong totalBytes;
+   unsigned char *targetFrame;
+   int r;
+   
+   if (PowerS[0].s == ISS_OFF || StreamS[0].s == ISS_OFF) return;
+   
+   if (ImageTypeS[0].s == ISS_ON)
+      V4LFrame->Y      		= v4l_base->getY();
+   else
+      V4LFrame->colorBuffer 	= v4l_base->getColorBuffer();
+  
+   totalBytes  = ImageTypeS[0].s == ISS_ON ? width * height : width * height * 4;
+   targetFrame = ImageTypeS[0].s == ISS_ON ? V4LFrame->Y : V4LFrame->colorBuffer;
+
+   /* Do we want to compress ? */
+    if (CompressS[0].s == ISS_ON)
+    {   
+   	/* Compress frame */
+   	V4LFrame->compressedFrame = (unsigned char *) realloc (V4LFrame->compressedFrame, sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
+   
+   	compressedBytes = sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3;
+   
+   	r = compress2(V4LFrame->compressedFrame, &compressedBytes, targetFrame, totalBytes, 4);
+   	if (r != Z_OK)
+   	{
+	 	/* this should NEVER happen */
+	 	IDLog("internal error - compression failed: %d\n", r);
+		return;
+   	}
+   
+   	/* #3.A Send it compressed */
+   	imageB.blob = V4LFrame->compressedFrame;
+   	imageB.bloblen = compressedBytes;
+   	imageB.size = totalBytes;
+   	strcpy(imageB.format, ".stream.z");
+     }
+     else
+     {
+       /* #3.B Send it uncompressed */
+        imageB.blob = targetFrame;
+   	imageB.bloblen = totalBytes;
+   	imageB.size = totalBytes;
+   	strcpy(imageB.format, ".stream");
+     }
+        
+   imageBP.s = IPS_OK;
+   IDSetBLOB (&imageBP, NULL);
+   
+   #ifndef HAVE_LINUX_VIDEODEV2_H
+      char errmsg[ERRMSGSIZ];
+      v4l_base->start_capturing(errmsg);
+   #endif
+}
+
+/* Downloads the image from the CCD row by row and store them
+   in a raw file.
+ N.B. No processing is done on the image */
+int V4L_Driver::grabImage()
+{
+   int err, fd;
+   char errmsg[ERRMSG_SIZE];
+   char temp_filename[TEMPFILE_LEN] = "/tmp/fitsXXXXXX";
+   
+   
+   if ((fd = mkstemp(temp_filename)) < 0)
+   { 
+    IDMessage(device_name, "Error making temporary filename.");
+    IDLog("Error making temporary filename.\n");
+    return -1;
+   }
+   close(fd);
+  
+   
+   err = writeFITS(temp_filename, errmsg);
+   if (err)
+   {
+       IDMessage(device_name, errmsg, NULL);
+       return -1;
+   }
+   
+  return 0;
+}
+
+int V4L_Driver::writeFITS(const char * filename, char errmsg[])
+{
+    fitsfile *fptr;       /* pointer to the FITS file; defined in fitsio.h */
+    int status;
+    long  fpixel = 1, naxis = 2, nelements;
+    long naxes[2];
+    char filename_rw[TEMPFILE_LEN+1];
+
+    INDI_UNUSED(errmsg);
+
+    // Append ! to file name to over write it.
+    snprintf(filename_rw, TEMPFILE_LEN+1, "!%s", filename);
+
+    naxes[0] = v4l_base->getWidth();
+    naxes[1] = v4l_base->getHeight();
+
+    status = 0;         /* initialize status before calling fitsio routines */
+    fits_create_file(&fptr, filename_rw, &status);   /* create new file */
+
+    /* Create the primary array image (16-bit short integer pixels */
+    fits_create_img(fptr, BYTE_IMG, naxis, naxes, &status);
+
+    addFITSKeywords(fptr);
+
+    nelements = naxes[0] * naxes[1];          /* number of pixels to write */
+
+    /* Write the array of integers to the image */
+    fits_write_img(fptr, TBYTE, fpixel, nelements, V4LFrame->Y, &status);
+
+    fits_close_file(fptr, &status);            /* close the file */
+
+    fits_report_error(stderr, status);  /* print out any error messages */
+
+    /* Success */
+    ExposeTimeNP.s = IPS_OK;
+    IDSetNumber(&ExposeTimeNP, NULL);
+    uploadFile(filename);
+    unlink(filename);
+
+    return status;
+}
+
+void V4L_Driver::addFITSKeywords(fitsfile *fptr)
+{
+  int status=0; 
+
+ fits_update_key(fptr, TLONG, "EXPOSURE", &(V4LFrame->expose), "Total Exposure Time (ms)", &status); 
+ fits_update_key(fptr, TSTRING, "INSTRUME", v4l_base->getDeviceName(), "Webcam Name", &status);
+ fits_write_date(fptr, &status);
+}
+
+void V4L_Driver::uploadFile(const char * filename)
+{
+   
+   FILE * fitsFile;
+   int r=0;
+   unsigned int nr = 0;
+   uLong  totalBytes;
+   uLongf compressedBytes = 0;
+   struct stat stat_p; 
+ 
+   if ( -1 ==  stat (filename, &stat_p))
+   { 
+     IDLog(" Error occurred attempting to stat %s\n", filename); 
+     return; 
+   }
+   
+   totalBytes = stat_p.st_size;
+
+   fitsFile = fopen(filename, "r");
+   
+   if (fitsFile == NULL)
+    return;
+   
+   fitsData = (fitsData == NULL) ? (unsigned char *) malloc(sizeof(unsigned char) * totalBytes) :
+				   (unsigned char *) realloc(fitsData, sizeof(unsigned char) * totalBytes);
+   /* #1 Read file from disk */ 
+   for (unsigned int i=0; i < totalBytes; i+= nr)
+   {
+      nr = fread(fitsData + i, 1, totalBytes - i, fitsFile);
+     
+     if (nr <= 0)
+     {
+        IDLog("Error reading temporary FITS file.\n");
+        return;
+     }
+   }
+   fclose(fitsFile);
+   
+   if (CompressS[0].s == ISS_ON)
+   {   
+   /* #2 Compress it */
+   V4LFrame->compressedFrame = (unsigned char *) realloc (V4LFrame->compressedFrame, sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
+   
+    compressedBytes = sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3;
+     
+     
+   r = compress2(V4LFrame->compressedFrame, &compressedBytes, fitsData, totalBytes, 9);
+   if (r != Z_OK)
+   {
+ 	/* this should NEVER happen */
+ 	IDLog("internal error - compression failed: %d\n", r);
+	return;
+   }
+
+   /* #3.A Send it compressed */
+   imageB.blob = V4LFrame->compressedFrame;
+   imageB.bloblen = compressedBytes;
+   imageB.size = totalBytes;
+   strcpy(imageB.format, ".fits.z");
+   }
+   else
+   {
+     imageB.blob = fitsData;
+     imageB.bloblen = totalBytes;
+     imageB.size = totalBytes;
+     strcpy(imageB.format, ".fits");
+   }
+   
+   imageBP.s = IPS_OK;
+   IDSetBLOB (&imageBP, NULL);
+   
+} 
+
+void V4L_Driver::connectCamera()
+{
+  char errmsg[ERRMSGSIZ];
+  
+    
+  switch (PowerS[0].s)
+  {
+     case ISS_ON:
+      if (v4l_base->connectCam(PortT[0].text, errmsg) < 0)
+      {
+	  PowerSP.s = IPS_IDLE;
+	  PowerS[0].s = ISS_OFF;
+	  PowerS[1].s = ISS_ON;
+	  IDSetSwitch(&PowerSP, "Error: unable to open device");
+	  IDLog("Error: %s\n", errmsg);
+	  return;
+      }
+      
+      /* Sucess! */
+      PowerS[0].s = ISS_ON;
+      PowerS[1].s = ISS_OFF;
+      PowerSP.s = IPS_OK;
+      IDSetSwitch(&PowerSP, "Video4Linux Generic Device is online. Retrieving basic data.");
+
+      v4l_base->registerCallback(newFrame, this);
+      
+      IDLog("V4L Device is online. Retrieving basic data.\n");
+      getBasicData();
+      
+      break;
+      
+    case ISS_OFF:
+      PowerS[0].s = ISS_OFF;
+      PowerS[1].s = ISS_ON;
+      PowerSP.s = IPS_IDLE;
+      
+      v4l_base->disconnectCam();
+      
+      IDSetSwitch(&PowerSP, "Video4Linux Generic Device is offline.");
+      
+      break;
+     }
+}
+
+/* Retrieves basic data from the device upon connection.*/
+void V4L_Driver::getBasicData()
+{
+
+  int xmax, ymax, xmin, ymin;
+  
+  v4l_base->getMaxMinSize(xmax, ymax, xmin, ymin);
+
+  /* Width */
+  FrameN[2].value = v4l_base->getWidth();
+  FrameN[2].min = xmin;
+  FrameN[2].max = xmax;
+  V4LFrame->width = (int) FrameN[2].value;
+  
+  /* Height */
+  FrameN[3].value = v4l_base->getHeight();
+  FrameN[3].min = ymin;
+  FrameN[3].max = ymax;
+  V4LFrame->height = (int) FrameN[3].value;
+  
+  IUUpdateMinMax(&FrameNP);
+  IDSetNumber(&FrameNP, NULL);
+  
+  IUSaveText(&camNameT[0], v4l_base->getDeviceName());
+  IDSetText(&camNameTP, NULL);
+
+   #ifndef HAVE_LINUX_VIDEODEV2_H
+     updateV4L1Controls();
+   #else
+    updateV4L2Controls();
+   #endif
+   
+}
+
+#ifdef HAVE_LINUX_VIDEODEV2_H
+void V4L_Driver::updateV4L2Controls()
+{
+    // #1 Query for INTEGER controls, and fill up the structure
+      free(ImageAdjustNP.np);
+      ImageAdjustNP.nnp = 0;
+      
+   if (v4l_base->queryINTControls(&ImageAdjustNP) > 0)
+      IDDefNumber(&ImageAdjustNP, NULL);
+}
+#else
+void V4L_Driver::updateV4L1Controls()
+{
+
+  if ( (v4l_base->getContrast() / divider) > ImageAdjustN[0].max)
+      divider *=2;
+
+  if ( (v4l_base->getHue() / divider) > ImageAdjustN[2].max)
+      divider *=2;
+
+  ImageAdjustN[0].value = v4l_base->getContrast() / divider;
+  ImageAdjustN[1].value = v4l_base->getBrightness() / divider;
+  ImageAdjustN[2].value = v4l_base->getHue() / divider;
+  ImageAdjustN[3].value = v4l_base->getColor() / divider;
+  ImageAdjustN[4].value = v4l_base->getWhiteness() / divider;
+
+  ImageAdjustNP.s = IPS_OK;
+  IDSetNumber(&ImageAdjustNP, NULL);
+  
+}
+#endif
+
+int V4L_Driver::checkPowerS(ISwitchVectorProperty *sp)
+{
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(sp->label, ""))
+        IDMessage (device_name, "Cannot change property %s while the camera is offline.", sp->name);
+    else
+        IDMessage (device_name, "Cannot change property %s while the camera is offline.", sp->label);
+    
+    sp->s = IPS_IDLE;
+    IDSetSwitch(sp, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int V4L_Driver::checkPowerN(INumberVectorProperty *np)
+{
+   
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(np->label, ""))
+        IDMessage (device_name, "Cannot change property %s while the camera is offline.", np->name);
+    else
+        IDMessage (device_name, "Cannot change property %s while the camera is offline.", np->label);
+	
+    np->s = IPS_IDLE;
+    IDSetNumber(np, NULL);
+    return -1;
+  }
+
+  return 0;
+}
+
+int V4L_Driver::checkPowerT(ITextVectorProperty *tp)
+{
+
+  if (PowerSP.s != IPS_OK)
+  {
+    if (!strcmp(tp->label, ""))
+        IDMessage (device_name, "Cannot change property %s while the camera is offline.", tp->name);
+    else
+        IDMessage (device_name, "Cannot change property %s while the camera is offline.", tp->label);
+	
+    tp->s = IPS_IDLE;
+    IDSetText(tp, NULL);
+    return -1;
+  }
+
+  return 0;
+
+}
+
+void V4L_Driver::allocateBuffers()
+{
+     V4LFrame = (img_t *) malloc (sizeof(img_t));
+ 
+     if (V4LFrame == NULL)
+     {
+       IDMessage(NULL, "Error: unable to initialize driver. Low memory.");
+       IDLog("Error: unable to initialize driver. Low memory.");
+       exit(-1);
+     }
+
+     fitsData			= (unsigned char *) malloc (sizeof(unsigned char) * 1);
+     V4LFrame->Y                = (unsigned char *) malloc (sizeof(unsigned char) * 1);
+     V4LFrame->U                = (unsigned char *) malloc (sizeof(unsigned char) * 1);
+     V4LFrame->V                = (unsigned char *) malloc (sizeof(unsigned char) * 1);
+     V4LFrame->colorBuffer      = (unsigned char *) malloc (sizeof(unsigned char) * 1);
+     V4LFrame->compressedFrame  = (unsigned char *) malloc (sizeof(unsigned char) * 1);
+}
+
+void V4L_Driver::releaseBuffers()
+{
+  free(fitsData);
+  free(V4LFrame->Y);
+  free(V4LFrame->U);
+  free(V4LFrame->V);
+  free(V4LFrame->colorBuffer);
+  free(V4LFrame->compressedFrame);
+  free (V4LFrame);
+}
+
+
Index: /BAORadio/libindi/v1/drivers/video/v4ldriver.h
===================================================================
--- /BAORadio/libindi/v1/drivers/video/v4ldriver.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/v4ldriver.h	(revision 500)
@@ -0,0 +1,177 @@
+#if 0
+    V4L INDI Driver
+    INDI Interface for V4L devices
+    Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#ifndef V4L_DRIVER_H
+#define V4L_DRIVER_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <zlib.h>
+#include <asm/types.h>
+
+#include "indidevapi.h"
+#include "indicom.h"
+#include <fitsio.h>
+#include "eventloop.h"
+
+#include <config.h>
+
+#ifdef HAVE_LINUX_VIDEODEV2_H
+#include "webcam/v4l2_base.h"
+#else
+#include "webcam/v4l1_base.h"
+#endif 
+
+#define COMM_GROUP	"Main Control"
+#define IMAGE_CONTROL   "Image Control"
+#define IMAGE_GROUP	"Image Settings"
+
+#define MAX_PIXELS	4096		/* Max number of pixels in one dimension */
+#define ERRMSGSIZ	1024
+
+#define TEMPFILE_LEN	16
+
+
+class V4L_Driver
+{
+  public:
+    V4L_Driver();
+    virtual ~V4L_Driver();
+
+    /* INDI Functions that must be called from indidrivermain */
+    virtual void ISGetProperties (const char *dev);
+    virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+    virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+    virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+
+    virtual void initCamBase();
+    virtual void initProperties(const char *dev);
+
+    static void newFrame(void *p);
+    void updateFrame();
+
+   protected:
+
+   /* Structs */
+   typedef struct {
+	int  width;
+	int  height;
+	int  expose;
+	unsigned char  *Y;
+	unsigned char  *U;
+	unsigned char  *V;
+	unsigned char  *colorBuffer;
+	unsigned char  *compressedFrame;
+	} img_t;
+
+
+   /* Switches */
+    ISwitch PowerS[2];
+    ISwitch StreamS[2];
+    ISwitch CompressS[2];
+    ISwitch ImageTypeS[2];
+    
+    /* Texts */
+    IText PortT[1];
+    IText camNameT[1];
+
+    /* Numbers */
+    INumber ExposeTimeN[1];
+    INumber FrameRateN[1];
+    INumber FrameN[4];
+    #ifndef HAVE_LINUX_VIDEODEV2_H
+    INumber ImageAdjustN[5];
+    #endif
+    
+    /* BLOBs */
+    IBLOB imageB;
+    
+    /* Switch vectors */
+    ISwitchVectorProperty PowerSP;				/* Connection switch */
+    ISwitchVectorProperty StreamSP;				/* Stream switch */
+    ISwitchVectorProperty CompressSP;				/* Compress stream switch */
+    ISwitchVectorProperty ImageTypeSP;				/* Color or grey switch */
+
+    /* Number vectors */
+    INumberVectorProperty ExposeTimeNP;				/* Exposure */
+    INumberVectorProperty FrameRateNP;				/* Frame rate */
+    INumberVectorProperty FrameNP;				/* Stream dimenstion */
+    INumberVectorProperty ImageAdjustNP;			/* Image controls */
+
+    /* Text vectors */
+    ITextVectorProperty PortTP;
+    ITextVectorProperty camNameTP;
+    
+    /* BLOB vectors */
+    IBLOBVectorProperty imageBP;				/* Data stream */
+
+   /* Initilization functions */
+   virtual void connectCamera(void);
+   virtual void getBasicData(void);
+
+   /* Stream/FITS functions */
+   void updateStream();
+   void uploadFile(const char * filename);
+   int  writeFITS(const char *filename, char errmsg[]);
+   int  grabImage(void);
+   void addFITSKeywords(fitsfile *fptr);
+   void allocateBuffers();
+   void releaseBuffers();
+
+   /* Helper functions */
+   int  checkPowerN(INumberVectorProperty *np);
+   int  checkPowerS(ISwitchVectorProperty *sp);
+   int  checkPowerT(ITextVectorProperty *tp);
+
+   #ifndef HAVE_LINUX_VIDEODEV2_H
+   virtual void updateV4L1Controls();
+   V4L1_Base *v4l_base;
+   #else
+   virtual void updateV4L2Controls();
+   V4L2_Base *v4l_base;
+   #endif
+
+   char device_name[MAXINDIDEVICE];
+   unsigned char *fitsData;		/* Buffer to hold the FITS file */
+   int frameCount;			/* For debugging */
+   double divider;			/* For limits */
+   img_t * V4LFrame;			/* Video frame */
+
+   time_t capture_start;		/* To calculate how long a frame take */
+   time_t capture_end;
+
+};
+   
+#endif
Index: /BAORadio/libindi/v1/drivers/video/v4lphilips.cpp
===================================================================
--- /BAORadio/libindi/v1/drivers/video/v4lphilips.cpp	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/v4lphilips.cpp	(revision 500)
@@ -0,0 +1,667 @@
+/*
+    Phlips webcam INDI driver
+    Copyright (C) 2003-2005 by Jasem Mutlaq
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    2005.04.29  JM: There is no need for this file for Video 4 Linux 2. It is kept for V4L 1 compatibility.
+
+*/
+
+#include "v4lphilips.h"
+#include "webcam/pwc-ioctl.h"
+
+V4L_Philips::V4L_Philips() : V4L_Driver()
+{
+
+}
+
+V4L_Philips::~V4L_Philips()
+{
+
+}
+
+void V4L_Philips::initCamBase()
+{
+   #ifdef HAVE_LINUX_VIDEODEV2_H
+    v4l_base = new V4L2_Base();
+   #else
+    v4l_pwc = new V4L1_PWC();
+    v4l_base = (V4L1_Base *) v4l_pwc;
+   #endif
+}
+
+void V4L_Philips::initProperties(const char *dev)
+{
+
+  // Call parent
+  V4L_Driver::initProperties(dev);
+
+  IUFillSwitch(&BackLightS[0], "ON", "", ISS_OFF);
+  IUFillSwitch(&BackLightS[1], "OFF", "", ISS_ON);
+  IUFillSwitchVector(&BackLightSP, BackLightS, NARRAY(BackLightS), dev, "Back Light", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0 , IPS_IDLE);
+
+  IUFillSwitch(&AntiFlickerS[0], "ON", "", ISS_OFF);
+  IUFillSwitch(&AntiFlickerS[1], "OFF", "", ISS_ON);
+  IUFillSwitchVector(&AntiFlickerSP, AntiFlickerS, NARRAY(AntiFlickerS), dev, "Anti Flicker", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0 , IPS_IDLE);
+
+  IUFillSwitch(&NoiseReductionS[0], "None", "", ISS_ON);
+  IUFillSwitch(&NoiseReductionS[1], "Low", "", ISS_OFF);
+  IUFillSwitch(&NoiseReductionS[2], "Medium", "", ISS_OFF);
+  IUFillSwitch(&NoiseReductionS[3], "High", "", ISS_OFF);
+  IUFillSwitchVector(&NoiseReductionSP, NoiseReductionS, NARRAY(NoiseReductionS), dev, "Noise Reduction", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+
+  IUFillSwitch(&CamSettingS[0], "Save", "", ISS_OFF);
+  IUFillSwitch(&CamSettingS[1], "Restore", "", ISS_OFF);
+  IUFillSwitch(&CamSettingS[2], "Factory", "", ISS_OFF);
+  IUFillSwitchVector(&CamSettingSP, CamSettingS, NARRAY(CamSettingS), dev, "Settings", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+
+  IUFillSwitch(&WhiteBalanceModeS[0], "Auto" , "", ISS_ON);
+  IUFillSwitch(&WhiteBalanceModeS[1], "Manual" , "", ISS_OFF);
+  IUFillSwitch(&WhiteBalanceModeS[2], "Indoor" , "", ISS_OFF);
+  IUFillSwitch(&WhiteBalanceModeS[3], "Outdoor" , "", ISS_OFF);
+  IUFillSwitch(&WhiteBalanceModeS[4], "Fluorescent" , "", ISS_OFF);
+  
+  IUFillSwitchVector(&WhiteBalanceModeSP, WhiteBalanceModeS, NARRAY(WhiteBalanceModeS), dev, "White Balance Mode", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+
+  IUFillNumber(&WhiteBalanceN[0], "Manual Red", "", "%0.f", 0., 256., 1., 0.);
+  IUFillNumber(&WhiteBalanceN[1], "Manual Blue", "", "%0.f", 0., 256., 1., 0.);
+  IUFillNumberVector(&WhiteBalanceNP, WhiteBalanceN, NARRAY(WhiteBalanceN), dev, "White Balance", "", IMAGE_CONTROL, IP_RW, 60, IPS_IDLE);
+
+  IUFillNumber(&ShutterSpeedN[0], "Speed", "", "%0.f", 0., 65535., 100., 0.);
+  IUFillNumberVector(&ShutterSpeedNP, ShutterSpeedN, NARRAY(ShutterSpeedN), dev, "Shutter Speed", "", COMM_GROUP, IP_RW, 60, IPS_IDLE);
+
+}
+
+void V4L_Philips::ISGetProperties (const char *dev)
+{
+
+  if (dev && strcmp (device_name, dev))
+    return;
+    
+   #ifdef HAVE_LINUX_VIDEODEV2_H
+    V4L_Driver::ISGetProperties(dev);
+    return;
+   #endif
+
+  /* COMM_GROUP */
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefText(&PortTP, NULL);
+  IDDefText(&camNameTP, NULL);
+  IDDefSwitch(&StreamSP, NULL);
+  IDDefNumber(&FrameRateNP, NULL);
+  IDDefNumber(&ExposeTimeNP, NULL);
+  IDDefNumber(&ShutterSpeedNP, NULL);
+  IDDefBLOB(&imageBP, NULL);
+  
+  /* Image Groups */
+  IDDefSwitch(&CompressSP, NULL);
+  IDDefSwitch(&ImageTypeSP, NULL);
+  IDDefNumber(&FrameNP, NULL);
+  IDDefNumber(&ImageAdjustNP, NULL);
+  
+  /* Image Control */
+  IDDefSwitch(&WhiteBalanceModeSP, NULL);
+  IDDefNumber(&WhiteBalanceNP, NULL);
+  IDDefSwitch(&BackLightSP, NULL);
+  IDDefSwitch(&AntiFlickerSP, NULL);
+  IDDefSwitch(&NoiseReductionSP, NULL);
+  IDDefSwitch(&CamSettingSP, NULL);
+
+}
+
+void V4L_Philips::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	/* ignore if not ours */
+     if (dev && strcmp (device_name, dev))
+	 return;
+
+     /* Connection */
+     if (!strcmp (name, PowerSP.name))
+     {
+          IUResetSwitch(&PowerSP);
+	  IUUpdateSwitch(&PowerSP, states, names, n);
+   	  connectCamera();
+	  return;
+     }
+    
+
+     #ifndef HAVE_LINUX_VIDEODEV2_H
+    /* Anti Flicker control */
+    if (!strcmp (AntiFlickerSP.name, name))
+    {
+       if (checkPowerS(&AntiFlickerSP))
+         return;
+	 
+       AntiFlickerSP.s = IPS_IDLE;
+       
+       IUResetSwitch(&AntiFlickerSP);
+       IUUpdateSwitch(&AntiFlickerSP, states, names, n);
+       
+       if (AntiFlickerS[0].s == ISS_ON)
+       {
+         if (v4l_pwc->setFlicker(true, errmsg) < 0)
+	 {
+	   AntiFlickerS[0].s = ISS_OFF;
+	   AntiFlickerS[1].s = ISS_ON;
+	   IDSetSwitch(&AntiFlickerSP, "%s", errmsg);
+	   return;
+	 }
+	 
+	 AntiFlickerSP.s = IPS_OK;
+	 IDSetSwitch(&AntiFlickerSP, NULL);
+       }
+       else
+       {
+         if (v4l_pwc->setFlicker(false, errmsg) < 0)
+	 {
+	   AntiFlickerS[0].s = ISS_ON;
+	   AntiFlickerS[1].s = ISS_OFF;
+	   IDSetSwitch(&AntiFlickerSP, "%s", errmsg);
+	   return;
+	 }
+	 
+	 IDSetSwitch(&AntiFlickerSP, NULL);
+       }
+       
+       return;
+    }
+    
+    /* Back light compensation */
+    if (!strcmp (BackLightSP.name, name))
+    {
+       if (checkPowerS(&BackLightSP))
+         return;
+	 
+       BackLightSP.s = IPS_IDLE;
+       
+       IUResetSwitch(&BackLightSP);
+       IUUpdateSwitch(&BackLightSP, states, names, n);
+       
+       if (BackLightS[0].s == ISS_ON)
+       {
+         if (v4l_pwc->setBackLight(true, errmsg) < 0)
+	 {
+	   BackLightS[0].s = ISS_OFF;
+	   BackLightS[1].s = ISS_ON;
+	   IDSetSwitch(&BackLightSP, "%s", errmsg);
+	   return;
+	 }
+	 
+	 BackLightSP.s = IPS_OK;
+	 IDSetSwitch(&BackLightSP, NULL);
+       }
+       else
+       {
+         if (v4l_pwc->setBackLight(false, errmsg) < 0)
+	 {
+	   BackLightS[0].s = ISS_ON;
+	   BackLightS[1].s = ISS_OFF;
+	   IDSetSwitch(&BackLightSP, "%s", errmsg);
+	   return;
+	 }
+	 
+	 IDSetSwitch(&BackLightSP, NULL);
+       }
+       
+       return;
+    }
+	 
+    /* Noise reduction control */
+    if (!strcmp (NoiseReductionSP.name, name))
+    {
+       if (checkPowerS(&NoiseReductionSP))
+         return;
+	 
+       NoiseReductionSP.s = IPS_IDLE;
+       
+       IUResetSwitch(&NoiseReductionSP);
+       IUUpdateSwitch(&NoiseReductionSP, states, names, n);
+       
+       for (int i=0; i < 4; i++)
+        if (NoiseReductionS[i].s == ISS_ON)
+	{
+	   index = i;
+	   break;
+	}
+	
+       if (v4l_pwc->setNoiseRemoval(index, errmsg) < 0)
+       {
+         IUResetSwitch(&NoiseReductionSP);
+	 NoiseReductionS[0].s = ISS_ON;
+	 IDSetSwitch(&NoiseReductionSP, "%s", errmsg);
+	 return;
+       }
+       
+       NoiseReductionSP.s = IPS_OK;
+       
+       IDSetSwitch(&NoiseReductionSP, NULL);
+       return;
+    }
+    
+    /* White balace mode */
+    if (!strcmp (WhiteBalanceModeSP.name, name))
+    {
+       if (checkPowerS(&WhiteBalanceModeSP))
+         return;
+	 
+       WhiteBalanceModeSP.s = IPS_IDLE;
+       
+       IUResetSwitch(&WhiteBalanceModeSP);
+       IUUpdateSwitch(&WhiteBalanceModeSP, states, names, n);
+       
+       for (int i=0; i < 5; i++)
+        if (WhiteBalanceModeS[i].s == ISS_ON)
+	{
+	   index = i;
+	   break;
+	}
+	
+	switch (index)
+	{
+	  // Auto
+	  case 0:
+	   if (v4l_pwc->setWhiteBalanceMode(PWC_WB_AUTO, errmsg) < 0)
+	   {
+	     IUResetSwitch(&WhiteBalanceModeSP),
+	     WhiteBalanceModeS[0].s = ISS_ON;
+	     IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg);
+	     return;
+	   }
+	   break;
+	   
+	 // Manual
+	 case 1:
+	  if (v4l_pwc->setWhiteBalanceMode(PWC_WB_MANUAL, errmsg) < 0)
+	   {
+	     IUResetSwitch(&WhiteBalanceModeSP),
+	     WhiteBalanceModeS[0].s = ISS_ON;
+	     IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg);
+	     return;
+	   }
+	   break;
+	   
+	 // Indoor
+	 case 2:
+	  if (v4l_pwc->setWhiteBalanceMode(PWC_WB_INDOOR, errmsg) < 0)
+	   {
+	     IUResetSwitch(&WhiteBalanceModeSP),
+	     WhiteBalanceModeS[0].s = ISS_ON;
+	     IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg);
+	     return;
+	   }
+	   break;
+	   
+	 // Outdoor
+	 case 3:
+	  if (v4l_pwc->setWhiteBalanceMode(PWC_WB_OUTDOOR, errmsg) < 0)
+	   {
+	     IUResetSwitch(&WhiteBalanceModeSP),
+	     WhiteBalanceModeS[0].s = ISS_ON;
+	     IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg);
+	     return;
+	   }
+	   break;
+	   
+	 // Flurescent
+	 case 4:
+	  if (v4l_pwc->setWhiteBalanceMode(PWC_WB_FL, errmsg) < 0)
+	   {
+	     IUResetSwitch(&WhiteBalanceModeSP),
+	     WhiteBalanceModeS[0].s = ISS_ON;
+	     IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg);
+	     return;
+	   }
+	   break;
+	   
+	}
+	     
+	WhiteBalanceModeSP.s = IPS_OK;
+	IDSetSwitch(&WhiteBalanceModeSP, NULL);
+	return;
+	
+     }
+	
+    /* Camera setttings */
+    if (!strcmp (CamSettingSP.name, name))
+    {
+       
+       if (checkPowerS(&CamSettingSP))
+         return;
+    
+	CamSettingSP.s = IPS_IDLE;
+	
+	IUResetSwitch(&CamSettingSP);
+	IUUpdateSwitch(&CamSettingSP, states, names, n);
+	
+	if (CamSettingS[0].s == ISS_ON)
+	{
+	  if (v4l_pwc->saveSettings(errmsg) < 0)
+	  {
+	    IUResetSwitch(&CamSettingSP);
+	    IDSetSwitch(&CamSettingSP, "%s", errmsg);
+	    return;
+	  }
+	  
+	  CamSettingSP.s = IPS_OK;
+	  IDSetSwitch(&CamSettingSP, "Settings saved.");
+	  return;
+	}
+	
+	if (CamSettingS[1].s == ISS_ON)
+	{
+	   v4l_pwc->restoreSettings();
+	   IUResetSwitch(&CamSettingSP);
+	   CamSettingSP.s = IPS_OK;
+	   IDSetSwitch(&CamSettingSP, "Settings restored.");
+           updateV4L1Controls();
+	   return;
+	}
+	
+	if (CamSettingS[2].s == ISS_ON)
+	{
+	  v4l_pwc->restoreFactorySettings();
+	  IUResetSwitch(&CamSettingSP);
+	  CamSettingSP.s = IPS_OK;
+	  IDSetSwitch(&CamSettingSP, "Factory settings restored.");
+          updateV4L1Controls();
+	  return;
+	}
+     }
+     #endif
+
+     // Call parent
+     V4L_Driver::ISNewSwitch(dev, name, states, names, n);
+        
+     
+
+}
+
+void V4L_Philips::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+   
+     V4L_Driver::ISNewText(dev, name, texts, names, n);
+
+}
+
+void V4L_Philips::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+
+    // Nothing for V4L 2 to do here
+    #ifndef HAVE_LINUX_VIDEODEV2_H
+    char errmsg[ERRMSGSIZ];
+
+    /* Frame rate */
+   if (!strcmp (FrameRateNP.name, name))
+   {
+     if (checkPowerN(&FrameRateNP))
+      return;
+      
+     FrameRateNP.s = IPS_IDLE;
+     
+     int oldFP = (int) FrameRateN[0].value; 
+     
+     if (IUUpdateNumber(&FrameRateNP, values, names, n) < 0)
+       return;
+       
+     if (v4l_pwc->setFrameRate( (int) FrameRateN[0].value, errmsg) < 0)
+     {
+       FrameRateN[0].value = oldFP;
+       IDSetNumber(&FrameRateNP, "%s", errmsg);
+       return;
+     }
+       
+     FrameRateNP.s = IPS_OK;
+     IDSetNumber(&FrameRateNP, NULL);
+     return;
+   }
+  
+   if (!strcmp (ShutterSpeedNP.name, name))
+   {
+     if (checkPowerN(&ShutterSpeedNP))
+       return;
+       
+     ShutterSpeedNP.s = IPS_IDLE;
+     
+     if (v4l_pwc->setExposure( (int) values[0], errmsg) < 0)
+     {
+       IDSetNumber(&ShutterSpeedNP, "%s", errmsg);
+       return;
+     }
+     
+     ShutterSpeedN[0].value = values[0];
+     ShutterSpeedNP.s = IPS_OK;
+     IDSetNumber(&ShutterSpeedNP, NULL);
+     return;
+  }
+  
+   /* White balance */
+   if (!strcmp (WhiteBalanceNP.name, name))
+   {
+     if (checkPowerN(&WhiteBalanceNP))
+       return;
+       
+     WhiteBalanceNP.s = IPS_IDLE;
+     
+     int oldBalance[2];
+     oldBalance[0] = (int) WhiteBalanceN[0].value;
+     oldBalance[1] = (int) WhiteBalanceN[1].value;
+     
+     if (IUUpdateNumber(&WhiteBalanceNP, values, names, n) < 0)
+       return;
+     
+     if (v4l_pwc->setWhiteBalanceRed( (int) WhiteBalanceN[0].value * 256, errmsg))
+     {
+       WhiteBalanceN[0].value = oldBalance[0];
+       WhiteBalanceN[1].value = oldBalance[1];
+       IDSetNumber(&WhiteBalanceNP, "%s", errmsg);
+       return;
+     }
+     if (v4l_pwc->setWhiteBalanceBlue( (int) WhiteBalanceN[1].value * 256, errmsg))
+     {
+       WhiteBalanceN[0].value = oldBalance[0];
+       WhiteBalanceN[1].value = oldBalance[1];
+       IDSetNumber(&WhiteBalanceNP, "%s", errmsg);
+       return;
+     }
+     
+     IUResetSwitch(&WhiteBalanceModeSP);
+     WhiteBalanceModeS[1].s = ISS_ON;
+     WhiteBalanceModeSP.s   = IPS_OK;
+     WhiteBalanceNP.s = IPS_OK;
+     IDSetSwitch(&WhiteBalanceModeSP, NULL);
+     IDSetNumber(&WhiteBalanceNP, NULL);
+     return;
+   }
+
+   #endif
+
+   // Call parent 
+   V4L_Driver::ISNewNumber(dev, name, values, names, n);
+
+}
+
+void V4L_Philips::connectCamera()
+{
+  char errmsg[ERRMSGSIZ];
+  
+    
+  switch (PowerS[0].s)
+  {
+     case ISS_ON:
+      #ifdef HAVE_LINUX_VIDEODEV2_H
+      if (v4l_base->connectCam(PortT[0].text, errmsg, V4L2_PIX_FMT_YUV420) < 0)
+      #else
+      if (v4l_base->connectCam(PortT[0].text, errmsg) < 0)
+      #endif
+      {
+	  PowerSP.s = IPS_IDLE;
+	  PowerS[0].s = ISS_OFF;
+	  PowerS[1].s = ISS_ON;
+	  IDSetSwitch(&PowerSP, "Error: unable to open device");
+	  IDLog("Error: %s\n", errmsg);
+	  return;
+      }
+      
+      /* Sucess! */
+      PowerS[0].s = ISS_ON;
+      PowerS[1].s = ISS_OFF;
+      PowerSP.s = IPS_OK;
+      IDSetSwitch(&PowerSP, "Philips Webcam is online. Retrieving basic data.");
+
+      v4l_base->registerCallback(newFrame, this);
+      
+      IDLog("Philips Webcam is online. Retrieving basic data.\n");
+      getBasicData();
+      
+      break;
+      
+    case ISS_OFF:
+      PowerS[0].s = ISS_OFF;
+      PowerS[1].s = ISS_ON;
+      PowerSP.s = IPS_IDLE;
+      
+      v4l_base->disconnectCam();
+      
+      IDSetSwitch(&PowerSP, "Philips Webcam is offline.");
+      
+      break;
+     }
+}
+
+#ifndef HAVE_LINUX_VIDEODEV2_H
+/* Retrieves basic data from the device upon connection.*/
+void V4L_Philips::getBasicData()
+{
+
+  char errmsg[ERRMSGSIZ];
+  bool result;
+  int xmax, ymax, xmin, ymin, index;
+  
+  v4l_pwc->getMaxMinSize(xmax, ymax, xmin, ymin);
+  
+  IDLog("X (%d,%d), Y (%d,%d)\n", xmin, xmax, ymin, ymax);
+
+  /* Width */
+  FrameN[2].value = v4l_pwc->getWidth();
+  FrameN[2].min = xmin;
+  FrameN[2].max = xmax;
+  
+  /* Height */
+  FrameN[3].value = v4l_pwc->getHeight();
+  FrameN[3].min = ymin;
+  FrameN[3].max = ymax;
+
+  IDSetNumber(&FrameNP, NULL);
+  IUUpdateMinMax(&FrameNP);
+  
+  IUSaveText(&camNameT[0], v4l_pwc->getDeviceName());
+  IDSetText(&camNameTP, NULL);
+  
+  IDLog("Raw values\n Contrast: %d \n Brightness %d \n Color %d \n Sharpness %d \n Gain %d \n Gamma %d \n", v4l_pwc->getContrast(), v4l_pwc->getBrightness(), v4l_pwc->getColor(), v4l_pwc->getSharpness(), v4l_pwc->getGain(), v4l_pwc->getGama());
+  
+  updateV4L1Controls();
+  
+  if (v4l_pwc->setFrameRate( (int) FrameRateN[0].value, errmsg) < 0)
+  {
+    FrameRateNP.s = IPS_ALERT;
+    IDSetNumber(&FrameRateNP, "%s", errmsg);
+  }
+  else
+  {
+    FrameRateNP.s = IPS_OK;
+    IDSetNumber(&FrameRateNP, NULL);
+  }
+  
+  result = v4l_pwc->getBackLight();
+  if (result)
+  {
+   BackLightS[0].s = ISS_ON;
+   BackLightS[1].s = ISS_OFF;
+  }
+  else
+  {
+   BackLightS[0].s = ISS_OFF;
+   BackLightS[1].s = ISS_ON;
+  }
+  IDSetSwitch(&BackLightSP, NULL);
+  
+  result = v4l_pwc->getFlicker();
+  if (result)
+  {
+    AntiFlickerS[0].s = ISS_ON;
+    AntiFlickerS[1].s = ISS_OFF;
+  }
+  else
+  {
+    AntiFlickerS[0].s = ISS_OFF;
+    AntiFlickerS[1].s = ISS_ON;
+  }
+  IDSetSwitch(&AntiFlickerSP, NULL);
+  
+  index = v4l_pwc->getNoiseRemoval();
+  IUResetSwitch(&NoiseReductionSP);
+  NoiseReductionS[index].s = ISS_ON;
+  IDSetSwitch(&NoiseReductionSP, NULL);
+  
+  index = v4l_pwc->getWhiteBalance();
+  IUResetSwitch(&WhiteBalanceModeSP);
+  switch (index)
+  {
+    case PWC_WB_AUTO:
+     WhiteBalanceModeS[0].s = ISS_ON;
+     break;
+    case PWC_WB_MANUAL:
+     WhiteBalanceModeS[1].s = ISS_ON;
+     break;
+    case PWC_WB_INDOOR:
+     WhiteBalanceModeS[2].s = ISS_ON;
+     break;
+    case PWC_WB_OUTDOOR:
+     WhiteBalanceModeS[3].s = ISS_ON;
+     break;
+    case PWC_WB_FL:
+     WhiteBalanceModeS[3].s = ISS_ON;
+     break;
+  }
+  IDSetSwitch(&WhiteBalanceModeSP, NULL);    
+  
+}
+#endif
+
+#ifndef HAVE_LINUX_VIDEODEV2_H
+void V4L_Philips::updateV4L1Controls()
+{
+  int index =0;
+
+  ImageAdjustN[0].value = v4l_pwc->getContrast() / 256.;
+  ImageAdjustN[1].value = v4l_pwc->getBrightness() / 256.;
+  ImageAdjustN[2].value = v4l_pwc->getColor() / 256.;
+  index = v4l_pwc->getSharpness();
+  if (index < 0)
+  	ImageAdjustN[3].value = -1;
+  else
+    ImageAdjustN[3].value = v4l_pwc->getSharpness() / 256.;
+    
+  ImageAdjustN[4].value = v4l_pwc->getGain() / 256.;
+  ImageAdjustN[5].value = v4l_pwc->getGama() / 256.;
+       
+  ImageAdjustNP.s = IPS_OK;
+  IDSetNumber(&ImageAdjustNP, NULL);
+
+
+}
+#endif
+
Index: /BAORadio/libindi/v1/drivers/video/v4lphilips.h
===================================================================
--- /BAORadio/libindi/v1/drivers/video/v4lphilips.h	(revision 500)
+++ /BAORadio/libindi/v1/drivers/video/v4lphilips.h	(revision 500)
@@ -0,0 +1,84 @@
+/*
+    Phlips webcam INDI driver
+    Copyright (C) 2003-2005 by Jasem Mutlaq
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    2005.04.29  JM: There is no need for this file for Video 4 Linux 2. It is kept for V4L 1 compatibility.
+
+*/
+
+#ifndef V4LPHILIPS_H
+#define V4LPHILIPS_H
+
+
+
+#ifndef HAVE_LINUX_VIDEODEV2_H
+#include "webcam/v4l1_pwc.h"
+#endif 
+
+#include "v4ldriver.h"
+
+class V4L_Philips : public V4L_Driver
+{
+  public:
+   V4L_Philips();
+  ~V4L_Philips();
+
+    /* INDI Functions that must be called from indidrivermain */
+    void ISGetProperties (const char *dev);
+    void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+    void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n);
+    void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n);
+
+    void initCamBase();
+    void initProperties(const char *dev);
+    void connectCamera(void);
+
+    private:
+    
+    /* Switches */
+    ISwitch BackLightS[2];
+    ISwitch AntiFlickerS[2];
+    ISwitch NoiseReductionS[4];
+    ISwitch CamSettingS[3];
+    ISwitch WhiteBalanceModeS[5];
+
+
+    /* Nmubers */
+    INumber WhiteBalanceN[2];
+    INumber ShutterSpeedN[1];
+
+    /* Switch Vectors */
+    ISwitchVectorProperty BackLightSP;
+    ISwitchVectorProperty AntiFlickerSP;
+    ISwitchVectorProperty NoiseReductionSP;
+    ISwitchVectorProperty CamSettingSP;
+    ISwitchVectorProperty WhiteBalanceModeSP;
+
+    /* Number Vectors */
+    INumberVectorProperty WhiteBalanceNP;
+    INumberVectorProperty ShutterSpeedNP;
+
+    #ifndef HAVE_LINUX_VIDEODEV2_H
+    V4L1_PWC * v4l_pwc;
+    void updateV4L1Controls();
+    void getBasicData(void);
+    #endif
+
+};
+
+#endif
+
Index: /BAORadio/libindi/v1/eventloop.c
===================================================================
--- /BAORadio/libindi/v1/eventloop.c	(revision 500)
+++ /BAORadio/libindi/v1/eventloop.c	(revision 500)
@@ -0,0 +1,515 @@
+#if 0
+    INDI
+    Copyright (C) 2003 Elwood C. Downey
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+/* suite of functions to implement an event driven program.
+ *
+ * callbacks may be registered that are triggered when a file descriptor
+ *   will not block when read;
+ *
+ * timers may be registered that will run no sooner than a specified delay from
+ *   the moment they were registered;
+ *
+ * work procedures may be registered that are called when there is nothing
+ *   else to do;
+ *
+ #define MAIN_TEST for a stand-alone test program.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "eventloop.h"
+
+/* info about one registered callback.
+ * the malloced array cback is never shrunk, entries are reused. new id's are
+ * the index of first unused slot in array (and thus reused like unix' open(2)).
+ */
+typedef struct {
+    int in_use;				/* flag to mark this record is active */
+    int fd;				/* fd descriptor to watch for read */
+    void *ud;				/* user's data handle */
+    CBF *fp;				/* callback function */
+} CB;
+static CB *cback;			/* malloced list of callbacks */
+static int ncback;			/* n entries in cback[] */
+static int ncbinuse;			/* n entries in cback[] marked in_use */
+static int lastcb;			/* cback index of last cb called */
+
+/* info about one registered timer function.
+ * the entries are kept sorted by decreasing time from epoch, ie,
+ *   the next entry to fire is at the end of the array.
+ */
+typedef struct {
+    double tgo;				/* trigger time, ms from epoch */
+    void *ud;				/* user's data handle */
+    TCF *fp;				/* timer function */
+    int tid;				/* unique id for this timer */
+} TF;
+static TF *timef;			/* malloced list of timer functions */
+static int ntimef;			/* n entries in ntimef[] */
+static int tid;				/* source of unique timer ids */
+#define	EPOCHDT(tp) 			/* ms from epoch to timeval *tp */  \
+	(((tp)->tv_usec)/1000.0 + ((tp)->tv_sec)*1000.0)
+
+/* info about one registered work procedure.
+ * the malloced array wproc is never shrunk, entries are reused. new id's are
+ * the index of first unused slot in array (and thus reused like unix' open(2)).
+ */
+typedef struct {
+    int in_use;				/* flag to mark this record is active */
+    void *ud;				/* user's data handle */
+    WPF *fp;				/* work proc function function */
+} WP;
+static WP *wproc;			/* malloced list of work procedures */
+static int nwproc;			/* n entries in wproc[] */
+static int nwpinuse;			/* n entries in wproc[] marked in-use */
+static int lastwp;			/* wproc index of last workproc called*/
+
+static void runWorkProc (void);
+static void callCallback(fd_set *rfdp);
+static void checkTimer();
+static void oneLoop(void);
+static void deferTO (void *p);
+
+/* inf loop to dispatch callbacks, work procs and timers as necessary.
+ * never returns.
+ */
+void
+eventLoop()
+{
+	/* run loop forever */
+	while (1)
+	    oneLoop();
+}
+
+/* allow other timers/callbacks/workprocs to run until time out in maxms
+ * or *flagp becomes non-0. wait forever if maxms is 0.
+ * return 0 if flag did flip, else -1 if never changed and we timed out.
+ * the expected usage for this is for the caller to arrange for a T/C/W to set
+ *   a flag, then give caller an in-line way to wait for the flag to change.
+ */
+int
+deferLoop (int maxms, int *flagp)
+{
+	int toflag = 0;
+	int totid = maxms ? addTimer (maxms, deferTO, &toflag) : 0;
+
+	while (!*flagp) {
+	    oneLoop();
+	    if (toflag)
+		return (-1);	/* totid already dead */
+	}
+
+	if (totid)
+	    rmTimer (totid);
+	return (0);
+}
+
+/* allow other timers/callbacks/workprocs to run until time out in maxms
+ * or *flagp becomes 0. wait forever if maxms is 0.
+ * return 0 if flag did flip, else -1 if never changed and we timed out.
+ * the expected usage for this is for the caller to arrange for a T/C/W to set
+ *   a flag, then give caller an in-line way to wait for the flag to change.
+ */
+int
+deferLoop0 (int maxms, int *flagp)
+{
+	int toflag = 0;
+	int totid = maxms ? addTimer (maxms, deferTO, &toflag) : 0;
+
+	while (*flagp) {
+	    oneLoop();
+	    if (toflag)
+		return (-1);	/* totid already dead */
+	}
+
+	if (totid)
+	    rmTimer (totid);
+	return (0);
+}
+
+/* register a new callback, fp, to be called with ud as arg when fd is ready.
+ * return a unique callback id for use with rmCallback().
+ */
+int
+addCallback (int fd, CBF *fp, void *ud)
+{
+	CB *cp;
+
+	/* reuse first unused slot or grow */
+	for (cp = cback; cp < &cback[ncback]; cp++)
+	    if (!cp->in_use)
+		break;
+	if (cp == &cback[ncback]) {
+	    cback = cback ? (CB *) realloc (cback, (ncback+1)*sizeof(CB))
+	    		  : (CB *) malloc (sizeof(CB));
+	    cp = &cback[ncback++];
+	}
+
+	/* init new entry */
+	cp->in_use = 1;
+	cp->fp = fp;
+	cp->ud = ud;
+	cp->fd = fd;
+	ncbinuse++;
+
+	/* id is index into array */
+	return (cp - cback);
+}
+
+/* remove the callback with the given id, as returned from addCallback().
+ * silently ignore if id not valid.
+ */
+void
+rmCallback (int cid)
+{
+	CB *cp;
+
+	/* validate id */
+	if (cid < 0 || cid >= ncback)
+	    return;
+	cp = &cback[cid];
+	if (!cp->in_use)
+	    return;
+
+	/* mark for reuse */
+	cp->in_use = 0;
+	ncbinuse--;
+}
+
+/* register a new timer function, fp, to be called with ud as arg after ms
+ * milliseconds. add to list in order of decreasing time from epoch, ie,
+ * last entry runs soonest. return id for use with rmTimer().
+ */
+int
+addTimer (int ms, TCF *fp, void *ud)
+{
+	struct timeval t;
+	TF *tp;
+
+	/* get time now */
+	gettimeofday (&t, NULL);
+
+	/* add one entry */
+	timef = timef ? (TF *) realloc (timef, (ntimef+1)*sizeof(TF))
+		      : (TF *) malloc (sizeof(TF));
+	tp = &timef[ntimef++];
+
+	/* init new entry */
+	tp->ud = ud;
+	tp->fp = fp;
+	tp->tgo = EPOCHDT(&t) + ms;
+
+	/* insert maintaining sort */
+	for ( ; tp > timef && tp[0].tgo > tp[-1].tgo; tp--) {
+	    TF tmptf = tp[-1];
+	    tp[-1] = tp[0];
+	    tp[0] = tmptf;
+	}
+
+	/* store and return new unique id */
+	return (tp->tid = ++tid);
+}
+
+/* remove the timer with the given id, as returned from addTimer().
+ * silently ignore if id not found.
+ */
+void
+rmTimer (int timer_id)
+{
+	TF *tp;
+
+	/* find it */
+	for (tp = timef; tp < &timef[ntimef]; tp++)
+	    if (tp->tid == timer_id)
+		break;
+	if (tp == &timef[ntimef])
+	    return;
+
+	/* bubble it out */
+	for (++tp; tp < &timef[ntimef]; tp++)
+	    tp[-1] = tp[0];
+
+	/* shrink list */
+	timef = (TF *) realloc (timef, (--ntimef)*sizeof(TF));
+}
+
+/* add a new work procedure, fp, to be called with ud when nothing else to do.
+ * return unique id for use with rmWorkProc().
+ */
+int
+addWorkProc (WPF *fp, void *ud)
+{
+	WP *wp;
+
+	/* reuse first unused slot or grow */
+	for (wp = wproc; wp < &wproc[nwproc]; wp++)
+	    if (!wp->in_use)
+		break;
+	if (wp == &wproc[nwproc]) {
+	    wproc = wproc ? (WP *) realloc (wproc, (nwproc+1)*sizeof(WP))
+	    		  : (WP *) malloc (sizeof(WP));
+	    wp = &wproc[nwproc++];
+	}
+
+	/* init new entry */
+	wp->in_use = 1;
+	wp->fp = fp;
+	wp->ud = ud;
+	nwpinuse++;
+
+	/* id is index into array */
+	return (wp - wproc);
+}
+
+
+/* remove the work proc with the given id, as returned from addWorkProc().
+ * silently ignore if id not found.
+ */
+void
+rmWorkProc (int wid)
+{
+	WP *wp;
+
+	/* validate id */
+	if (wid < 0 || wid >= nwproc)
+	    return;
+	wp = &wproc[wid];
+	if (!wp->in_use)
+	    return;
+
+	/* mark for reuse */
+	wp->in_use = 0;
+	nwpinuse--;
+}
+
+/* run next work procedure */
+static void
+runWorkProc ()
+{
+	WP *wp;
+
+	/* skip if list is empty */
+	if (!nwpinuse)
+	    return;
+
+	/* find next */
+	do {
+	    lastwp = (lastwp+1) % nwproc;
+	    wp = &wproc[lastwp];
+	} while (!wp->in_use);
+
+	/* run */
+	(*wp->fp) (wp->ud);
+}
+
+/* run next callback whose fd is listed as ready to go in rfdp */
+static void
+callCallback(fd_set *rfdp)
+{
+	CB *cp;
+
+	/* skip if list is empty */
+	if (!ncbinuse)
+	    return;
+
+	/* find next */
+	do {
+	    lastcb = (lastcb+1) % ncback;
+	    cp = &cback[lastcb];
+	} while (!cp->in_use || !FD_ISSET (cp->fd, rfdp));
+
+	/* run */
+	(*cp->fp) (cp->fd, cp->ud);
+}
+
+/* run the next timer callback whose time has come, if any. all we have to do
+ * is is check the last entry in timef[] because it is sorted in decreasing
+ * order of time from epoch to run, ie, last entry runs soonest.
+ */
+static void
+checkTimer()
+{
+	struct timeval now;
+	double tgonow;
+	TF *tp;
+
+	/* skip if list is empty */
+	if (!ntimef)
+	    return;
+
+	gettimeofday (&now, NULL);
+	tgonow = EPOCHDT (&now);
+	tp = &timef[ntimef-1];
+	if (tp->tgo <= tgonow) {
+	    ntimef--;			/* pop then call */
+	    (*tp->fp) (tp->ud);
+	}
+}
+
+/* check fd's from each active callback.
+ * if any ready, call their callbacks else call each registered work procedure.
+ */
+static void
+oneLoop()
+{
+	struct timeval tv, *tvp;
+	fd_set rfd;
+	CB *cp;
+	int maxfd, ns;
+
+	/* build list of callback file descriptors to check */
+	FD_ZERO (&rfd);
+	maxfd = -1;
+	for (cp = cback; cp < &cback[ncback]; cp++) {
+	    if (cp->in_use) {
+		FD_SET (cp->fd, &rfd);
+		if (cp->fd > maxfd)
+		    maxfd = cp->fd;
+	    }
+	}
+
+	/* determine timeout:
+	 * if there are work procs
+	 *   set delay = 0
+	 * else if there is at least one timer func
+	 *   set delay = time until soonest timer func expires
+	 * else
+	 *   set delay = forever
+	 */
+	if (nwpinuse > 0) {
+	    tvp = &tv;
+	    tvp->tv_sec = tvp->tv_usec = 0;
+	} else if (ntimef > 0) {
+	    struct timeval now;
+	    double late;
+	    gettimeofday (&now, NULL);
+	    late = timef[ntimef-1].tgo - EPOCHDT (&now);	/* ms late */
+	    if (late < 0)
+		late = 0;
+	    late /= 1000.0;					/* secs late */
+	    tvp = &tv;
+	    tvp->tv_sec = (long)floor(late);
+	    tvp->tv_usec = (long)floor((late - tvp->tv_sec)*1000000.0);
+	} else
+	    tvp = NULL;
+
+	/* check file descriptors, timeout depending on pending work */
+	ns = select (maxfd+1, &rfd, NULL, NULL, tvp);
+	if (ns < 0) {
+	    perror ("select");
+	    exit(1);
+	}
+	
+	/* dispatch */
+	checkTimer();
+	if (ns == 0)
+	    runWorkProc();
+	else
+	    callCallback(&rfd);
+}
+
+/* timer callback used to implement deferLoop().
+ * arg is pointer to int which we set to 1
+ */
+static void
+deferTO (void *p)
+{
+	*(int*)p = 1;
+}
+
+#if defined(MAIN_TEST)
+/* make a small stand-alone test program.
+ */
+
+#include <unistd.h>
+#include <sys/time.h>
+
+int mycid;
+int mywid;
+int mytid;
+
+int user_a;
+int user_b;
+int counter;
+
+void
+wp (void *ud)
+{
+	struct timeval tv;
+
+	gettimeofday (&tv, NULL);
+	printf ("workproc @ %ld.%03ld %d %d\n",	
+		(long)tv.tv_sec, (long)tv.tv_usec/1000, counter, ++(*(int*)ud));
+}
+
+void
+to (void *ud)
+{
+	printf ("timeout %d\n", (int)ud);
+}
+
+void
+stdinCB (int fd, void *ud)
+{
+	char c;
+
+	if (read (fd, &c, 1) != 1) {
+	    perror ("read");
+	    exit(1);
+	}
+
+	switch (c) {
+	case '+': counter++; break;
+	case '-': counter--; break;
+
+	case 'W': mywid = addWorkProc (wp, &user_b); break;
+	case 'w': rmWorkProc (mywid); break;
+
+	case 'c': rmCallback (mycid); break;
+
+	case 't': rmTimer (mytid); break;
+	case '1': mytid = addTimer (1000, to, (void *)1); break;
+	case '2': mytid = addTimer (2000, to, (void *)2); break;
+	case '3': mytid = addTimer (3000, to, (void *)3); break;
+	case '4': mytid = addTimer (4000, to, (void *)4); break;
+	case '5': mytid = addTimer (5000, to, (void *)5); break;
+	default: return;	/* silently absorb other chars like \n */
+	}
+
+	printf ("callback: %d\n", ++(*(int*)ud));
+}
+
+int
+main (int ac, char *av[])
+{
+	(void) addCallback (0, stdinCB, &user_a);
+	eventLoop();
+	exit(0);
+}
+
+#endif
+
Index: /BAORadio/libindi/v1/eventloop.h
===================================================================
--- /BAORadio/libindi/v1/eventloop.h	(revision 500)
+++ /BAORadio/libindi/v1/eventloop.h	(revision 500)
@@ -0,0 +1,107 @@
+#if 0
+    INDI
+    Copyright (C) 2003 Elwood C. Downey
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#ifndef EVENT_LOOP_H
+#define EVENT_LOOP_H
+
+/** \file eventloop.h
+    \brief Public interface to INDI's eventloop mechanism.
+    \author Elwood C. Downey
+*/
+
+/* signature of a callback, workproc and timer function */
+
+/** \typedef CBF
+    \brief Signature of a callback function.
+*/
+typedef void (CBF) (int fd, void *);
+
+/** \typedef WPF
+    \brief Signature of a work procedure function.
+*/
+typedef void (WPF) (void *);
+
+/** \typedef TCF
+    \brief Signature of a timer function.
+*/
+typedef void (TCF) (void *);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \fn void eventLoop(void)
+    \brief Main calls this when ready to hand over control.
+*/
+extern void eventLoop(void);
+
+/** Register a new callback, \e fp, to be called with \e ud as argument when \e fd is ready.
+*
+* \param fd file descriptor.
+* \param fp a pointer to the callback function.
+* \param ud a pointer to be passed to the callback function when called.
+* \return a unique callback id for use with rmCallback().
+*/
+extern int addCallback (int fd, CBF *fp, void *ud);
+
+/** Remove a callback function.
+*
+* \param cid the callback ID returned from addCallback().
+*/
+extern void rmCallback (int cid);
+
+/** Add a new work procedure, fp, to be called with ud when nothing else to do.
+*
+* \param fp a pointer to the work procedure callback function.
+* \param ud a pointer to be passed to the callback function when called.
+* \return a unique id for use with rmWorkProc().
+*/
+extern int addWorkProc (WPF *fp, void *ud);
+
+/** Remove the work procedure with the given \e id, as returned from addWorkProc().
+*
+* \param wid the work procedure callback ID returned from addWorkProc().
+*/
+extern void rmWorkProc (int wid);
+
+/** Register a new timer function, \e fp, to be called with \e ud as argument after \e ms. Add to list in order of decreasing time from epoch, ie, last entry runs soonest. The timer will only invoke the callback function \b once. You need to call addTimer again if you want to repeat the process.
+*
+* \param ms timer period in milliseconds.
+* \param fp a pointer to the callback function.
+* \param ud a pointer to be passed to the callback function when called.
+* \return a unique id for use with rmTimer().
+*/
+extern int addTimer (int ms, TCF *fp, void *ud);
+
+/** Remove the timer with the given \e id, as returned from addTimer().
+*
+* \param tid the timer callback ID returned from addTimer().
+*/
+extern void rmTimer (int tid);
+
+/* utility functions */
+extern int deferLoop (int maxms, int *flagp);
+extern int deferLoop0 (int maxms, int *flagp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /BAORadio/libindi/v1/examples/README
===================================================================
--- /BAORadio/libindi/v1/examples/README	(revision 500)
+++ /BAORadio/libindi/v1/examples/README	(revision 500)
@@ -0,0 +1,62 @@
+*************************************************
+* INDI Developers Manual
+* Chapter 8: Tutorial
+**************************************************
+
+Introduction
+--------------
+
+The tutorials included in the INDI Library can be used with any INDI compatible client. The following instructions are provided to test the drivers with KStars. If you are running a different client, refer to your client documentation.
+
+Tutorials
+----------
+
+Four tutorials are presented to introduce developers to the INDI architecture. 
+
+tutorial_one: We construct a most basic (and useless) device driver to illustate basic INDI structures.
+tutorial_two:  We create a simple simulator. We will use a few handy utility functions provided by INDI like timers, string <---> number conversion, and more.
+tutorial_three:  We create a simple device, and establish a data channel with the client to transmit a FITS file. 
+
+tutorial_dome and tutorial_rain are part of the inter-driver communication tutorial. 
+
+Usage
+--------
+
+1. Running cmake in the libindi directory should build the examples binary as well.
+ 
+------------------------------------------------------------------------------------------
+
+2. Run KStars (v1.1 or above is required)
+
+Under KStars, click on the "device" menu, then click on the "device manager". Click on the "client" tab and then click on the "add" button.
+
+A dialog box will be displayed with three fields: name, host, and port. 
+
+You can enter anything in the name field, for example "my device" or "tutorial". 
+
+Enter "127.0.0.1" in the host name and "8000" in the port entry (without the quotes). This device will be saved in your client menu. So you only to do #2 once.
+
+------------------------------------------------------------------------------------------
+
+3. In the src/examples directory, run each tutorial 
+
+$ indiserver -v -p 8000 ./tutorial_NUM
+
+where num is the tutorial number (tutorial_one, tutorial_two, or tutorial_three).
+
+For the inter-driver communications tutorial, type instead:
+
+$ indiserver -v -p 8000 ./tutorial_dome ./tutorial_rain
+
+------------------------------------------------------------------------------------------
+
+4. In KStars, go the device menu --> device manager --> client and select the host you added in step #2 and hit connect.
+
+------------------------------------------------------------------------------------------
+
+5. The connection icon should be changed to connected, otherwise, an error message will be displayed.
+
+------------------------------------------------------------------------------------------
+
+6. Close the device manager, and open the INDI Control Panel in the device menu. You can control your device from there.
+
Index: /BAORadio/libindi/v1/examples/ccdpreview.txt
===================================================================
--- /BAORadio/libindi/v1/examples/ccdpreview.txt	(revision 500)
+++ /BAORadio/libindi/v1/examples/ccdpreview.txt	(revision 500)
@@ -0,0 +1,22 @@
+The CCDPreview
+
+The 16 or more bit data read from a CCD chip has to be converted to 8bit in order to be displayed. CCDPreview transfers the whole high accuracy data to the indi client and lets the user adjust the parameters of this conversion. The way the image is converted depends on the client. For example there could be sliders for brightness, contrast, gamma or a simple bitshift slider or two spinbuttons for lower and upper cutoff values. All details of the conversion exist inside the client only and the indi driver does not care about them at all.  CCDPreview allows to send parts of the preview image of arbitrary length that are joined on the client side. So the whole image data needs to be sent only once and the preview can be kept up to date during a longer readout sequence. A "maximum good data" value can be set so that saturated pixels can be marked.
+
+Control structure:
+There must be an INumberVectorProperty named "CCDPREVIEW_CTRL" it must contain
+INumber Elements with the Names "WIDTH", "HEIGHT", "BYTESPERPIXEL", "PIXELORDER" and "MAXGOODDATA".
+"WIDTH": the width of the image
+Allowed values are positive integers up to 65635.
+"HEIGHT": the height of the image
+Allowed values are positive integers up to 65635.
+"BYTESPERPIXEL": the number of bytes per Pixel:
+Allowed values are {1,2,3,4}. The byteorder is lowest byte first.
+"PIXELORDER": determines how the pixels are fed from the stream into the image.
+Set it to 1 if you have got a normal CCD.
+Allowed values are {1,2}. (1) The first pixel received is written to the upper left corner of the preview, the second one right next to it and so on, when a line is finished the next line below is started.
+(2) The first pixel received is written to the upper left corner of the preview, the second one to the lower right corner. The third one right next to the first one, the fourth one left next to the second one and so on. Pixelorder 2 is usefull for CCDs that are read out from two sides simultaneously.
+"MAXGOODDATA": the maximum good data value. Allowed values are non negative integers up to 4294967295.
+Every pixel with a value higher than MAXGOODDATA is marked as defective in the preview (e.g. by red color). So the observer can directly see whether there are saturated pixels.
+
+Usage:
+Before transferring any new image you have to call IDSetNumber on "CCDPREVIEW_CTRL" in order to reset the preview. You can send data to the preview using an arbitrary blob. But you have to set its .format property to ".ccdpreview" (or ".ccdpreview.z" for compressed data). The uncompressed length of each blob must be a multiple of BYTESPERPIXEL. For reasons of bandwidth and protocol overhead it does not make sense to transfer blobs much shorter than 1KByte.
Index: /BAORadio/libindi/v1/examples/ngc1316o.fits
===================================================================
--- /BAORadio/libindi/v1/examples/ngc1316o.fits	(revision 500)
+++ /BAORadio/libindi/v1/examples/ngc1316o.fits	(revision 500)
@@ -0,0 +1,8665 @@
+SIMPLE  =                    T / file does conform to FITS standard             BITPIX  =                   16 / number of bits per data pixel                  NAXIS   =                    2 / number of data axes                            NAXIS1  =                  440 / length of data axis 1                          NAXIS2  =                  300 / length of data axis 2                          EXTEND  =                    T / FITS dataset may contain extensions            COMMENT   FITS (Flexible Image Transport System) format defined in Astronomy andCOMMENT   Astrophysics Supplement Series v44/p363, v44/p371, v73/p359, v73/p365.COMMENT   Contact the NASA Science Office of Standards and Technology for the   COMMENT   FITS Definition document #100 and other FITS information.             COMMENT   FITS (Flexible Image Transport System) format defined in Astronomy andCOMMENT   Astrophysics Supplement Series v44/p363, v44/p371, v73/p359, v73/p365.COMMENT   Contact the NASA Science Office of Standards and Technology for the   COMMENT   FITS Definition document #100 and other FITS information.             OBJECT  = 'NGC 1316'                                                            TELESCOP= 'Optical '                                                            INSTRUME= '        '                                                            OBSERVER= '        '                                                            DATE-MAP= '24/03/94'                                                            EQUINOX =               1950.0 / EPOCH OF RA DEC                                DATAMAX =      1.037890381E+03 /MAX PIXEL VALUE                                 DATAMIN =     -5.450668335E+00 /MIN PIXEL VALUE                                 CTYPE1  = 'RA---SIN'                                                            CRVAL1  =    5.01966661513E+01 /                                                CDELT1  =     -1.944444492E-03 /                                                CRPIX1  = 2.260000000000000E+02                                                 CROTA1  =      0.000000000E+00 /                                                CTYPE2  = 'DEC--SIN'                                                            CRVAL2  =   -3.73856168315E+01 /                                                CDELT2  =      1.944444492E-03 /                                                CRPIX2  = 1.470000000000000E+02                                                 CROTA2  =      0.000000000E+00 /                                                HISTORY --------------------------------------------------------------------    HISTORY /Begin "HISTORY" information found in fits tape header by IMLOD         HISTORY BLOCKED =                    T /TAPE MAY BE BLOCKED                     HISTORY /--------------------------------------------------------------------   HISTORY /BEGIN "HISTORY" INFORMATION FOUND IN FITS TAPE HEADER BY IMLOD         HISTORY /END FITS TAPE HEADER "HISTORY" INFORMATION                             HISTORY /--------------------------------------------------------------------   HISTORY IMLOD OUTNAME ='NGC1316     '      OUTCLASS ='OPT   '                   HISTORY IMLOD OUTSEQ =    1     INTAPE = 3     OUTDISK= 1                       HISTORY IMLOD RELEASE = '15APR89'                                               HISTORY TRANS RELEASE ='15APR89 '  /********* START 17-FEB-1989   08:47:28      HISTORY TRANS INNAME='NGC1316     '   INCLASS='OPT   '                          HISTORY TRANS INSEQ=    1   INDISK=  1                                          HISTORY TRANS OUTNAME='NGC1316/G   '   OUTCLASS='OPT   '                        HISTORY TRANS OUTSEQ=    1   OUTDISK=  1                                        HISTORY TRANS BLC=    1.,   1.,   1.,   1.,   1.,   1.,   1. / INPUT IMAGE      HISTORY TRANS TRC= 2001.,1401.,   1.,   1.,   1.,   1.,   1. / INPUT IMAGE      HISTORY TRANS TRANCOD='1-2           ' / OUTPUT AXIS ORDER                      HISTORY CNTR   VERSION=  1  / PLOT FILE CREATED 17-FEB-1989 14:03:52            HISTORY CNTR   VERSION=  2  / PLOT FILE CREATED 17-FEB-1989 14:07:08            HISTORY CNTR   VERSION=  3  / PLOT FILE CREATED 17-FEB-1989 14:08:35            HISTORY PUTHEAD CTYPE1   ='        '         / OLD                              HISTORY PUTHEAD CTYPE1   ='RA--TAN '         / NEW                              HISTORY PUTHEAD CTYPE1   ='RA--TAN '         / OLD                              HISTORY PUTHEAD CTYPE1   ='RA---TAN'         / NEW                              HISTORY PUTHEAD CTYPE2   ='        '         / OLD                              HISTORY PUTHEAD CTYPE2   ='DEC--TAN'         / NEW                              HISTORY PUTHEAD CRVAL1   =  0.000000000E+00  / OLD                              HISTORY PUTHEAD CRVAL1   =  5.019667053E+01  / NEW                              HISTORY PUTHEAD CRVAL2   =  0.000000000E+00  / OLD                              HISTORY PUTHEAD CRVAL2   = -3.738555908E+01  / NEW                              HISTORY PUTHEAD CRPIX1   =  1.00000E+03      / OLD                              HISTORY PUTHEAD CRPIX1   =  7.02000E+02      / NEW                              HISTORY PUTHEAD CRPIX1   =  7.02000E+02      / OLD                              HISTORY PUTHEAD CRPIX1   =  9.97000E+02      / NEW                              HISTORY PUTHEAD CDELT1   =  1.00000E+00      / OLD                              HISTORY PUTHEAD CDELT1   =  3.05600E-02      / NEW                              HISTORY PUTHEAD CDELT2   = -1.00000E+00      / OLD                              HISTORY PUTHEAD CDELT2   =  3.05600E-02      / NEW                              HISTORY PUTHEAD CDELT2   =  3.05600E-02      / OLD                              HISTORY PUTHEAD CDELT2   =  5.09333E-04      / NEW                              HISTORY PUTHEAD CDELT2   =  5.09333E-04      / OLD                              HISTORY PUTHEAD CDELT2   =  5.09333E-04      / NEW                              HISTORY PUTHEAD CDELT1   =  3.05600E-02      / OLD                              HISTORY PUTHEAD CDELT1   = -5.09333E-04      / NEW                              HISTORY PUTHEAD CROTA1   =  0.00000E+00      / OLD                              HISTORY PUTHEAD CROTA1   =  3.00000E-01      / NEW                              HISTORY PUTHEAD CROTA1   =  3.00000E-01      / OLD                              HISTORY PUTHEAD CROTA1   =  0.00000E+00      / NEW                              HISTORY PUTHEAD CROTA1   =  0.00000E+00      / OLD                              HISTORY PUTHEAD CROTA1   =  3.00000E-01      / NEW                              HISTORY PUTHEAD CROTA1   =  3.00000E-01      / OLD                              HISTORY PUTHEAD CROTA1   =  5.00000E+00      / NEW                              HISTORY PUTHEAD CROTA2   =  0.00000E+00      / OLD                              HISTORY PUTHEAD CROTA2   =  5.00000E+00      / NEW                              HISTORY PUTHEAD CROTA1   =  5.00000E+00      / OLD                              HISTORY PUTHEAD CROTA1   =  0.00000E+00      / NEW                              HISTORY PUTHEAD CROTA1   =  0.00000E+00      / OLD                              HISTORY PUTHEAD CROTA1   =  0.00000E+00      / NEW                              HISTORY PUTHEAD CROTA2   =  5.00000E+00      / OLD                              HISTORY PUTHEAD CROTA2   =  0.00000E+00      / NEW                              HISTORY PUTHEAD CROTA1   =  0.00000E+00      / OLD                              HISTORY PUTHEAD CROTA1   =  1.00000E+00      / NEW                              HISTORY PUTHEAD CROTA1   =  1.00000E+00      / OLD                              HISTORY PUTHEAD CROTA1   =  0.00000E+00      / NEW                              HISTORY PUTHEAD CROTA2   =  0.00000E+00      / OLD                              HISTORY PUTHEAD CROTA2   =  1.00000E+00      / NEW                              HISTORY PUTHEAD CROTA2   =  1.00000E+00      / OLD                              HISTORY PUTHEAD CROTA2   =  3.00000E-01      / NEW                              HISTORY AIPS   IMNAME='NGC1316/G   ' IMCLASS='OPT   ' IMSEQ=   1     /          HISTORY AIPS   USERNO=   51            /                                        HISTORY /END FITS tape header "HISTORY" information                             HISTORY --------------------------------------------------------------------    HISTORY IMLOD OUTNAME ='                                                        HISTORY IMLOD OUTSEQ =    0     INTAPE = 1     OUTDISK= 3                       HISTORY IMLOD RELEASE = '15JUL94'                                               HISTORY SUBIM RELEASE ='15JUL94 '  /********* Start 24-MAR-1994   10:58:33      HISTORY SUBIM INNAME='NGC1316/G   '   INCLASS='OPT   '                          HISTORY SUBIM INSEQ=    1   INDISK=  1                                          HISTORY SUBIM INTYPE ='MA'      USERID=  100                                    HISTORY SUBIM OUTNAME='NGC1316/G   '   OUTCLASS='SMOOTH'                        HISTORY SUBIM OUTSEQ=    1   OUTDISK=  1                                        HISTORY SUBIM BLC    =    1,    1,    1,    1,    1,    1,    1                 HISTORY SUBIM TRC    = 2001, 1401,    1,    1,    1,    1,    1                 HISTORY SUBIM XINC   =    4      YINC =    4                                    HISTORY SUBIM OPCODE = 'AVE '                                                   HISTORY HGEOM RELEASE ='15JUL94 '  /********* Start 24-MAR-1994   10:59:29      HISTORY HGEOM INNAME='NGC1316/G   '   INCLASS='SMOOTH'                          HISTORY HGEOM INSEQ=    1   INDISK=  1                                          HISTORY HGEOM IN2NAME='FORNAX      '   IN2CLASS='I     '                        HISTORY HGEOM IN2SEQ=    2   IN2DISK=  1                                        HISTORY HGEOM OUTNAME='            '   OUTCLASS='Optic '                        HISTORY HGEOM OUTSEQ=    1   OUTDISK=  1                                        HISTORY HGEOM BLC =    1,    1,   1,   1,   1,   1,   1                         HISTORY HGEOM TRC =  501,  351,   1,   1,   1,   1,   1                         HISTORY HGEOM IMSIZE =  512,  512          / Output image size                  HISTORY HGEOM  / Interpolation order used was BiCubic                           HISTORY HGEOM  / Indeterminate pixels filled with magic values                  HISTORY HGEOM  /      74383 Pixels blanked due to memory limits or geometry     HISTORY HGEOM  /          0 Pixels blanked due to input blanked pixels          ORIGIN  = 'AIPSGorilla (NRAOCV IPX) 15JUL94'    /                               DATE    = '24/03/94'                    / File written on dd/mm/yy              HISTORY AIPS   IMNAME='NGC1316/G   ' IMCLASS='Optic ' IMSEQ=   1     /          HISTORY AIPS   USERNO=  100            /                                        END                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
+$0;J{²Y_diou}
+Š¯¹ÁÀÄÇÈÈÈÈËÌÌÏÏÏÓÓÑÒÓÓÕÖÕÖ×ØØØÙÚÚÛÚÜÝÝÜÛÜÝÜÝÝßáÞßàßßáàßàááâáÝàáâäçèéëæååääãããæäéäâãäãääââãåãããããäãááàßàáàáâääååääåææççéìíïììëèçæçèçæåäåæååäåãååãèåãâåçããäãäåçæçèççèææçèæèáãèèææææèèæçæååååäçåææææéæäåäåååæåäææåååæææåçæææçææçåçèèèèççééææååæéèæéèçèèçæååçèæåãäååäääåääãäåäãââäãàáâáààáâããâãããããäãääååäâåèýçâãäâãââãàßâãäààààÞààáßàÞààÝÝÞàáàààßÞßåõÜÞÞÞÞÜÞÞÞÝÛÛÞßÝÜÜÛÚÚÙÝÙØØØ×Ø×Ö×ÖÕÓÔÖÔÓÑÒÓÊÊÊÊÇÆÅÅÃœ·°Š}wrnhc`[VN	".9EVZc^chnsz¥±·»ÁÅÅÇÈÉÊÊËÌÎÎÑÐÓÓÒÒÒÔÕÕÖ××ÙØÙÚÙÚÝÝÞÜÞÝÝÜÝÞÞÞßßÝàæáÞàáÞàààáãáãâáâêêåçääåâââáãáâáãããââäãâãããââãââãâáâáààâãâããããäääåååçééèêêééèççççéèèéæåååææåææçòçäâãæääääæçèççèççéçèçëçãVæççççççæççæçéææææçæææåæçååæååææåæååçååèèççæçéèççèèçèéêèééèççæéèæåëìçøöééæççæååååçåååæåääæååååçäããããåãâãäáâãâääãäæåäääåæææäåäååßãâãääãããðøìâåæáââáàâàáàßßàÞõôÞáààáàßßßÞÞßáÞÞÝÞÞßÝÝÜÞâáÞÝÜÛÝáßÛÚÚÚÙÙÙ×ÜÙØÖÖáâ×ÓÓ×ÍÍËÊÉÊÈÌÈÃœ¶®¥|vrmgb^ZT*6AJSUXbflsx~¡¬Ž¹¿ÃÆÇÇÈÌËÏÓÜÑÐÑÑÖÔÓÔÔÔÕÕÖ×Ö×ØÚÚÚÛÜÛÞßÞÝÜÜÝÞßàÞÜÝÞÞßÞàáßàààââáâââáâãããããããäâããâáâãâãããääääãããããââÞããâåäããæäââäããååååæèééèééééèéêéèéèèéçæææççåççèíçæåäåæææææçèèèèèçèíèèèèå
+þçèçæçéèæææçæéèççæççææææççççåææåççæêçæåèéçèèéééèèèééèêîïéèçèçêéìèææëíéèéíñëèæçæçæåçåæçææåæææåãäååãääååâääääääçèäæéçåæææçæèååæååæãããääååãÿR8ÜäãâããâáäâáàÞàáÞù÷ÞààßààààßÝàßàÞÞßÞÞÞÝÝÞàáßÞÝÜÜÝáßÜÚÜÜÛÚØ×ÛÙØ×ÚáßÖÔÓ×ÏÍÌÌËÊÈÉÇÄÁº³«¢zvusfb^Y
+
+'4?GNUZ_flrw}¡Š²º¿ÄÅÆÈÉÉÊËÎÏÒÓÑÑÒÖÕÕÖÕÕÖØàâÙÙÚÚÛÝÜÜÝÝáßÜÜÝßÞÞÝÞßßßßßÞßàáááâãäâââããããããääãâãäääãââãããæææææåãäåääãëåãâéæåãâããääääåååæèêççèèèéèéêêèææççåææåææçææççêèæçèèæèèçæåæèèèèëçê	íèééèãæééèçæçèæçççççèçææææççççææææææææèççèæçéçèèèçèéççèèèèéìëëêéçèèééëèèççççèå;èæææçææåäåææåçæåææåäääääääåäååäåææçéæäææåæææååæååæååæääääãäéåðVOÙäããäãââãâááßàáàßàááààààáàáàÞàßàßàßßßßÞÞÞâàÜÝÝÞÞßßÝÝÛÝÜÜÜÛÛÛÚÙÙÛÛØÖÕÔÔÒÎÍÍËÊÉÈÇÆÃÀ¹²ª¡zwvkgb^
+#.;EMSX^cjov{€ºÀœÄÆÆÇÊÊÉËÍÎÏÎÐÑÒÒÖÕÔÕÖÖÖÖßãØÙÚÛÜÜÛÜÝÝÞÝÝÝÞÞÞÝÝÝßßàßßßàßàáâäâáââãããääããçêääâããâãââããäæåææåäãããäåäùSåãâçääãâããäãäæåäæççéçæçèçëêéèéççæçæåææåääçææçéíìèççèæèèææççééèèêçêýìéêéèèèãåéêéèéèèçççæççææçêèçèçææååæææææçççéêééçêéèìêçèèèèèêìêèêçêèêêéêèéçèèçççîöñéççççææååèçåäæååççåååæçèåååææççåææåççåäæææèéççæææèæåæåååæåäèèäÞÞåäååçæäãâááâáàáàááààààááááàáßáßààààààààßÞááÞÞßßàßßÝÞÞÞßßßßÞÜÛÛÛÚÚÙ××ÔÓÔÒÏÍÍÊËÊÈÈÆÃŸ·±š ~yvojfa	 +7BKQW\chntz£¬»ÂÃÆÇÈÌÏÊËÌÎÑÐÐÏÔÕÔÕÖÕÖÖÕÖØÛÚÙÛÜÜÝÚÛÜÞßßÞÞÞßàÞÝÞÞÞßààßßàââááâáâäèåããååãããâããããâäæãåääääääääåäääåææéûåäãäääãååäåååççæèéæçèçççéíîèèèççèçççççæïÿæèèèêêìéèæææèèççèèêéèêééêæèêêîóë:åêééêëéèèçèçèçèçêéçèçææíîççèçæçèçèééêéìëéóïèèéééêëêéçèéêéëèèçèèêëéèèèçèèèèçççéèæåççèççååçèçææçèèææçóééææäççææææçççææçæååææææåæääææääåååååäåæççåããáâáãââááááááàáááâàáàáßáàßáááßáàßààßÞàßàßßÞßààãâáàßßÞÝÜÛÜÛ×Ø×ÖÔÓÑÏÎÌËÍÊÉÈÆÂŒ¶®Š}wtnjd
+
+(3?HOTZagmsx ©³ºÂÆÈÊËËËÉËÍÏÓÒÒÑÖÙ×ÕÙØÖÛÜÙÚÛÛÝÛÛÛà
+ðÞÝÞÞÞÞßßßßßàààáàáààçâáãâããáòêáãææããääååäåãåäîåãäåææååæååæååææåäåæçåãääåæçæççæææççèèèèæççèèééèèèççééèçèåøæêèéèéêééèçåçéèèéêêêéêéêìéèééø
+B
+æéçèêëéééêééééççèèèèèêéììææèéçèççèèèéëéëêîìééééêëééééèééééêèéçèëêèèéçèèççæèèêççææèçççææçèççëìæäææäé
+íèèæäåæççæççççææåæçåååçìåäåääåæææååææåæçäåååãáãããââáááááâââââââááááâààáâáààáãáßàßßßàßàáàââäãäãàââàßßßÝÙØØÙÖÓÓÑÑÎÍÍËËÉÈÅÁ»Ž­¥|yrmh
+$0<FNSX^ejqw~§¯ž¿ÆÊÈÉÊËÎÌÎÎÏÒÔÓÓÔ×ÖÕÚÙ×ÜÝÙÚÛÛÜÛÛÜÞìçáßàßÝÞßÞáààãâßàßàáàáââäááãåæäâãååååääãääåããäææäåäåææææåäæçæææææçæêçäåèææçæççççççççèëæèèèèèééèééèèéèçççæì÷èèèèçéééèéíøðééêìêêëëêêêìéééöû%	÷óíêéèéìíéêííêêééèèéêéééïíèèççèèèèéèëëêêìêêëëéèéêêëëéêêêéééêèëêéèééééèèèéèèèéèçççèçççèéèçæèèèçèéæçèéìçéëçêèæååéèæéëëêææçåæåååçôëçæåæèççæåæææåææææååãããåäãâáâãáâäãâãááââáâááààáâàààâåãàâáááááâãããäæåçåääåäââàÞÜÛÚÚØ×ÖÓÒÏÎÍÌÍËÉÐËÀ¹³¬£|wpk	 +8CKQW\cinu}€­¶œÃÌÏÌÌÊÌÏÎÑÏÐÔÚÕÕ××ÕÖÚÙØÚÚÚÛÛÜÜÛÜÞàÜÞàßáßðæßàâáßèõìàáâäââáãâãæäæäããääååæåæåæôõäåçååååæææöñãåææçæçæèææççççèåæèçççççæççççéîçèëééêèéêééèçèèçèèèèééèéçèèëêééò	øèëììèîöìêííëêëêûð÷õìêëëëëêìíéêíìéêêéêèéìêééíìéééèèèéèèêìëêíìëëëêééééëìêêëëëëêêëñéèééèéééèéêêêêíèèèççèççèèèçèèçæææçæåççéèèèçéççèçççæçêêéçåæåæççæèêíççåææåæææççææçææåäåããååãâââãããääããââáâáâáâááâãáàááâââââãââããäæäéêçèèéèèçåãâáßÝÜÜßâØÔÒÑÏÎÍÌËÊÒÏÄœž±©¡
+zuq	
+
+'3?HOU[`gms{¢ª³»ÂÆËÎÔÕÌÌÌÏÐÏÑÕØÕÔØ×Ö×ÛÛÚÙÙÛÜÜÜÜÛÝßßßåèáààçãááááÞð	üâããäââââãâæäããåããääåääåååèìíåèåäåæåçïìæåååìðåææææççæèèéíêèèéèççèéçèèèçççêééééèèèèèèèèçèéèééééééééðêëééëêêììéçöìéîóëëëëéëëêêêéêëìëééêééêèêëêéééêéèéêêêééèéëéêëééëììëêëêêëëééëêéêêëëëééí¶)ìçêëèèêêèèêêèéëèèêìéèçææèçççççèèèçæçççæçççêéææéèççèèéèèéèæçèçèæêèêçæçæåæåäåæææäæèæææääããääâãâááâããââãäãâãâááââàâãâááâáâãáâäãâääæçæìëêìííåçìêçåäâàßÞâçØÔÔÒÑÐÍÌÌËÌËÉÃŒµ¯Š}yw
+".<FMSX^djpw
+š±ž¿ÆÇÇÊÑÒËÌÍÎÎÏÑÒÒÕÕÖ××ØÛÛÙÚÚÜÝÝÜÝÞÞÞÞÞéëáàáßßàáááàçñíââãããâáããâääãäæääääååäåæèååðçèååãåæççææççæççåèêèæææèêéâÃOéæèèççèèèèèéçèéèìéèèéééèéêèèèèéêêêêêéêçèéêééêéêëëëêéðúëéíôëñíìëìëëêééêêëëêéêéãêêëêêêêéêéééêêééééêìèêëçèìììîëêêëëêêêéòúîëêëëêéíYëéëêèèééééêéèéêéçêíóèèæçèæåèèèéêêèççéîæèêééèççèéêèççèéèèçææèèççççéçççææçæææææææçèçææåääååääãâãââääâáããâãääãæââââââáââããããââèðææêêéëíïðôú
+
+ññìèèåäâàÞÞ×ÕÔÒÒÒÏÍÌÌËËÊÇÁ»µ­¥~z	*6CLQV[ahmtz€®¶œÃÆÇÈÊÊÊËÍÏÏÏÐÑÐÓ×ÖÖ×ØÙÛÝÙÙÜÝÝÞÞÝÞÞßáåãçáàâááááááçíçáãâãæäâããäãâýóäçåäæåçêèççääæåæäæååèìèååææææçéçéçèççèìå`%ëèèèèèèççèèèééèèééèèêëééëêéèêìéêééééêêéêêìêêéêêêëëêëëëììííìøîììììðìéëíêéëëéê$éëìêêêìëìëêêëëëìëêêêêêéêìììíðîííììëëìéóþñëêëìïëêßëëëììéêêêëëêêéêêéééêîéèèééèçèéééêêèèéèêçèééêêéèèéèééèèèèèèèçèéêçèæèèèèçééèéèææçèééççèæåäåãääæääåäâãäââãâäæãããââââââáâãååäääãñ	æéëíîñôô÷û
+XõöúþòêèãàßÝÙ×ÕÒÓÒÐÍÍÌÌËÉÈÅÀ»³«€}
+&2>HOUZ`gmsy¢«³»ÂÇÈÉÊËËÌÍÎÑÒÑÒÒÓÕ×ØØÙÛÛÛÝÛÜÝÞàÞßßàáæáäâäãâââäåäçìèäæååçåèäæäääôïåææææçèééçæåååçææçæçééèîìæçèçèèèèèèééììêéôðëðîéééééêèéêéêéêëêêêêììïøñêëíîêéêìéêîééêêéêëííìëììëìîíîíëíëîííòîíùòëìîöõêììéjèêëëëìïîìëëëìëìíëëìëìíìíîíîîíîîíîíëëîíëïîëëëìïëìíììëëìêééêëêéééééééèééèèèéèééèèèèèççêëçèèèèëéèèèèëêèééèçèèçççèçéèçïõëèèèèééèèèçèçééççççæåæääãåãåìèâãäåäâããäãââáááâããââãåæääääçìèéìîñõøúý	wMþÿðëæáàÜÛÙÕÕÔÒÐÎÍÍÌËÊÊÈÅÀ¹±ª¢
+
+".;EMRX_dkry~
+š±žÀÆËËÉÊËËÎÐÐÐÑÑÓÕÔÖÙÛÚÛÜÛÛÜ
+ÛÝÞÞßáááààáâáâæãããâäæçåäåååäåçåçåæåääæååæåæçççæææææçææçåååæææææééææçæçèçèèçèèçèèèåççþöèéèèéêèéêéèèèêééêêéèêëêêëêêêéééìêèéééêðíë÷ñêêëëëêêéêëéëéîêíðóîìïîêì
+
+èììììëìéêìëîííëìêêééëëíïïííîîìïðîîîííííðïìîïêêëëëëëëëíîìëëêêêêéêêééééèéëééêéçéèèéêééééêèíòêíçèèèéêèèèèèëéççèèçèèçççæçèçè6¿áèèêèèèçççèèêèèçèèååæäãäåãáíøîâããäââãâãáâáäáâåæäãäåääææåæèêìïñõüþ
+
+þôîéâàÜÚÛ×ØÔÓÒÐÏÎÍÌÌËÉÉÆŸ·±Š	
+
+)6AIPUZagnt{¢®®¶ŸÃÆÎÌÈÊÌÌÎÑÏÐÐÓÖÔÔÖØÚÚÚÚÚÛÝÝÝÞÞßÞßááæààááàáããâããâäåäãåååååæäãååäãäääåæååæççåæåçèçæçæääåæçææææçççççççéèççèéèéèèèèèîìëêèéééééèëëîëêêêëêêêêéëëêêêëëëëêêìëëêæLíëëëëëíìêëëëêëëðëììííîëðïëìíììëììëëëêëëìíìëëëêíëëëìñöóðîîïñòîíïííïê'èìîîëëëëëëìííëêëëëëêééêéêéèêéëééëèèééèêëêêêéêéìïëêéèéíêéééééééééèééééééì÷èéééé/÷çêéêïæãéèéèééêêééèèæåääååääæèççèääääääããååäããëçäååäåææèçèëîîñõúÿ
+
+(01)
+÷ðêåáßÜÛÛÚÖÕÓÑÑÐÏÎÍÍÌËÇÂŸž¬¥
+$1=GOUY_flsyŠŸ·ºÂÅÆÉÊÊÌÍÍÏÏÏÒÒÔÚÖØ×ØÚÚÛÛØÙïüéÜÞÞßààáçáâáâáâãâáãääããâäèéèêææååäääæåäåæååææççèèçèèçæççååæççèééèçììçèêíéèéèéçéèçéééêêòðêéçêêééêîíëëêéêêëéëëêêëëëëìëëììëëëëêéòôïìëììììëëííëëìíòìììíïíììîíìììëëìëëëìëëììíìëëëìòðìííïððòðïïõñîîðïñóî=èìðòìëëìíìíìëêìðíìêêëëëéëèåëëëêêêéééééêêêìëééèèéìëéêìñëëëééééééêêêéééêêìðééêêêêäéìëëêé¹©âèéêêëîììççèèçæåæçåååääåææääæãããããæçäãäååååååçèêìêìíñôúý
+!-@WjgQ=*úóîêæãßÝÛÚØÕÕÓÓÒÐÏÍÌÌËÉÅÁ»³©£	
+ ,9DLSY^ekpw~
+ š°œÁÅÈÉÍÍÍÍÎÐÏÎÒÓÔÓÕØÚØÙÚÜÛéì#ýÛßàááááâäâáâäãããããäääããåéêèêæèæçåååçåååååæçççèéèèèççææççæèéèèéêéèêëééîóêêééèéììéêêêëëðîéþ	ðììëëìíéêëêêéëêëíëëìííìíìíììììíëìëìïíìîîíìëìîìììííîííííî
+÷ëìïïîííìíììììììììííìëëììðïîïðòðïïíïïïëíïññññôóíêëíííìííìííììëëêîóïìêëììëêèþìêìíëéíêéèééêêêêêéèèèêìéêëìêëêèåèééèèëìêéèéêêééêêéêêëéêêéêèsçéééééìëïþëèæééçåååäåååæäãääããããåååäâáãåååååççæèêëîñöü&WÐüíŽp8
+ýôîìçââÜÛØ×ÕÕ×ÙÓÎÎÎÍÌËËÈÄŸ·°š
+
+
+'4@KRV]cjou|¥¯·ŸÆÈÌÌËÌÍÏÐÐÙåÙÔÔÖ×ÙÚÙÜÛÛÚúIÛãààààâââââããâäåäãäääåååääåååææåææææçæææåæåæçèèççèèçççççéèèíéèêèçêëêèéêéìðêééèèéêëééêêéêëëÜæçëêêééêééêêêìëëíìêëìîîëëììêìíìíìëêëììíîîíìííìëëëìñðòîììíñïíììíëíîëììîëëëîêëëëêëííìííîñòïîîîííðíííïññîíííììîíííììîìììëëëëðííìëëëìëêæ	0íéëîêëðìêéêêêéééêêèèééêéêêééêéêûèêééëëêééêêêéééêèêêìêíìëêêÿþêééêéêêå	€óæççççáâäãåååååãê÷ããäâååääääæååææçèèèéííðóùþ
+8s)Õ0fšF%ÿðìçáÞÜÛÚØÕÖÕÒÑÐÏÎÎÎÌÌËÈÂœž®€
+#.:FMRX`gmrx¡«µŒÂÆÇËÌËÌÎÎÏËý5åÓÕ×ÚÙØÙÜÜÛÜÜÚÜßááàáàáäââáàãâäãäããæåææååääåääæåååæçéæççæèææçèççææéèçççèîêéîéçééçéëêèééêëëééêéëéêéééêéèéêêã5eëîêêéèëéèêêëëëìïíêêìîíëìëììíïøîíìììëìïñòïííîîïîíòöõóñîðìïøõíììíïíëííììíéêëëêëìíïñøõðññðïïðïìíîïðóððîìíííìíîííííëííõììîìïìëëëëëìëêëïîëêêëëíîìëêëêèèééêêééêêëììêêêêéë.ÿçêêêêêééêëéìóéêéèëêêéëêééêææêééêêêêéþIïçèçæä
+ãäååååäãèíæåäãäåâäåæçååèèæççâ	Z
+ïôû
+'KŠ ãÃÞÏX+ùñìçâÞßÝÚØ×ÖÓÔÓÑÐÏÏÎÍÌÍËÇÁŒ²«€
+)6BJQW]cluw}§°»ÂÆÉÈÉËËÏÑÐÑÑÕÙÕÕÖ×ÙØÛÚÛÜÝÞÞÞÝÞããáããàááãââäãâãäääêèçåäåäääääææåèèèèçèççèçæççèçææèèçèèèëêèçèèèìêéêêëëééëìééêêêêêêéééèééééëåßéìíìéêéêêéêêêêêëíìëêëîìëêëìíëíñìëëìíììðöúøñîòóððîöðîòðïîîíòòíêêîðíîíëíìëêèïìêéìììëíïðïîîíîïîííîíòôëîíìëìëìíìììïòëìïìí÷ðëìëìîíëêêêíîéëëêêëêëêëëëëëìêééêêééêíñðéêêëêêôïëêëêêëêêêëêíóëëêëéêêêééèëëêëêéêëëêììíéèéêéèçã0äåææååååææçæååäåäääææçççèçèééóõîö
+,UœÔœõÆßÍX-ûñìèäßßÜÚÙØÖÔÓÓÒÐÐÐÐÎÏÏÍÊÄ¿ž°º¢$1<FNT[agnsz¥±¶ŒÃÇÈÈÊÍÎÍÎÐÏÑÓÓÓÔÕØØÜåÞÛÛÞßßßßßââàâááßÛâåäæãââããåæåååäääääååååæëéèæçèëèææççèçççèéèæäçèçéçèéåçíêéêéëìíëêìêêééèéêëêêééééèèëìëêêëìëêêêíëëêêêêêëëëëìëìëêëìíììêëììììïüëïDLéîðòðïðú
+ðíîîîòôïìëíïìîïîíìêëììííëëìíïññîîïðïíîîîîïïïíîìîîîíìííîîðòîîìííìííñìïîííììííìííîîìëìíêêìêìíìîòïìêêëêêêíðñéìêëëíòïìëëêêììêêëëëêëëììîíëëëïëëêéëêêêêêêëëëêëéêéççåþöååææååææååææççååççææåæççåæççêéèíðõû
+*L§£u8]E"ùðìåâáÞÝÚÙÙ×ÔÔÔÑÏÏÏÏÏÎÍÍÌÉÅÁ³«€
++7CLRX^dkqw¢ªŽŒÂÇÈÉÉÌÐÔÐÏÑÑÑÒÔÕÖØÚÛñþæÝÞÞßàßßàãåããâàìþñ
+åãåãäèåääääååææääåçææçëèêèèîòëçççêìéçèèèçîééééçêéâæèçèèðóíííêéêêêêêéêêêëëêêéèéëìëëêêììëêëíëëëêììììëëìëêìíìîîëììêìììííñüóÍ-êîïïðïïóGÐ5îìñðîîðîíîîîìíííìêéêììíîìíííîïïððîíîïîîïïïíîîðïîíîîîíííëý
+ñðîíìíìëìëììííììííìííïðìëìîíêêìêëëëëïðìéëêêêëêëëîíííëððéêëêëëìëëíëéëëëìíðñëéëïëèéêêéêêéêêêêêêìîëéççêçååççåååæåååååççååææèæååææååèéèêëïïõ÷þ%>Yj#Œh0ÿøðëåâàÛÛÚ××Ø×ÖÓÒÐÏÏÏÍËÌËÊÊÇÀ·±ª&2?IOV[ahnu{§¯žÀÅÇÉÉÌÌÏÔÔÑÑÑÒÔÔ×ØØÙÚÜÝÞÞÞÝÜÝßààããáâáÙG!.Mæäãåãïéäåååæççååäåæææèççòìçòêèëéìñëçççèæö)íêìèèéêêééêêéîéêëêêêêêêèéêêìëêêêééëìëëëêëëìêììëëììíîììëëëêëëíìííìììëììííííñó
+øïîîïðîðñ
+ïíñîíîðïîðïííííìëéééíìîíëîîîïîíïïîïñðïîïïñïïñðîìîîìëëìíìõÿóññììíììììíìíîíððíííí÷ýëìëìîìêìëëêêñîëëêêëêêìëêíõïïïêíöîêòïëëìììííëéêëìëìêïêêêéééêêêêêêêëêêéêééíêèççêéçæêêæåååçêçæååææåææçæååèéçæéìéëìîðóöý
+9Yr{X=%úõîëèãá@ïØØ×××ÖÓÔÒÐÑÏÍÌÊËÉÊÇÃœ·± ,:EMTY_ekrz¥¬ŽÄÃÇÉÉÊÎÍÍÏÑÐÑÒÒÔÖÖ×ÙÙÜÜÞÝÝÝÜÜÜâåãååãââÞ*Àäååäääåèæååäåçæåæææçæåææçíêéîìêèóïæççèèçèééêëéíèèêëééêìêìêèêëëéèêëêééëëëëëêêêéíîëëëëëëíìíììîç÷ììëëëëëìëìììïîìììíììííìíïìêîïíîðñïïññàñóïïîíîïîîðïíííííìëéëíííìîíìííììííïðñòðïîòñïîììíìííìëìííìíîïðïíìííìîìíîíîîíìíïðîý
+ëíííîìíìëëëìðîìëëëëêëììêëîììëëëïíëùìììíìëëëêêêëëêëêéììêéêêêêéêëêêêëêêêéêêééèçééèêéæçççèìèççæææåçèçæååèèççéìêêëîðó÷û
++17?A:,
+øóîêæãáÿäÚÚØ××ÖÔÔÓÒÑÐÍÍÌÌËËÈÆÃ»Ž'4@KRW^dipv}
+ ©²¹ÇÈÈÊËËÍÍÎÐÒÑÑÓÔÖØ×ØÚÚàÝßàÜÛÛÜßâã
+ðãæåäèðéäãääãäåäåæääåååååççèçççççìéèççççéééççéèèéëééìëìéêêêéëëëëêêêëêêììêêëìêëëîììëìëëëíòôñììììîïìïííòùììëëëììììíïíïîëììïîíííôòððïïîíîîñðïñòððóðïîïîïññððïîîïîîìììïîìëíííííòñììîïîïððñðîìíîïíìîíììííîííîïððîíîííïïïîïîïîîïîððìíîîñìííìíìëëîìíîíííìíííîììñììîíîííïý÷íììíîíëëëêëìîíìëëëììììììëêéëëëêëêëëêêëéêéèêëêèçèéèèèèçééçççææçèçççççæèéééêëíîò÷ú	$!
+
+ýõðëèäãàÝÜÛÛ×ÖÕÕÖÖÕÓÑÐÎÎÍÍÎÏÉÉÆÀž.<GOUZagmtz¥¯Œ¿ÅÉÉÊÍÌÍÏÑÒÑÒÓÓÔÖ×ØØÞÛÝáéÛÜÜÞàßàêñëääæäåáåååãæçìêææææææçæåêñïìçççèëçêçèèèèèéêèèéèéééëêéìëêìêëëíìëìëðòìíìììíïëììëìñíìììííìñôôôíîííïïíïïîúýqóëíííìììììíðííííììîîîíîóòïïîîîîîîñòíïñïïñòñòñðñññò÷õïïïîïîíííîíìîíïïïñðíííîîîòóðïïðíîîìíííîííîíííðóïîîîîîïîïíïïîïïíííîîîðôìîííïìíííëìììííîíììííîìííììíìííìîîííììîîíëêëìêìïìêëëëëìììììëêèêëìëêéêêëëêéìêééééèèêëèéèææçéçççèæææêéæçæåæèèèêìììîóùÿ
+þû÷òð÷èâáßÝÛÚÚØÖÕÔÔÕÕÓÒÑÐÐÍÑÏÎËÍËÆœ5CLRW^dkqw}
+¢ªŽŸÂÈÌØÎÌÎÎÏÑÒÒÔÕÔÕ×ØØÙÛÛÝÞðàÜÞßàààßáåçæãåæäåæåäääææåèçæèçæææææçèçççæçéêéçæçèéèèéééêêéèéêééîìëêííëëììëé
+ëîíëìó÷ïíìííííîîìîïîîíëìîîíííîîîðïüN÷îðííííííììîîíìíìíííííîíïïîîîïïïïñðîîñîïïòòòðïððñóõõñðîïïððïíîíîîîîîðîííííîîïïïîííðîîíííìîîíìëýíïïðîïïîîïïðíîïóóðîîîïïîîîííííìëëëíïíìëëììëëìííðîííëíìíííììíííîíìîìêêëëëëëëíëêëëëêëëêëêéêêëëêéëêëëêéîëêéçèéèèêéêççæççççæéææåëéåææææèèèêíìììðõùÿ
+	üøõñîðüéâßÞÛÛÚÚÙØ×ÖÕÔÓÕÖÒÛþúÑÏÎÌÍËÈÂ>HOU[bhov{š°ž¿ÇÍÌÕÍÌÏÐÐÑÒÔÕÔÕ×ØÚÚÛÜÜÞÜÛÚÜßâääßÞáãåæãäåäåçãääæç
+øææåæææææçæçççèèçèïíéèèçêêèééèéíîêêêèéèéêëëïðíìíìëë÷ùìíðíëîùóëëðíîíîíìîîíìëíîîïíîîîðîðïôìðóõñîîîîíïîîïïíííííìîíííîððîïïïðïïïïïïòòðïðððððññññððòðïñðññðîîíïïññïîîííîïðïñöóîíîíïîîíîîîòðìëòíîððììðïîðîîîðòñïïðîîïîìïñîîîìëìííììîîíííìëìííîííëîîîííîíîîîîííìììììîìíìêëîììëêììíìííëììëëëëëìëìììéëêëêéêêéèéééééçççæçèêèçæçèçæçéçéëìêìîííïòó÷úüþÿþþû÷õñîëêíçãáÞÜÜÚÛÚÚØ××ÔÔÖ×ÕØöÏÎÏÍÔÑËÇDLRW]emsyŠ®µŒÄÒÌËÌÍÍÏÐÑÒÒÔÔÔÖ×ÙÛÛÜÞÞßâÚÚÜáâäâíéáãæåâäæäçæãåãéçõëåçèèçæççççææçæèçèçèèèêèæççééçðùñêéêììéêêëìí
+ûîïñîííìììëìíìëëêíîîïîìíííííííîððïïîîïðîïïððïïððñðïîîïïïðïîíîîîííïïïïððóóïïðððïñïïòôñóòðñóóòòñòóóòòóññññññïïððñòòðïïïïðñïñôôñöðîðïïïïòòòðîî÷üòðñîÿO7ôïñðïðñóóñúùïïðñîðîïðïñïïîïîîïïîîííîïñïïîïðíïóñïïïîïððïîîíìíîíîîììîííììîïïíïðìììíëìëìììììììéêëììêêêêêêéêéèèèèèéêêêçæçççééèèëïêêíìíîíïõööøùùù÷õóñïìçñæãáÞÝÜÙÙÙÙØ×ÖÖÕÕÕÔÒØÝÏÏÐÎÖÑÍÊIQW\aiqx~
+ª³ºÁÉÒËËÌÏÏÑÒÓÔÕÕÖ××ØÚÛÝÝÝÜë
+áÛÞàããàçæãäççäææææææçåæçåæææééèèééèèçæôíéëêéééïëëêééééíïéêìíëìíîîñïîü÷öóðïííîîîíîìíïìíôîïîîîïïîîîïïðñññíñððððòòñïòòóñðððïïðððïïïïñïïððïðññûüïððïððññðñññóóôôõõóòòóôôóôôññððððððððïðóñïïïðñðððïññóðïïîîïïñðððîïðñðððë
+Ì¿öîðïñððòñð÷÷ïðññöúïïïïïîóðîììïííîîîíîîíîïîîîñîíïïîïïîðñðïïïîììíííìëíîíììììíîîíìëëêêëìëìêêëëêëééêéêéèèéëêèèèéççççèèéêèæææçèééçèêéééìëìëïññòóóôôñïîìëìèð
+åâàßÝÜÙÝÚ×Ø×Ø×ÖÕÔÓÒÒÐÏÐÐÏÑÏÓÎNTZ`fmt{¶Ò·¿ÅÉÊÊËÍÎáÙÔÔÕÖØÙÙÙØÚÛÜÝáôèûáàßßáààáãååèéæåååæçäåæççæçææçèçæçèèéèéðêèéèèèéìêéèèèèéêéééêëëëëìíïîïó
+øóòîïñîïîííîíìí%úëíïððîíîïððïîòdùïòððñòððððððððððïïðððððîñðïïññððòúúñðïððñññððïðñòöõóõôòòòòñóòòòõðóòîñîðïïïðïîïïððïïïïïðîïîðîïððïðïððïðïððïïüA@óððïñððòñðòñððððñðïïïîðîððîíìîîîîððîïïîîñðòòðïïðïïïïîîïðöòîìîððíììíîìíîíîîíìëìíìêëëìëëëëìëêéêëëéêêééëíêéçèèèççèèçíêçæææèééêèèéèéëëëìîìíïïïñïíìêèèìëçáâáàßÜÛÙÞÛ××××ÙØÖÖÕÔÓÒÑÑÐÐÑÐÓÐQU\bjpw~
+€Ìë»ÃÈÊËÊÌÎÏáÙÓÕÕÕØÚÙØØÙÛÜÝãõàÛÞáßßàÞàâååæèéçåæçäêüææçææççææåäéêçèéééééèééçèêéééééèéêééëëìîììíîììòðñóËëòñïïîîïîñíñîîîñöïíîîîññðïðññî÷ÅñóòñóòñòòñðññïîòôñððòñõðñññððöóñóòòôñññòññòñðññòõõôóòôôòòòòóòñòöòôòðñïïïïïïîððïïïïîîïïððïððïññòñðïïòòïððñññðçëññððñòñðïððñòðïïïðïïïîïîïïñîüîîîïðîíïîîðñðñïïððîïòñïïòæW:ûäîíîïîìíëîììïíîñîíðïîìíìêëììëëêñîìêéëëéêêèééëíèèèíêéêçèéûïæèççççêëèçèçéëéëìëêìííìíììïìæçèèçæáàßÞÜÚÚÚÚÙ×××ÚÚ×ÖÕÕÔÔÓÑÑÑÒÐÐÐUYbiot{«ÀÃÁËÊÌËÌÔÐÐÏÒÔ×ÙØ×ÙÚÙÙÚÝÞÞàãáàßßßàààâãåååçèèäæçäçõêêæçæçæååäãæèçèèéêéèçèêèéêêèééëêéêêêëëìïìíîíëíïïñöwqîòðñóñîðîïïîîíïîîîðïïðòñïïðñòðó
+øðññññññññðñññðîôüòððñóòñòòðôôñòññòñòòòôôòññóóòõóôôó÷öòòòòóññððóóîðòñðïïïððððïððïððñðñòðòððòðóóñðïòòððððññïðóòðñôôôóñòñðòòñññïððïðñîðòññíñðïððïïïîîððððòïñðïïðñððñí ~ìðîïïííîïïîíïîîîííððíîïîîìììíëëîïíëêêëëëêçèëìêèéêñééìèèçòìèêéèçèéèçèéêêîééìêèììëëëéëðíåååäååáààÞÞÜßÝÛÚÚÚÙÚÙÖÕÕÕÕÔÓÒÒÑÑÏÏÑWaluux¢«³ŒÈÑÊËÊÍ×ÒÏÑÒÔÖÚÙÖØÚÛÛÜÜÜÞáààááãâÝàãååäæçåçéæäãäääìíèççèáâååååèêéééêêêéìêêéêëîëéëëêëììííìîíðîììíïïñöEHöòððïïðïïðïîíðïñóñïïïïðððïðôóñóõôôñðõóóôóòñððñòòñðññòñóòøñòóóñòòõõññòôòóôòóóñòõöóòòòóóóóóôóóññòñòõððòññðïððððððððñòñòññóñòòñññññðððïðñññðññððòòñóôóôôóóòñòòòòòððïðïñïððóïîúñððñðïîîîîñïñðñðïðïïîïïðððöóîîîðîïîïôõðîíîííìíîëóýõ÷ìëììêêéìêééêêëëêëìëêééêêêèèèèèèêëéèèéêèççèéêéðééêçèêëêéèèêééîëåääâáãàÞßÞìæÛØÜÛÙØÖÖÖÖÕÔÓÓÒÒÑÒÐÏÐZhp~}|§°¹ÁÆÊÊËËÎÏÐÐÑÒÕÕÖÖØÙÙÚÛÜÛÜÞáßßàâæéøëáåæåæéêêèåâãäääèéèçççûãæçèéèéìéêêêêìêêéìëïëééêëìëéìì
+êîïíìîðñý÷ðïôõóñïîïïïïîïðððîðññïðððñðïðñðððòòññòòòò÷ôñðððñóóññòñóöóññððóòòòòòöôðòóòóóòóóóòöóòóóòññññòòòòôóòóòóñññðïïððððïðððññðñòñññññòñòòñññððïïïïððòóññññðñññòññôóóóòñññòñðòõòðïñòðïòððîîðððïïïïðïððîðñððïðïîïïïîïððíìððíîïîîííï÷ñííïïîìííëìè€_êìëêìëêëééèéêïðéêéêéèèèééèéçèéèêêééëêæçèéççèèççèèçèçéççéèèåíûòãããáâíàÝÜÝëèÛÙØØØ×ÕÔÕÕÕÔÔÔÓÒÑÒÑÑÑ^gs£­µŸÄËÉÊËËÎÏÐÑÓÔÔÕ×ØØÙÚÜÛÜÝãçÞàààáäë7ééæåäíòêæãäææåæååçèçæ
+ÿâèííèæèëéêêêììììêëììëêêêëéòêõêíïíïíïó%õôóññóñðïîîïñïïïïïðôòñðïïðòðïïðñðññòòñôõóóõôõôòòôôññòóóòñòòòñòòôôòòóóññòóôôòóóóôôôõóóòòññóòòòòóòòóôòòññòîïïïðññðððñòòñòóòñíôòòóòòððððñïïïðññòòòðòòöñóòñòòóòòóòðñòòðòööòðññóðéëðñððððïïïïððñðïïðòïðïïïððïðððñðïîïñîïðîïííîï
+ùëíîîììîîíêôíìêëîëììêëëëêñòêêêêééèèêèíêèççæèççòöèèèççèçççèççææèðíéçåæäããäãáâäöâÝÜÞÙØÙÚÚÙØ××ÖÕÔÕÕÔÕÕÕÖÓÕÖÔbhry~©²ºÄÌÒÊËÌÍÏÎÐÒÔÕÕÖÜÛØØÚÝÞÜÞèòßßàááãçµ»§/Þæåëíæçäæèèíëæåæêéçîéåèîîèççèêëêêìëìììëíëëëêììéûñììéìíîíðìíñøññõùîðñïîïðñððòñïðñòóóòððññððñòòòòñóøóÿõóúüõñòóõôóôòòòóññòóôóòòóóôýùó÷÷ôøúóôõöõõóôóñòóòóôóòññòñòòóóòñðóïñðïðñòñðñòóóñòòò	?ôóôöõññðñðñððñòõôñññðòóÿòóóòóóòòñòòñòóñòö÷óòòòñòðK:üîòñððððððñðññðñññðððñññðððððñïðññððïïïððïîîøñìðïððííëø	òìíïíììïììêëêíìëíìíðíìëêçèéèðèèéèêëêêæ+dìéèéèèæééèæççææ
+ãææåååäâââãäëââàáÞæÞÙÚÚØ×ÚÛÖÖÖÕÔÕÙØÛÕÚÙ×ek|
+£­¶ŸÅÊËÍÍÍÏÑÐÑÑÒÔÕ×ÚÚÙÙÚÜÝÝÞßÞáßâãããåÎ
+XÚæäãäççåæçèðìæçíêééæâæèèêêçèéëëëëìëìììììëíîìììíìëîîííííîïîðîððññðõúïðïîñòòïðñññðòóòòóòòñððòóóóóññô÷óöõóõ
+üñóôõõôóóóòòóòôóóó÷öôø
+òicîôöøþõöõôôôôôöõõõôóòóóôôóñòóýòûòññòñïðóòñòñòòï#§òòóõòñòòóòðïñòô÷öñòóðñóüòñóôóóóóòóôóóòñóõóóòóòñòðL<üîòòññðïïðññððññòðññðññðïïðððññðòññòïïîððîíîíîíîïððïîíðöñïîîíìììììëêëëëêêìîîíêéèééééîèéèèéïîëéíøûõéçåçæçééææçéçäãäääéêäâäãàâëòëßÛáìÙÛÙØ×ÚÛÖ××ÕÖØÖ×ÔÔØÔ×io°©²ºÂÉËÌÏÐÏÏÒÑÓÒÕÖÕíéÙÚÚÜÞßßßßßàáãâããäèêèèçìûäçéçäççååçêôëèêêýöçèêêèêëëêëììííìðíììîðíëïñííïîîïíîïîîðîðððñòóõþúïðððóñððñðñòòòññóõôòñññóóóôóññòôóóôòóúøòóõôòñòóôóòóòóôôôôôóôõôô÷ò`iìóòóõóõóõóôõôóóôôóôôóóôôóòòòóõóòðñòòôòñûüññòóôõðõóòóïñòõôóòïðòòóóñô÷óóññòñóõôòòóòòóóõöôóóóóñïòóôïñññòñññðððïðññðñññðññññññõôòòññòñðïññððïðððïîîïîîîïïïïïîìðûõîííìììëëëëéêëëîîîíëîêéêëèìêéëéèêééèçèèèèçæçæçêêèååçååæçæååæçååâãäáàåñçÞÜèàÜÛÙÙØ×ØØÖ××ÖØÛ×ÙÖ×ÕÔ×kp €¯·ŸÄËÌËÍÐÐÓÑÒÖÔÔ×ÓÕÙÚÛÜÝÞÞàâáââáãäææçææåó#âçééåæçäàæéëééêð'ççççéëììëíìíïîëðïíìììììððíîïïðïîïííîíïðïïðòññóòðñðñòðñññòñòñòòóôôòññòóôóòóòòôñóóõôóôõöõôôôôóñòóóôóóôõôôõôóóôóôôóóöÿÿóóòôóóóóóòô÷ôóóòôò
+÷óòóõôóóôõóòóòôóûí!(ðôöò÷ùôóóóññòöõòñïðóóòòòó÷÷ôôóòôôôöóòóòòóò÷üøõôóöûóóöñññòòññññòòðñòñññóñóòññòññôôóòññòøÿðòöñððññïïïîððïïîòóîïïïøîíîíìììëëêêêìíííìëêëëêéèéééêìêèçèçæçèçèééæççèçèæåæåææææåããääããäãáââáßÞßÝéàÜÛÛÛÚÙÙÙ××Ö××ØØÚÛÞÛ××qv
+ªŽ»ÄÉËÌÍÎÐÐÔÓÒÓÖØ××ÖØÜÞÞÝÞààààáâââäãæçäåååææååçééëæåçòêééëëéðêèèéëìíîíîíïððîíïïîíìíîíîðîîïðîîðíîíîïðññðòñòóòòñòóðñóóòóòóóóôóóóóôôôõöóóôôôõôóóöö÷ôôö÷õôôôóòôõõôóôõþõõö÷ôôôôõôõöõïð÷ôóôöôõõôòôõóôóô÷ö÷øõôôööôõöõóóó÷òòóôóòõõôôõó÷ôóõööòòóõôòòòòóóòòóôõ÷øóô÷õóùôòóòóôôóö÷õõó÷Góóðóòòòòóòòóòññòòðñðñôôóóññòòñïðòñðððü5LëòóðððñððñïññóòïïññïñòîïöïîííðììëêëëêìíìëëëééìéêèêééëéêéèçççñöêèçèçæèèèæåäåäåæåääääâáâããâããâáâßßÝÝÝÜÚÛÜÛÚÚØ×ØØÙÙÜÛÙÜàÛ×Ösz€¯ž¿ÆËÌÌÎÑÐÐÒÒÓÓÕ×ØØØØáìèÝçñàââáãâââäååååååæçæææçêíèèé
+fïèêêëêéçèêêëìííííïììîîñïîíîîííîîîñòðîîïïïðîîîðððòñðñòòóòòñòóñòôòóóôóóòóòóóóôôôôôóóôôõõôóôôôõôõöõôôôóöùõõôôôõô÷÷õôõõìïþûóôí%¶©ëôóôôóôõõóóôòòòôööõôõõõööôõþöóò
+ûòóóòòôóóôõôõööõõô÷óòòòóòóôóòòóòòôôõöôôõôôôóóóóóóôôôóóôôóô
+Ióôòóòòóñòòòòõùõñ÷þòòñòôñòñòòóòððñðñòí<:ìñïðïðñòòñðõôôòïïððñóôñîíîîîíïíìëêëêêëëëêêêèéíëêëêêëëêìëèçèã
+,èíéçãþðååååååæçåååäâáãåãâããáàààÞÝÝÞÝÜÚÛÝÛÚÙ×ØÙÙÛäèÜÜÚÙØ×v}©²»ÃÉÌËÍÐÏÑÑÒÔÓÔÕÙÙÙÚÛÛÜßàáçàâááãäââããååæåæçççæççèëçééëëéêêêêêëëêëìíîïííîðíììíííîîîîîíîîîððñðïîïðïïïðððòòððñòóóòòòòóóóôóóôõóôóóóôóóõöôôõõõôôööõôöôõõõø÷õóóóðó÷ôõ÷÷ööõõöõõ÷øñóøøôôðíôôõôõûööõóôõóÿû÷ôûõ÷õ÷÷ôõô÷õôõôôóôõõõôóöøõõõöõ÷õöõõóòóóóôòóôõõõõöööõùõööööõööõõôôõôóôôóôôîõõôõôóôòñòóòùÿðû	óõòòòóòòòñóòðññòóóðþëññðññññññðñöôòðóóïòõôòóïïîïîìîíìëêêêêêééëêééééééëëêêééêéèèèæóüðèêæåäð(ëçäçääåòíäääææâêòâãáááààáÞÞÜÝÜÛÚÜÛÛÛÚÙÙÛÚßðíÜáÛÙ×Ö¥¯·¿ÇÌÐÎÎÏÑÑÓÓÔÔÕÖÚÛÚÚÜÝáãÞÞááäâäéæåäåååæåæçéèçèèèêïééèêïêêëëëêëìììííñõðííîïïíîëçïñðïïîíîððïðððïðñðñòñððòòðñòòôôôóóóôôôõõõöøöõöôôôõ÷ø÷öõ÷÷÷õö÷ööõöõþö÷õôóúñôöûþ÷õööööö	ú÷õööõõýõööö÷÷øööôôõôöùùø÷öøø÷øö÷öõôóõóú÷ôôõõõöõôõõõõôü
+ôöõööõôõõõöõõöõôôôõõ÷÷ùúøøø÷öõÿúõööôõöôóóôõôõõõóóôóòòóóòóõÿÿòòñóóôòñòòñòòóòðòñòóòòóòòññðòòððïïïðòñðïôõïïòòïðïôïðîëïìëêéêêéêêèééèèéèççêêêéìéèéééççæãæççæãäåèçåãåäääèæääãääàïÿáááááÞàáßÝÞßÜÜÜÜÛÚÚÚÙØÙÚÞááÚÜÚÙÙØ¡«²ŒÄÉÎÐÏÏÏÐÑÒÒÕ×Ö×ÙÙÚÛÝßàààáàâåáãäñæååæçææææçççèèèêðêééêîêììëêêêìíìëëîòðìîîïïïï-ûîôñïïîïñïïððïïðññðòñïðïññòòóóòóôôôôöõöøööú÷õõöõõøþúõ÷÷÷÷÷úûõõöõõöüôöôôóø
+òõöùûöõööõ÷õÿüøõõõõöõòò÷õö÷øñòùöõõõôõõõõõööö÷öõõõõôóôóõöõôô÷ö÷öôöõóõõõùöôõõôôóõôôóôõôôôõ÷øùúúúúú÷÷ûöôõôõôóòó÷õõöôòóòóòòòóòóóòñññòõòòôñòññòóóóòñòñññòóóñññððôðíííîíîïðððððïîðòïíðôïðîìïîììëêééçèééëêèéèççêíèèìéêêéççççæåæçæäããååäåææåããääåäããâæêâàááàáóåáâàÞÜÜÜÛÛÛÚÚÙÙÚÛÝÝÛÙÛØÙÙÙŠŽŒ¿ÆËÍÎÎÎÎÐÐÑÐÕÖÖØ×ØÙÛÜÜÞßßààáâââæõçäçåéæççææçççèèéêêèéêëêêëëëêêììëëìîíìíïíðîðïæþóðïïðïïðñðïðñòñóòñðïðñòòóòòôôõ÷õ÷÷÷ûøôöõ÷õööö÷üùõö÷÷ö÷ýüõõõõöõõòõöù÷ôóóóòõõõö÷õôööõ÷ö÷øøöôôõõööõõöö÷ô	÷âòõõöõôõöø÷ö÷öööõõôõóôóöôõõôôõö÷öóò.óõöõööõõôöõööõîIJööö÷öõ÷úýÿûøôõ÷öõôõ 6ôôõõ÷óôóóòóôòóôóõõóóóòõúôóôóôóòõóòôóôóòññòòóòïïññôðîïïïííïññññðïðòôñïñðïòïîùòîííëéèö÷çîòêëêéêéêìéêêéêêèçèèçææææçåãåææçæååååääååääääãâäääãàßåâàåàÝÝÝÜÜÝÜÛÛÛÚÝßãßàÜÜÜÜÚÙ
+¢ª¶¿ÂÉÌÌÍÏÒÐÒÒÒÿÚÕ××ÙÙÝÝÜÝÝßßßàááââãææåæäååéèåæççèèèèéëèêíëêéêëêêìêëìëïòíìîïïîððï
+öî	÷îïððïïðòðððñòñôòóòóóñòòòòóôôöø÷÷ùùúúüøøøöýúõôôõõööõöø÷öööööõõööøù÷õôôõöôõö÷ø÷÷ö÷÷ööö÷ööõõöõööõööööõ
+ôçôööõöööõõ÷÷÷ö÷öööõõöõôõõööõõøûöò/ôø÷øõööøõö÷øøøöÿýõö÷øùûüþùöõõööôúøýõõöööôöõôóóóöõóóóôôóõöôóôõôùúõôôóñòôóòñóóôóóüöòðñðñòðîíîðððððïïññðïïîðòïîûòðíìëêç
+çîñêíêéëééèêêëëêéèççççççææçæäååååååääåãããääããáßãåãéæàßÞÞÞÝÞÞÝÜàßÜÛÚÛÛÛÜÜÜÜÜÚÚÝàÚÚŠ°žÀÇÌÍÍÎÐÓÔÔÒÕóÚÖ××ÚÚáàÝáàãèâáââããåãçèæåææçååçèèèéèèêíéêëëëëêëìêëëììëììîïîïîíîðòïðð÷óðïððõõððòôñððóòðòòñùþõòòóóõöõõöøúûþþ~)ýöööþ÷÷öö÷÷÷öö÷÷÷÷ö÷÷öö÷õ÷õôöõôõööõ÷öøø÷÷øøöõôöööööùú÷öõöùûô÷þ21ÿ÷ööööööôþÿõ÷øøûöööõöööõõõö÷öõõööõõûÿõööøõööööõöö÷öõóõöö÷ùú
+1PQ/þøöôôõööó
+7ùõöôõööõôôóóòóóòóóóóòòóôóóòôôòôóòòþõ÷õòòóóñûúñîîïðòðîííïðïððïïðñðïîíððïíííïîìëêèúýéêéêêêééèèçèééëêèèëëèçæææçæææääåäåääãäâããããããáßããâæäáâßÞßÞßÞÝÝßÞÛÛÙÚÛÜÝÜÛÜÝÛÛßÝÛÛ©³ŒÃÊÌÍÎÎÐÑÕÓÔÕÙ×ÙØØÙÚÞÞÞáááäâáâáäãääåææçìéæææççèéêééëîéééëìéL
+èìììëëìííííîïîïððððñï÷îðððïïïðððôñññòïïññ÷øóóòòóõöõöøùþ	
+
+ýTÿóöø÷øø÷÷øøùùö÷ö÷÷÷õö÷÷öõõôôõööõö÷÷õööù÷öö÷÷ööõöõõööúû÷õööøÿúøòòøù÷öööööõ÷ù÷÷øúÿ÷öõõööôöööööùøöõõõöõõöõö÷÷÷öö÷ö÷öö÷÷÷öö÷øúþ
+$Vžÿ©Aúööõôõõö÷üüöøö÷ôööôôõôôõôóóôõôôøùôõóôóõûô#óóóìWDûóôòòôòñôüùòïïïóòðïíïððññððññòóñïîïïôïîìììíîìêííéëìêèêêçéèéèéèêêèèìòòêæçæçææçåææåæãåääãããããããââäãâãâáàßßÞßßÞÞßÞÜÜÛÚÛÜÜÜÛÜßÞÛÚÜÝÚÜ£­¶ÀÇÊÌÎÏÏÐÑÓÓÔÔÓ×ÙØÚâÞÜßÞßàààààââããääãääåçæçëêçèéêêéêìîèéëíêêõììììíîïîííîîîîïïìñððïñïòòñððððððððñðñóÿ
+ôòñññòòòõöõööøû
+_Hüüûñö÷ö÷÷÷÷øùø÷÷ø÷÷öö÷÷÷ö÷öööõöõö÷÷øùùø÷ùø÷öö÷öööøøö÷÷÷ö÷÷÷÷ö%ýø÷ö÷øø÷÷ø÷÷öøúø÷øùú÷öø÷÷öõö÷ö÷÷øø÷øöõöøùúüú÷ùøö÷÷÷øøøøøøøøøúþZÙWv+
+þüøöõõõ÷÷õöõö÷ööõõõöûôôõõõõõôõõù÷÷ôõöõöùöõôôñ15òôòóóòñòñòòðïïòòïïîïññññððððñòóðñïïòóðíìììîîìëëëìëêéêêæééêéêééêééçîóëçèççæåçèçæåæäåääæäãääãáâããââãááßßÞÞÞÝÞßÞÝÜÜÝÜÛÜÜÜÜÞÞÝÜÜÝßÛÜšª³»ÃÊÌÍÐÒÑÑÒÔÔÔÕÔ×ØÙÛàÞÝßÞÞßáåëéääãääåääåæççæïïçéééêçæìîêéëêìììíííííîðñðîîííïððòðóðñòñðñòóñðú÷ðððñññø
+ðôõôóóõõõöýÿþW[×
+þûöùùøù÷÷øøøøøøøø÷ù÷øøøøøøøúø÷÷÷÷øùûüû÷ø÷øö÷÷ö÷öøüùøø÷öøùøøöûö÷øøùúøùúù÷ùúùùúùùùù÷ùùû÷÷÷÷øúùøùùù÷	úùûüúùøøùø÷ùùùøøøøùúúûÿ	'rÍÑv1úùøöö÷÷øøööö÷÷÷öõõõ÷÷öö÷õö÷õ÷öçµ	óöõõöööôööõôõöôóõöôóôóòòòòòóòïîîïðïïðôùöñòòññòóòòòñððññïîììíëêëëëíêéêêéêééëééèèèééèçççæççææåæèçèæääããåèÛÚääèôõãááââáàßßÞÞÞÞÞÞÝÝÝÝÜÜÛÛÛÛÜßÝÛÜÜÝÝÛÛò¯žÀÇÌÏÏÑÓÓÓÕÕÕÖ×ÞÝÚÚÚÛÜÝÞßßâåæêéåääåäæçåæçèèæêëèêêä(­ièõîëëëîíííííððíîïðïñôïïðòñðññðñðòóóóóòôõòóòòóóôô
+ùóôöõóôöööô*üdßê
+þúúúùøùøøùøøùøøøùúùøöøùú÷øøùøøø÷÷÷ö÷øúøø÷øö÷ööøö÷úù÷øù÷øùùùøøôøùùùúúøùùùùúúùùùøùúú÷÷øúø÷÷öøùùúùøø÷ÿøøùùùùùøúùøøøúø÷÷øøüþû?V> þù÷÷÷÷÷÷ö÷÷öö÷õõõôöõ÷õôöõõöøõõöõ!0ýöõôõöôöôôõôôôöõóóõóô÷óñòóðñòòññîîîîññý
+ðôóòòòòòóñòïðïïîíìììêëëêéêêêìëêìêêëéêéèçèéééçæææçææçååèèçããâãäâsyþÞìãàããáááßßßâßßßÞÝÝÝÞÝÝÝÝÜÜÝÞÝÚÝÝÝÝÝÛð ²»ÄËÏÐÐÐÒÒÓÔÔÕ××ßÞÚÙÚÜÝÝÞàáãäââããåäæëçèçææçççæçéêëè]8êðíêêìîìëìííïíìíîïîïðïïïðñïîòñðñððòòññððñóóññóòóòðóôóòõôôõôùö&F÷ü*r=
+ýùø÷øø÷øøøøúûö÷øøùùú÷÷öø÷öö÷÷÷öööõö÷÷ö÷øøú÷÷÷÷úø÷÷ööøøøøøùøøù÷ùûøøø÷øøùúûùøùø÷ùøøøø÷÷÷ø÷øøøøøùøøùø÷÷øøøùúúúùùüúùùúúùøùøþûÿýûúø÷÷÷ö÷ööøøöö÷÷÷õöö÷öôöööýúõöøõôø÷öôö÷ööõö÷õöö÷÷ô÷øûõôôóóóóôóýôñðòôóô
+ïóóòóóòòóôôòòðïïîííëêììëëëêëìêëéêêééééèèèçííèæçèççæçåæåäåæäãäãßòÝèòòããåäâââáààäáßßãáÞÞÝÞÞÞÝÝÝÝÞÝÜÝÞÝßÞÜ¯¶ŸÇÎÐÐÐÐÑÒÒÓÕÖÖØØÙÚÛÛÜàãâßàáâáâãääååìæççèççèçæçéêìíëèéìëîëëëììîíííïííííîïïïïïññòñïñññòðñòòññññóõñòñóóóòóóôôóôóõõôöù÷ü
+
+þýúøùùùøúûùùø÷÷÷ùøøùöø÷÷ø÷ö÷øùøö÷÷öö÷øøøøþùøüúûúøøøøøøùùøø÷÷ùøúúøøùøøùúûù÷øûüýûùùúøùøùúúùùùúùùùúûùùúúúúúýüüüüüûüüûüûûúúþþüÿþüüúùùøøùøøø÷÷øøùú÷ø÷÷÷û÷øøùø
+	ö÷÷÷÷÷ø÷÷ý÷÷÷õ÷øö÷÷ôÿó÷ööôóóôóóòôõòòòóòðòóóóóôôôôööööôúõññïíììììììëëêëìëíêêëêêééêêéçíîèççèçèåçæèåååèæãäåç<KãäââããääããââáàáàààæãÞßßßÞÝÝÝÝÞßßßÝÞÞßßÞŠ±ºÄÌÐÐÑÐÑÓÔÔÕ×Ù×ØØÚÜÛÜÝâçãàáââãáÛåäæèçæèéèèèèèèéêíêæëëêìíðìììíîîííîîïïïíïòïïððòòóòðñòòòóóòòóòòòóôòòòóõõõóôóôôôö÷ööøûûùûþþýüúùúùùøùûù÷øøøùùúøùûøøøøúø÷øøúù÷úû÷÷øúúþ÷øùùùøùøùùøùùùùùùùøøøùùúùùúùùùúúúüú
+øùúûùúùûúüøýüûúúûûüûûüýüüþÿüýúþüüýýüüüüûûûýÿþüûý÷úùùùùùùùùøúýûùûøø÷÷øûûøø÷÷ùú1/øùø÷ùøúøù÷÷ú
+øõöøöûü÷õõóóõóòôôõôôõóôõôóôôõöôôöö÷úúøøöõóóóñïðîíîîîííëêëìêíêêêëîìéèéêèèèéèçèèçèçæçäååçåääåçàÝãåääãââãããåâáàâáàáàáßÞßßßÞÝÝßÞßßàÞÝßàààÞ«µŸÆÎÒÒÒÒÔÔÕÖÕÑØÞäÞÛÜÜÞßàáááâãâáý/ãåçèæèèêèééèèéêëâUÖLæëììïëíîïîíííîîîîííðóòðððññòññïõ÷óòòòòôõòòóóñóòóô÷ùóôõôôôõõõ÷øöùýùüüüýüûüüùùûúùúûúùøùûúúùùüúùøûúøøøùùøø÷öûü÷ùùúùúøøùøùùùøùùøùúùúúøùùùùúùúûùùùùúúúøPFò
+øúüúùùúúùúùýúúúûüüûüüüûþþûþ,
+îõýýûûûûúûúüþýýüüúÿ×Aû÷úùùùùùøúûùùùø÷öøø÷ùøø÷÷÷÷÷
+
+ùø÷÷÷÷÷÷÷û÷ý4
+÷öõõõôôôôõýóóòôóôõ÷óóóôôñòôóòóóöøúþø÷õõðñðïîëìíììêééëëêèêêêèééééççèèéëêçåæçæèåææåäåäääääåãâãäåãââáââãåâáßáàáàßÞÞßßÞÝÝÝÝßßßßÝÝÝÞßàÞÝ¯¹ÃÄÈÐÒÑÓÖÔÖÕÚúÙäñäÝÜÝàÞÞßààâãâÞ\ãåçäæçççèêêèèèéêàdóSäêìëðììéîíìîðîíïðîíïñðððïðñòññöññòòòóóòñôóòòóòóõôóôóôôõõõõõ÷÷øùøúüûûúúýüúúüúùúúùøúùùøøøùùúøù
+üøøûüùøøøøøùùøøøùøùù÷÷ùùùùùùøùûüüùùúùùúúøÿøùùùúüüù}ïøøûüþúùúùúúùúýýùúúüýüûûúüüýýûý=X	ûüûûûúûüûüüüüûúüúÿÎAûøùùùùùúùùøö÷ùø÷÷øøööøúøùøøù÷ö÷÷øøø÷ùú÷øûøû
+þ÷÷ööööööõõóóõøôöõôóôòô÷ôôôóóôöøüû÷ôòòððïîííñ÷òéêëìêêìòìêêééíêççéêêèæçççåæææååäæåääääããããääââââââáâáâßàßáàßßßàßÞÞÞÞÞÞààÜÞÞÞÞÝßÞÞ³ŒÃ âÏÒÓÓÔÕÔäFÞØÙÚÞÝÝÝÝÞßááâãâãçëçäçèçæçççèéééèèéìñôòêêìëðììéìííïðîíðñðïðòïïðïðððñðûòòñòññòòòôöòúòòôóòñóóöõôóôõõõö÷ööøùùûúùùúúúúùúúÿûùùù÷
+'ùûùúùøùøøùùùøø÷øùùüúøúùøùùùùüúøúúûú÷øúùùùùûûúùùüüûúûúúúúúõöüúúúûûüûüùüûúúûùúúúûûûûûûüüüÿýýýû(ºùýýûûûûüüüûúûúùúúþøúûúüþüùùùúúþûø÷÷÷ùù÷øùúùùùøùùùøøøûùùø÷øö÷÷õ÷ø÷øöõöööôóùþóóõýõõôóóòòóôôôóôõöúÿ'¥ýaüöóòñðîïîìëëëééêéìñêêèééìééêèççççèçåæççæååçãââåäããããâãææäââááâââááâáààááàßßßßßßßâàáççò
+ëáÞÞÞßßß·À¹ñ
+ÊÒÓÕÕÖÖØéÛÜÛÞÝÝÞÝßááãäâãããåêæåçìéæçèèèééêëëëëëìïëêëêîìëììîîîîîíîððððòòòðððïïðñððòóòññòñòòóóñûñóúóôùöôöõõôõôôõööõö÷úøùøùøùûüúùùöøúùùùúøùúùùøý÷üøúúøøø÷øúøùúúýúøùùúúúúùúúûûúúûüûúùùú	
+ÿúùùýýùùûûûûûüûüüýþûûüûúúúúùûûûûûüüûûüþþþýþY?	üýýûûûüýýüúüþûúûûüùùûûþÿüûûúûûÿû÷øùÿúøúúùùúúúùøøùúùûÿúøöøøøýûýùøø÷ööö÷öôôóòóõõöúôòôõôôóóóõõó÷ûøûýdÕøõòòðùíîíììëêëëëêêìêììíìêêëëêêèèééèæèçæåæåæäæäääåääãòôäãããâáãçâáäãááäãäâáááàßààßìí
+
+ëâàààáàŒÅÍîöÜÓÒÓÔÔÖÙØÖØÛÚÝÜÜÞÞßâââãããäåäåèæçæåææçèéèèéìïíéíðìíðëëîïëìíîííïïîïñïïïðôôññðìïïòññõôòòóôóôòðñóøûóôøóõùøõôöõõöôõöõö÷÷öùûùùùùùúýúùøT2óùùùúûüøøúýüüûüøýüúùúûúùùùùûúùúûûùùøøûþþûùúûü
+ùûúûúûúûÿ
+þúúùüúûüüüýþýüüüýüýþüúúúúûûüýýüýýüýþþþÿùùÿþýýüüýýýûûüýÿüýúüúûûûûúùûýüúûüûýþüùúûúûúúúüüûüûùùúûûúøûúøúùúüûûøøúù÷÷÷÷÷ööõõöõõóñôôôöõôóóôõõôõ÷÷ýU^ä®øôòòðõñíïïñòíëêêêêêééîìéêéééêëêèæèéèèççæååçåææéååæäãäæåãååäáâãæâáááàáçããâààáààáâåòéû^
+óæáßßàßÁÈÎÑÒÓÖØÖÖ××ØÙÙÚÜÛàÞÞßßááâãâäåææèëíèçéçççèèéèééêëìëêíìôëìíñîíîîîîðïïñðïïïòõñññô
+ñïòòòöôòóôôõõóòôöõòôôôô÷ôöõôõöõöõõöõö÷÷öùúùúùùùúûùùøf?óúùùúúúúûüýýùúûúüÿúúúüûûûûùúûüýûúüúúûûüýûûúüùúúüýýüüüüüûüûþþüüýýýþýÿüýýýûýýüûüüüþýüþþýþþÿþÿýÿþþþýÿþþýûýýüüüüþûûýÿþýùüûûüúúûûûûüýûúúúûúûúûüúûûþýûûûûûüûûùúúúùúùûøùø÷øûýùöø÷÷ø÷öõõõõõòô÷õõôóòõõôôóôö÷ú"]r,üöôññðîîíííîíìëéêêêêêíêðêèéèèêèèèççêéçææåæææçåèèååäãåääååäâââââãâãââãããàááááááàáïðãùááåèåæåãâáÃËÐÑÒÓÔÕÕÕ×ÚØÙÙÛÛÝÝßàßàáâããããåååæéåæçêéêéééêéêêéìîìëìëôëìëòïîîïîîîïððïïððñòððïôñõóóôóòòóóóôôóóôôôõóóôõ÷ôôôõõõõõôõõö÷õ÷öøøúýúúùúúùùù
+øúùùøüúùûúùøùùúúþÿýûûûûüúùùúúûüüúüûúúúüüûûûûûüüúúûüúûýûûüýûúüýýüýþþýýüýÿþýýýüüþýþýüýþþýþþÿýþþÿþþÿþýýüüüüûüýýýþûýýýýþûüüûûúúûúûüûûúúüûûúûûûýüýüûúúûüüúúûúùøùùùúùùûûøøúøö÷ö÷øõõõõôõôòó÷ôõóóóõôóôôõúþúüÿþþ÷õòòïñóïìíîíëìêêëìééèêéìèèéèçéèæèçæçååååäæåäææçèæäããäâãäââãäãâáããäãââåâàáàááàààßæõðàìáßäáàèëçãáÈËÐÑÒÓÕÖÕÖØßÙÙÙÝÛÜÝÞßààáââäåãäãæéäæææçêèèèçêéêêéêììêìëêéìììóîíìííîîîïïîðñððñññïîìïøöñóóòññòóóõôóòóóõö÷óóôõôôõõõõôõõõ÷÷õùü÷÷ùûùùøùùøøùúööúùø÷ýùùùùùøúùùüúûûúúùúûúûûúúúüüþüþùûûúûûûûûýþýüüýüýüûûüûúüýþþþþýýýþþþüþþþýýûûûûþýüüüÿÿþýÿÿÿýþüþþýüýýüÿýýýüýÿýÿþ%úüûûûûûûüýüüüüûúüüûûþüýüýþüÿþûüüúûûúúùúùúùúùüýù÷÷öùùööþôõõõööøôöôõõôôõõôôõ÷üùùúûúøöôòòðñóïíïïîíììììîêêêìêééíêéééèéèëîéçæêõæçæåååççæååæçæäãäåãäçãâãäæåãäíåàááåêæàààßÞßàÞßààààãããââÈÏÕÕÒÓÖÖÕÖÙÛÙÚÚßÝÝÞßÞààáâãäääãäåçææåçææééèééèéêêéóùííìììîîñ÷íííîïîïïðò÷õðññòòñïîïðð÷òïñòòòóôóõõòòóóôø÷óôõõôôñô÷öôõõ÷ø÷øúüø÷øø÷ùùøøøøùùúûûùøø
+÷úúùùúùùùúúùûûúüûúüûûûûûûýüþü
+
+þúüýþýûüø?
+üýýþþþþýýýüýþ
+	ýýþþÿÿÿþþýþþÿþýýüýÿÿÿÿÿÿþýýþþþþþÿþþþþÿýÿ4üüýüüýýûþÿýüýüýýýýýþýýþýûûüüûúúûúûúúúùúûúúúø÷úú÷öþýöõöööüöõõõõõõôôôõö÷øûþùûùöõöõõòòòñððñðîíììíìììëìëíêêêìêëêëéééìóïççìøççæåååæçæåéïëæåãåçåââãæââããããæãáâáååââááàààáÞÞàßàáâàßàâÑÓÓÓÖØÕÕ×ÙÚÙÚÙÞÞÝÝÞßßààâãäääããååæèíóéèèèêëêéèêëêëíðíëíîíîîòñíìïðñððóòøðóóòñððîïðòôñïòóôóôõôôóóôôóôôõøööõôô÷øõõö÷÷øúùøúùûúùùúúùúúùùúûûúùúûûùúûûúúúúûúúûþýüüüüüýüûýþþüýüýþüýüþþüýüýþþþþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿ
+ÿÿþþÿþþþýýýþþþÿÿýþûüüýüþýüüüýýþüüýýþýýþüýýþþýýýýýüûüüûûúúúûúùúùùúúúùø÷÷øö
+öõööóøõöööôôôóóôôôõõõö÷÷öôöôóóòññðïïïïíìììììíéêëëììêêêéééêëéèéêéçæçêååææåäåæååë:ÝããäåäâáâæããáâáâáâààßááàßßààßâààÞÝàßååàßßàÐÒÒÔÖÖÕ××ØÚÚÛÛÞÜÞÞààßááâããååååæåäì(sòéèèéëêêêêêêëììíîïðîíïíñîïïñññòóòñðñòóóóòòññð÷óöñïôõóø÷ôôôóôôõóôõ÷þþ÷öõõ*
+ó÷÷ö÷ø÷øù÷øúùýûúøùúúûûúùúúúúúúúùúüúúúúùûüûúûüþþüûýýûüÿþüûüûýýýüýüüýýþþýú
+ÿýýýÿÿýýÿÿÿþÿþÿþÿýÿþýýÿ
+ÿÿýþÿÿþýýýýýþþþÿþÿþþýýýþüüüýýýþþüûüýþýþýüþýþþþþýþþýþýûýþúûúûûüøúûùùùùýû÷ö÷ø÷ýõõôøõôöõöõôôóôôóóôôõõôóóóõòòññðððïîííìììììíìëêêëéìééêïìéêëéèèæææææææååçææææåääöâãâãâââááââááââââáàáäãàáâàßßßáßßßÞàßæäàààßÒÒÒÕÕÔÖ×ØØÙÙÚÜÝÞßÝàáààáâããããäæåååçïõèçéèëéêéééééêìììíîîîîìíðñðíïðòòððñððððòôòòñðñ
+ôôñðòóòóôôóóôôóôõõô÷õöö÷öõööö÷ø÷÷ùø÷ùøúùùùøùùúúùùúûûûûøòöúûùùúøùúûúûûûüýýüüýûúþûûüüüÿþýþþþýýýþþþÿþþþÿþþÿÿÿþÿþþþÿÿþÿþÿÿÿÿþýýýÿÿÿþþÿÿÿÿÿýýýýýýýýüýþþüþþýýþÿÿÿþþþÿÿþþýýþÿýûùûþüúúúùúùùúù÷÷÷øøöõööö÷
+öõöõõõööôôôõöõôóõôõöôôòòñññðððïíïïìíîíìììëëìêììðìðíêêëêéèçèèççèèçêçèèçææåäâãæåãäããââáâáââäãåââáâåäââááàÞßâàááààÞæâÞããáÔÓÓÕÔßåØØÙÚÚÜâåßßÞáââââããããääåååæéæåèèèéêêìêêìëéëëëìíîïîííîîòïïððïðñòòññòòóõôóñïñùôòòòóóõöõôôõôôöõõööõõôööõöö÷ø÷öøø÷÷÷øù÷ùùùùûüùùùùúúùûüüüù=
+ùúûúùùüüûúüüüüüþþýýüþþÿþýýþýüÿÿÿþþþÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿþ
+ÿÿÿþÿÿÿþÿûûýûüüûûúûüûúùùúù÷øø÷öøûõôööùöö÷ööööõ÷øõôóôôõøõôóòòñòñððñðñðíîîíííëììëìí÷ûïìëêêêéêêèèçéëéèèéééèçæèçææåæåååääãããäâäääåæåâãããääâáááààáßàßáàßâãâââáÓÓÕÖÖÜÞÙÙÛÜÜÝßáßàáááâââãääåæååççæèêèèîéêìïñïìíëÿëíîîõðððñïôðïññðññòòñòôõôóôôôóòöõôóô÷öõööõõöõö÷øöø÷ö÷ö÷÷÷ø÷ùûù÷úûøøøøùúùúûýúùúûúúûûûúûûûö$x=úýýý
+þýþþüüùúýüþÿþÿýþÿÿþýÿýýþÿÿ(ÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿýüýüûüýýýýüýþüûûúùøø÷÷ö÷ù÷÷ù÷÷öö÷öö÷øöõôõöóòóóîðòóòóðñðïðñðóòîíëìíìëëëêêìôõíëêéêêéêêèççéêççèèééçççèæåçèæåæåãåäãââáåäããäãâäãáãäãâááàààààààáààáâááâÓÓÕ×××ØÚÚÛÜÝÞÞààááâáäãâäåææææçççèèèéêëêëìëëðîííððíîîïïóðññññõñðñòòòòòóóòòóóóôõôõòõôõøôõõöööõööööõö÷ø÷ö÷÷õöø÷÷ùøøø÷øøøøùùûúúûýúûûüüûûüüüüûüûýþûh	üüþüûýþþýþþþþüýþþþþþÿÿÿÿÿJiÿÿÿ
+ÿþÿÿÿÿÿþþþþþüÿýûþþüýüüûùøùúüø÷ø÷ö÷üøõö÷õõöøøöõôõöôóôùýòñòñððõóñðîóôîìëëëìëëëêêëêéêëëééêéèéêèèèççèççèèæçççæäëëææååäåäãåéáãâââããâãâåäâääáààáààâááßáààáââãÔÕÙÚ××ÙÚÚÛÜÞÞÞßááâàáãâãååççåææææçççèêèéêëêíîìëîíëìíîîïïðððððôðòòñòññ÷þøÿóôôõûöóôöóó÷ôõöõööööö÷øõøýõ÷õõúööøøùùø÷÷÷øøøøùùûùúúûüûûüüûüüûûûüýþýúüüû
+úüüü&úþþþýþþýþýýþþýþÿÿÿÿÿþþÿÿ"À>ÿ	
+ÿÿþýýüüýüþýýþüýýýüûúùú÷ùùøøø÷øøøúøóò÷øööõõõôö÷Zòñññðð	ÿòôôïíïîííëíëìëêìëêëëìëëêééèéëèéééèéíéçèçççççæêéæçåæåäääæèãäâããåäããâéçâãâââââáãâââáââââããâÕÖÙÙ×ØÙÚÙÚÜÝÞÞÞáâááâââããäåååæææçèèèéëêêéêêìíìíîîííîîîïïñðïñðóòòñòòòòóõò*ôóõö÷õööôóö÷÷÷÷ö÷÷ø÷ö÷øõ÷öø÷÷üù÷÷øøùúùùøøø÷ùúúûþúûûýüüüüüüüüýüûüüýþýýÿÿþõýýýüýýûýÿþþÿþþÿÿýþþþþÿ0°ñÿ		=
+ÿþþÿÿþþÿÿÿÿüüýûûûù÷øùøùøüùøù
+üö÷÷÷÷öõóù
+ôòóòóòñõûõîððïîììíîìëìíëìììëëêììéêêééêêçéîëèèèçèçéèæçèçæèæäåääåääããææääããæåããââããááãáââáâáãããããÖ××ØÚÚÚÛÛÜÞÞààáâãâãääåäääååçèæçéêéèêëëìëìïîîðïîîïïïïðòòñððñòôóóòóóóóôôôü÷õö÷÷õ÷öööÿ
+üö÷÷øøùúùùùøúûøùù-ùüûúûúúùùùùúúúúú	ûûýûýýýýüûýþýüüüýþþÿÿþÿÿÿÿÿÿÿÿÿÿþþÿ	
+ÿýþÿÿþþÿþþþþýÿÿúùúùùøùøøûûøøóiÞiõ÷öõöö÷õóòñòôòóñóòññðïòóðîîîîíííïëëêëêëëìêêêîíèêêêéêêéééèèèçççäåææèéâÜåèååäãäãâæãååââããââááááââßàááàâáàáâââãã×ØÙÚÛÜÜÜÝÞßàâááâäæåäåææååææèéèéêëêëíêëëìíïïíïîíîððïïðòôðòñññõôòõôóôóôôôóóõõ÷øö÷öö÷üúýù÷øøøøùùø÷øùùøùùùûúúýûúúúùøøùùùûüúùúúüúüüûûûûûüüûüûüüüýýýÿþþþþÿýþÿþþÿþþÿÿþÿÿÿþÿ#
+	ý*j
+ÿþþþÿÿÿþýýüüûùúúúøûøøüù÷ùûw&éõôõõöøôóôòóòðñòòòòññððñðííííììëììëëêêêëëêêêêéèéëèéëêêèèçèçççèú÷äçâ4)äçåãâãâäçããäâàâãâáàâèéâáßáááßââáããâââãÖ×ØÙÚÛÜÜÝÞÞßáááââæåãääååæçææéìééìëëìêëëëììíííííðîêððïðòñðððïòõòóóóóóôôôõôôôöööúöö÷þø÷÷øþÿù÷÷ö÷÷÷øöøùøøùøùùøùøøùùùùûú÷øùúüúùøûùúüûúúûûüüüûûþþýýþÿýýþþþþþþþÿÿþÿþþÿÿÿÿÿÿÿ	
+!				
+%!/
+þýýþûüûûúúùúüúùùþÿú÷öõôõõøÿüùóóôòúõòòòóòðïïîíîîíëëìïììëêëëêììêêêèêìêééééèééèèçèèSáèÜ}sßæåäããããäããßJ&éáâáàãíîâáßáááááäãåæäãâãÕØÙÙÙÚÜÜÝÞÞßßáâáâáäääääæçæææéìééìëêëëëìëìììíîííð;f
+òñññððððññõóñóôòôõôôöõôôö÷øùö÷÷ùøùùùýüþýùøùøøùùúøùøøøùúûùùùùûüûúûýýúûûüýýüûûûüýüûûüýýýýÿþþÿÿÿÿÿÿþÿÿÿÿþþÿþÿþ
+			
+
+
+
+					
+		
+	
+	
+ÿÿþüþþüúùûùùøöøúúúùø÷öö÷öõöûøóõôóùôóóóóñðïïïîíìíëììïëíìëìëêêêêêîîèéêééééèééçéééèî+
+ãèå#h*ãååæäããââäãÞ^6êàâáàâååâààáááââäãååäããäÖØÚÚÚÛÜÝÞßßààããâóìãåæææææèééçééêêéêêëëìíìíîïíîñ>pôðððïðññññõóõõôòóôôôõ÷õõö÷øø÷øøùøùùúøúûúùúûùøùúúøøùøùüúúúúûûýýûûû	øûüúûüüúúûýûûûûûûýýýþþÿþ&$#
+ÿÿþÿÿÿÿ
+
+
+
+		
+
+
+
+				
+
+
+
+
+
+
+
+
+							
+
+							
+	
+	
+
+ÿþýþûúùùùúø÷øøøø÷÷÷ù&ôöõôõõõõóóññòõóòñððððííîëìëíìëíìëëììëëëéþêêêééêëèçèèéêéêçãæèçéïëáæååååäãâãåãåàÞàââáââáàààààáßáãäãäãâããä×ØÙÚÜÝÝÞßßààáâáãþñãåæéèææèêêèééììëêëííñîîîîîïñòýÿóððññññøòòöó÷öýùôôõöööööõø÷ùùøúûùúúûûúúúúúúúùúúúùüúúùûûúûûüýýüúúûýÿûûüýüþýüùK#üüüüýþþýýýþÿÿÿ>ÿ6ú		
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+					
+	
+
+										
+
+
+
+		
+	ÿþþýýýûúúøùøø÷ö÷ö÷÷ö÷ø
+ôôôóóóòóòòòòðòóòøöððîíðòîííìëëííëìììëêñðóÿøíêêèéêéèèéëèçëéèèèçççååæååæèæâãäääããâáåäáâááààáàßáìááâãàáèæãåØÙÚÛÝÞÞÞÞÞááâââãäãæèææëéæçèçèééêìíìììíîñîîííìïðððïñññòõñðñ÷ôòõôöôýúóôö÷õö÷÷öùøúùÿûúùúúûûùøýÿùùùùúúúúúúùúûûüûûûúûûùûùûûüúýûûûø2
+ÿûüüýþüüüýýýÿÿ %!	ÿÿÿÿÿ	
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+@7
+
+
+
+
+
+
+	
+
+
+
+		
+
+
+
+
+
+
+
+
+
+
+!G
+
+
+
+
+		
+
+
+
+		
+	ÿþüûúúûùøùúøø÷ö÷÷÷ùø÷÷õõöôôôôôòóóöõóôõóòòðïñóôðîïíìííììííììëñòëíñîëëéëêêéêéìêèîðëçêéèèçæææååêæããåãåãâãâêçàáâââáàáàäöâáâàïïêåæ×ÚÛÜÝÝÞÞÝÞßáâäâãåãææææçççèççèèéëééëëêëìëííììíîïïïïðñññóñïñïòñõôôóôôôôööõö÷÷ø÷ùùøþûûùùüüúúúüÿýùùúúûþúúùûúûúûüúúûúûûúûýþúüüúûûûûÿýüüýýýýýýýþýÿÿÿþþ
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]S
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+!E
+
+
+
+
+
+
+
+
+	
+
+	þüüüûúûúúùøøøö÷÷öøøõõöôóõóõóóôòóööôôôòòòñïîîíîðíîðíììííîïìîîíìëìíëêêìêìêêéèêéîöíçììçèéæäååäççääãääâááâããááâãåáßßáâáãââß
+üèåååØÙÚÞáÝÞÞßààáâãããéåååæåæçççèééèéêêëëêëìíìííííîïïïïðññóññòññðôòöõôôóóôõöõõö÷øøøøøøùúüüûüüüüüúúûûúûýûúûýúûûùûúüüüûûþþûûüýüüüþýüÿûûüýýýýýýýþÿÿÿÿ	
+	
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+	
+
+
+
+	ÿýýýüûüûúûúøùùø÷øø÷õõôôõôóóôôõôôõõõóóóóñðññóòðòîíðïíííîíìíììîíìëìëëêêëñéëìêêéèéêéééêéèçååæååæåååçãââááââäãàáãááàââãæããââçæåææÙÚÜÞàÞÞáßàâââãåçéæåæçççççèéèéêéêììíìëìîííîîîïïïðñòóóôõóòòòò÷ôôõóóóôöøöõ÷÷÷øøøøùøúúüýûúüüüüûüüüûûûûûüüûúúûûûüüüüüýýûüýýüýýýþÿþþÿþýþþýýýýþÿ
+ÿÿ
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+					ÿýþýýûüûüúøùøøøøøöõöøõôôôóõõõôôóööôóóòòññòññðððîïíìïîíìíííîíìëëëëìëêëëééìêêéèééééêéèèèçææçæçæååæãäãââââááàßãéãáãâäåäæããäçêéçÙÛÜÜÞßÞààâæáãâåèèèçêêéçæçèéééëêêîëíîìíìíïíïïîîïñòóôôóöôóòòòóôôõþùóôøøõö÷÷÷ùúûùùøúúûüýüýüýüûýýýüüüûûüüýþüýüúûûûüüüûüûüüüýýþýýþýýÿýýýÿÿþþýþÿÿ
+	
+
+
+
+
+
+
+
+
+
+
+?B
+
+
+
+
+
+	ÿÿþýûüüúúùøøùøø÷÷ö÷ùõöõöôõööõôôö÷öóòòòðòóðïïïðïîìíïîìîîìíîîìêìíìììëëëëëéêëêèéêéééèèçççææçèèåäãâãääãâââáãäàëúßàáâãäçæãääåçèåÛÜÝÝßåèßàãããåäãååèêééèêëéçêëééëëíëìííììíîîðïïïðñòòóóòòôóòóôôôóõ
+ÿóôõõõööööùûþùùÿûûûýÿþÿþþýüüýüüüüýüýüþÿüþûüüúúüýüüüüüüýþýþýýüýýýýÿþþÿþþþÿÿÿýþ
+
+$:	
+	
+
+
+
+
+
+
+
+
+7Ü@
+
+
+	
+
+					ýþýüûûùøùùùùøøøö÷ö÷ööõö÷õôôôôöõóòóòññññïðððïïîíïîííîííïïíììííìíëëìðììëììêêêéêéèèéèçæèéèçääåãäæãââããâæçããàááâççäåãääåååçèÜÝÝÞßãæàâââãåääåæêéèèéî	æëìêêêëëìíòïíîîîïðððððñòóòòóôôóõôö÷õô÷ôôööõõö÷ö÷øùúûúüþýÿÿþý	þýýþýýüýýþýüüûûüýûúüýýýýüýýþÿþþþþýþþýþÿÿÿÿ(
+
+â3
+		
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/!
+
+
+"(âE
+
+
+
+
+
+
+			
+
+
+
+	ÿþþüýüùøùùøøø÷÷øùøøööôööõóôõóôôòóóòòòñòóñïïïïïîîîîíííííííííîîêëëííííëìììêëèù÷çèéèèèèçççåäãäåäååããããââáâãàáááåöáããããäææéêÜÝÞßàààáäâââääæåççúðççëÿÿïòíëîëìëíììíïïîïïïðððñòòòóòóõóóõõô÷øõøõô÷øöö÷ö÷úùùûûúûýþÿ
+þÿþýÿþþýþþþþýüüüüüûûþýþýþÿþÿÿÿÿþþÿÿÿ!
+	C
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+	ýýúüûùùøøøø÷ö÷ùú÷÷öõôõõõôóôóôõóóòòòñï'ðïñðîîïíîíëþëííìííììêêìïêëîëëîìëìêîïêêéèèèèæåéæääãåâèêçåäããâááàáâãâââãâãäååìëèèÝÝáãàâãæäâãååæ
+îéçéèèèêëêîòíñþííìîîíïðòðîðððññòòòôóóôõôó÷úöõõôù÷õõõö÷øøøúûúüûúüýÿÿýþþþþþÿÿÿþþüüýûûûþüýþþÿþþÿþþþýýþþÿÿ
+			
+
+	
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		þýûúúùùùùù÷÷øøö÷÷öõöõöõòóõõõôóòòñòðüðïñðñïîîîíìúøïïïîîíìêêêëîëííëíòïìëëëëìêéêëéêæçéæäæäæêåçóìããââããáàáãçåâåããèôéçéççÝÞßàààáããâãäãäìææçççççèçèêëêëìêêîñ
+÷íõõóððïðòññòóòóõóóôõúóõô÷÷õööö÷ö÷÷ùúúúúúûþýþþþÿÿÿþþþþþÿþÿüüüüûüüýÿÿúõÿþÿýþþüüýýýþÿ	
+
+
+
+
+
+
+
+
+
+
+ /
+
+
+
+
+
+""!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+þýûúúúùùø÷ø÷÷÷÷ööõöõõöôóõõóòóóòñòñðíñðððõðïîîííìíîîïîíííëëíëììííìîïîëëïîêêééêêééæèçæçåææêåäçäååââàî
+$àæëääãããäèçåççæÜÞààââãâââãããåäæäéêèèééèèéëêèëëìîðòøîðîïôñïïðñññôôôõóôõöûõõõöùù÷ö÷÷ö÷øøùúûúúûþÿÿÿÿÿÿÿýûýÿþýýÿû÷üû9
+ÿÿÿÿþýýþ
+
+
+
+
+
+
+
+
+
+ 
+"
+
+
+  !!!! !#!
+
+
+
+  
+ 
+
+
+
+
+
+
+
+!
+
+
+5
+
+			
+
++n¹O	ÿþûúùùøùù÷ùø÷÷÷õõõööôöõõõôóóóóóòòòõðððððòðîíîííííííîîíîííìïíìììíìììîíëïîììêêéèèéçççæèæçäææåãäæåäåàñM~âéäãæãâââååæææèÜßáááåèåãäâãåäæç
+ôçéééêéééé9èëìðôîïìíïïïïðññòôõôôõôóôôôõøóõõø÷ù÷öööø÷÷øùûûüüýüþþÿÿÿþÿþýÿþþþú'Fò{ÿþÿÿÿ	
+
+
+
+îZ
+ !'(  "+' !""#$%##!"#"""#   "!"#  !!!  
+
+
+"'
+
+
+
+
+
+
+
+
+
+		
+
+?AAÎþþýýûùùùùúù÷øø÷÷÷ööö÷÷ôôýûöôõõóóóóñòôñññðñïîîîöñîîïïííîîîîîîîíììëìíëëíìëììëëêééèçéççæçææåääææäåêèääãæ÷ãâááâãâ
+íãäåæçèÝÞßààäéäããâãæèæçþîæèèèèéééêèëìîîõîùðíîðïïòòòóôôôóóõôóôöôöõõ÷÷ùøøùùúú÷øùùýýÿÿ		
+
+ÿÿþòtÊJúÿÿÿ			
+
+
+
+
+
+~A0
+!!(%"(& "$%#"#$%$$'%$%##$$$" ! !""""#$$$"#" 
+ 
+
+
+
+
+
+
+
+
+
+
+		
+CDÏ
+ÿþþüûúúúúùùù÷ø÷øöõöööö÷õüöôõôóòóóñððóóñòóòîîïöñïïïîíîîíìíîïííììììîëëìììëìêåèëééèêèçæèæçååæååäåæåäãããßÞäââáãåâþëâþöèççÞÞßááâäãäåîææçæèéççéééèééêêìïêëñìïí&÷íïðððððòóóôôôóôõõóôôôùöõöúú÷úûøø÷øùø
+	þÿ$:5
+
+ÿÿÿÿÿÿÿ
+ÿ	
+		
+	
+
+
+
+
+9S:,
+%
+#+5*"#$!"$#$%%&!Hi,%%&&$$$##!"  "##$%&&&%&%#""!#!
+
+
+
+
+
+
+
+
+	
+
+	
+
+	
+"Jd*ÿþýüúúûûúûúøø÷ø÷öõ÷ö÷ø÷öõõõõóóóòòòñòòòñòõòððïïïïïîíîïïîìîíîííëìíìíìììííëë"
+éêëêëêèæèçæææçççåååäãäææäååâãáââäçåäùôèéëÞßâãâââääæìæååæìçæçèèéêêëêêêêìëîöìíîÿñîïðïïïïòôòóóôøõõôõôöõõúöõüû÷÷øøøøùøúúÿþ	
+¬12
+
+ÿÿÿÿÿÿ	
+
+			
+
+
+
+
+
+!
+
+
+
+
+
+
++cF'#%$*,(&&&')%Jt;&(('&&%&&"($!$%&'((')(&%%%%" 
+
+
+
+
+
+
+
+
+		
+	ÿýûûüüûúúùøøù÷÷÷ö÷ö÷ööõ÷öõõôõõòóòòóòðòò÷ñòññïîïïîîíîïïîîìííîììììëííììììæ+¹áëëêéééççæçæçéèæææåæçæåäãäãâãâããäãäåèèæëìßàáâáâãäãåäæååæìèèèæçèéêêìíëëíîíëíîîìôñïðîïðñóóöøóõøõôôøôôõööûøøøùúúúûúüüüþ
+
+
+Ï8
+ÿZÿÿÿÿ		
+
+
+
+
+
+
+
+
+
+
+
+
+!
+
+%4$)D6*''$TH%)))*@O80***('''(&$%$%'&'())+.))'&'&##!
+
+
+
+
+
+
+
+
+		
+
+
+
+
+			
+þýüþùøùø÷úùøøøø÷õööö÷öõõõõõôóóõóóòóñöòñððîîïïïííîîïïïìííîíìëììííëìììès[åëêééèçèèæçåæêçäæçåèçããâããâãæâäâäæåäåäåèéààááâåääãåæççèçéèèèèééêêëëìëëìëîìîññïöñðððñòòòóøûô÷üøõõ÷õú÷üûúúùùùúúúüýþÿÿ
+gž#
+	
+*
+	
+		
+
+
+
+
+
+
+
+
+
+
+
+
+!"!!  #*2&&%)+)*(?T:)+,-.77(+,,,*))))'&&'))()++****+*()'$$# 
+
+
+
+
+
+
+
+
+	
+
+
+
+	ÿþýþ÷øùøø÷÷øù÷øü÷ö÷úöõõõõóôöòòõóóóóòðñðïïïîîííïðïïïîîììííïíëìììëëíìëìêáâíêêééçæèéçæææçêçææäçïîãããâââåâãáãååææææçéààáâãäääããææçèèçèèéééêêëììëëíôüïðîðïîðñððñññòòñóöõ÷û÷õõõõ
+þ÷÷øùúúùøøúúü
+ýÿÿÿ
+
+
+	Hq<
+
+
+	
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+!%$!"!#')&*'(**,,,*(,.../0.+-,..-.-,+*+**)++*+-+***+,+)+)()&  
+
+
+
+
+
+
+
+								ýÿÿýúúúøùúøø÷ö÷÷÷ø÷öõöøõõõôõôóòòóóóòñðòòñððððîïîìôõïïîïíììîîïîíìîíìëìëëêëëëìëêêéççèèçèççåíëæåååíïåääãââäãâããääæçççêìßààâãããäçõåçæèèççéêèèéíìëíìëì<ìðíîîîîñôöôòñòòóóòõõöõõö÷ôø÷ö÷øûúøùùúúüýÿÿÿ
+
+
+
+
+
+	
+
+		
+
+
+
+
+
+
+ 
+
+
+
+ "%##%#&()*++*-,11000210122123.0//10.----.,,-,--,,,,,,,-+)))&"!
+
+
+
+
+
+
+		
+		ýýúúùùùúùùøøø÷øùùø÷÷ùõõö÷÷õöõôóóóòóòòôòñòóòòñðïóóðïîïññîïîîîîìðïîíììëëëëìîòëìêêèèèèéæææééæåååäåççääãääãâãçåææçèêììàááâåçâãì
+åçèêèèçééìëêííëëìíìÿ'ìîíîîïðòõúøòðòôöôòôõôôõö÷ýõ÷øøø÷ûúøúûüüûüýÿ	
+
+						
+
+
+
+
+
+
+
+
+
+
+  !""%%$%%&)+.-+--2/24545775665445122142200000//////.-.---,,,,,*(%# 
+
+
+
+
+
+
+
+
+
+
+
+
+			ýþüüûüüûúûûúùù÷ù÷÷öøúø÷÷öø÷ö÷ôóóôôòòòóñ÷ôóòòòðððððïïîñøíïíîììíìîîíìììëììëîóíëêëêèéééççæåææåäååäíóâäåæääããçäæåæèêëëáâããåçääìøæçèèééçééííëëëììíîíëèïðñðñïñòóøöñóõõõôôôôôõööö
+û÷øøùùùüýûüüüüþþ
+
+
+
+
+
+
+
+		
+	
+	
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+" ""#$%%%'('),37.//2:2246679;:9877776664645544312211000//.0..7L..**'$#!
+
+
+
+
+
+
+
+
+
+
+
+
+		ÿþþþþûüûúúúùùýùûûüùû÷ø÷õø÷÷ù÷÷ùøóòòóõòòòóòò÷õòòñññððñðïïîïîíïíîííìíîîíìììëëîððëëìëëéééééçéçææææææåäìòãåäåääãååáäæçèéêëâãääääæååäçèèèéééééêëëëëííìííîíïñòðñïïññóòñ÷ø÷÷ôôóôôö÷öõôöùø÷øøøüüûüüüýþþ
+
+
+
+
+1
+
+
+
+
+
+
+
+
+
+
+
+ 
+ 
+
+
+   !$$$%&&'())*-48141593467889<<<<<<:;;<:9989:86697454211200100<b0/-+)&&# 
+
+
+
+
+
+
+
+
+
+	
+
+	(³Bÿÿÿýüüüüûûûúùúúùùøûüøøùùùùù÷÷øø÷ø÷ôôóóôõóóòóóòòñòòðïñññðïðïîñðòîìíïîíïîíîìííëêí÷ùëëëëêééèéèèèçææææææååäãååäääääååõìèêëééëââáâäåæååææççèèçêêéêëëêéìíìííííîïïðïðððññòòõöøøóøüô÷ùõõööûù÷øøøýýúûûýþýþ
+
+
+
+^
+				
+
+
+
+
+
+
+
+
+
+
+!)
+
+#"!!$%$&'%')((+--10162433689:;==>@?@B@<>?==<===;::=;8865323211214D0..,)*'$!
+
+
+
+
+
+
+
+
+
+
+
+
+
+K ÿÿþþýüüûûûúúúùùùûùúøøùúø÷÷ööúøôúûóôôñóõñóòññòðñòñðîðñðïðïîïïïïðïîîïïîíííííííìëìíìëêëêëéèèèèææååæååææççäæçìåääääãýçïîêêëãáâäæêéèèçæèéèèèééêêëìêêëíîíîííîïïñðññðñòòóóóôôóùýõúúôóõöùûùøö÷þþúúûýýýÿ
+
+
+
+
+
+	
+E0
+
+
+
+
+	
+
+	
+
+
+
+
+
+
+     !!###$%%'((()**-0/1.24456679:>@BAABBBEF@@@B?>?>?@?>=<<<97655432341/1/--++(%" 
+
+
+
+
+
+
+
+
+
+
+
+ÿÿýûúúûúúûüûùúüûúúùùûøøøø÷ûùöøùöôõõùùöóôóôóññòóòòñññðððïîîîïðñòïïïîïîïïííííëìíêëëéêìëêéèççççææææçèðôäåçðääæäæã
+ùèíìêììâáâäåêôïåçæèèçèèìêéêêëêêìïðìíííïðïòððôõóòóóôòñôôôõöøù÷ø
+øö÷þüþúýüüýþþÿ
+#%%"
+
+
+
+															
+
+	
+	
+
+
+
+
+
++8
+  " ! !!#$*'%%%())++,--.4513876789;<<GDCDDEFGEDDCCDACCABDBAB?>>;9867554553340//.,(%"! 
+
+
+
+
+
+
+
+
+
+
+	ÿÿÿü	
+øúûüýüýúþ	
+ûùùøø÷÷ö÷ø÷÷÷öõõöøýööõõôóññññïðññððððïðïíïððñîîïïïîïïîíììììëëëììéêêëéêéèçççååååææôüäåääääéäåæäæéééêíîãâãäåæåèæèçèêéèêíìëíííììïïîïîìðîññðððøúôòóóò
+ñôõ÷ùø÷øü
+ûøøþý(ùþÿýþþ
+
+
+!"+4651+( 
+
+
+
+
+
+			
+
+		
+			
+
+		
+		
+
+
+
+
+|¹
+
+
+  #" !!!#&&)&''()*/0--.09?16@876:;>@>FDCDEFIJGGIGFDEHHDCEEDDB?><<<9765464365211.-)%#!# 
+
+
+
+
+
+	
+
+		ÿýÿÿýY1õûüýüòaDtþüûúøù÷÷øø÷÷øööõôöööõôôöôîòòññññññññðññðîíðïðñíîïïíîïîíííììììëëëìêëëêëëëéèçæçççææçæåæççåäæçäåççèéëëëëìäããääæçæçéèèèèêèéêíîëëìîðííñïòïïïñðïðñóòñì@Qíôôõõõöõöô÷ùøûúýúþþüþÿÿ	
+
+(;HR]WK?/"
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+
+
+
+
+
+
+
+
+%
+ ;#!#
+ !
+'+"&&$$%#&%&())*+**,../01<F4788<;<?@AA@BEGIJKKIKMJFGHKIIFGGGEEC@>AIE789<65574322/,)&%""
+
+
+		
+
+	ÿþÿ#úüüüûõJlùúúûûùø÷ø÷÷øøø÷÷öôôõõõõôõ
+íñðññðïññïïðñïïïñïîïîïïííïîîìëììíïðêëìêëëéêíêéèèéèæææææåæéçäæäæäåçççèéêêëëìâçêääêöëèèçêçééêêëëëììììííê÷Kíðïïóóñðñòòôôðñ÷öööõöö÷ö÷÷øùøøøùúûþþüþÿ	
+
+!1YŸäÑW7( 
+
+
+		
+		
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+ 
+""
+
+  "##$)2&%&'(((),0-,-/0/002336888::>B@ABCDEGIJKKKKKKHIKMLKLJJHHGEC@EQL;<AN87744211.,*&%$ 
+
+
+
+		
+
+
+	øúþýüûüþ
++ÿûûúùùø÷ø÷÷øøøø÷öõôõõööõõjîòóóóñðóóðïñóòððòðîïïððïïïïïîîííììììëìëëêêêîëêêèééçèèçèææçååçåæççëèêëëíììììàçäæçèçéðëëêèïíìììëìííïïîîïïðõóñðóòòóóôõöõóõööööøøøøøøùùùúúüüýþÿþýýÿ
+
+	
+"$+@pþžœmB0#
+
+
+	Zzû	
+
+
+
+
+
+Ýà1
+³Y
+
+
+
+
+
+
+
+
+
+
+
+(
+
+
+!##$$$%(+*(*),,-+,,31,MI/333468;::=<=>@CCDGHIKLKLNLKLKKMMNOOOMKJGHHFEB><>BJ:86554100,+'$#!
+
+
+
+
+
+
+
+
+
+	þþýþýûüÿûôøþûýúøùù÷øøøøøøø÷ööõõô÷õöööùñóóòññññòñññòðñóòòððïððððïïïîîíììëëëìëëëëìêêéêèèééèèêéææèçææåèçççèêîðñòóóðíâèååçèèëîíëëëëëëììíïïîíîîïóþïðòòóòòõøóóõöôõöõ÷øúøúøùùúûúýüþýýþþ	
+
+
+$1L£	tAG1$
+
+
+	Rp	n
+	
+
+
+
+
+3ABùäÃ
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+!#%&'((''((,*+*,,+02//<A;6288479:;<<=?BBCFGHHJLKLMJIKNNMNPQPPOPOKJHFE@Yk>AF;98553116+('""! 
+
+
+#
+
+
+
+
+			ÿþýþüúûûúúûúúûù÷÷úúùøøøø÷øø÷÷öôóöøöõõöôñôòñððïóôññððïðòïîïîïððïðîíîíìíìëëìëìêìêêéêééèêêèççèëëæåæèèçæåååäèðòóóñøõîîäôüææçéëëéêëôïìêëííííììíííïðñóððòòôóóôöôôôôôôööõö÷÷ùùùùùúýûúüüüýþý
+
+
+#2LÓ?#wC.#	
+
+			ý	} 
+			
+
+z#ežR
+
+
+
+
+
+
+
+!
+
+ '&$$%&'')*(((,,+,---10/002/Uh687:===ABABFFFEJKJKKLKJINQOORQQRPQQQMJHFE;Ú:Mi:;9553101.*'$#%$
+
+
+
+
+
+
+
+
+
+
+
+
+
+	þþýüúûýüúúúûùùøü÷úùøøøøøøøøù÷öõôöúöôõóóòóòðïïïðòðïøöðððîïîîïðïðïïîìììììììëìëëêëéééèèééèèèééèçæçççåççåæççìêéêéøúðñåççææçéêéêêëöïëìëììíííìíîíïñððòóðóóôöòóóôôõõóõ÷ø÷÷öøùøøúúþûúûüüüüÿÿýþÿ
+
+
+#/Eºåfœ]8+"
+
+
+
+	
+
+	
+û
+	
+
+ 
+	
+
+	
+
+
+
+
+
+
+
+
+
+
+
+ #$$$%&()+1)*,,,.-.//0020250Cj`7:9;?>AABACFGEEJKJIJHFIMQRRSTSRSRQORQLKIGGHFA?<<?<96510/,+)&$+)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	ÿýýýûúüþýüûûûùûùúùøøùøøøøøùøööõõõ÷õôôóóòñðïïñðïòñïÿùññïïððïñöòñóóøøöïëíëëëëéîêéêèèêéèééééèçèèæçåëççèèéëéêëê÷øïîæååççéíêêìêëíëëìêêìíííííïîîïðïññóòòøñûùõõôõööøøöøùøùùùýûúûþþþÿÿ	
+);_«²iG/$
+
+
+	
+		
+
+	
+:J
+
+
+
+
+
+
+
+
+
+
+
+%
+
+ !!!"$%&&),++,),---.../001223547>>989C_ABCCCDJJIHIJJKIGKRTTUUVUUTTVTSRRRPLIHFDCAA<?<96631/.,)('%!
+
+
+
+
+
+
+
+
+
+
+
+		ÿþþýüüûûûüüûûùùûùûúùøúø÷÷÷øøöõõöùõôôôöõôóñðððððñóòì(tþïòôïîòñðôññðø28
+
+ïîììììêëêðêéëëêééèéèéêéçèèèæçëçèééêêêëëëíîîîåæççèêëêêêêëëëíëòëìíïîîîîðððñóññòøøôõõõõõõö÷÷÷ùüøùùøùúüþýýýüþþýÿ
+
+&2:FSUJ;3)
+
+
+
+
+
+
+
+	
+				
+		#5
+
+
+
+
+
+
+
+
+
+
+
+
+
+-(
+ ""!"%%')16,,,,,./---.158323335668::=?FBCCDEGHIIGJKIHHJPSUUX[WVUSTTVUTRSQLKJIIEA?><;7642/.+),*'$ 
+
+
+
+	
+
+
+
+
+
+			
+		þþýýýüûúúûûúûþúúùüúûúøùùø÷÷÷ö÷õô÷ûõöôô÷õôõòñòóñïñóòð=øïóõðïòòððñðïô
+ûìííììëêìëëêêëëëêééèèèééééééçèèèçéèêêêêëëëííîäåæççééééêêêìëíëûûïëìðóïïðïððóòôðñññññ÷ûöôõõ÷÷÷øùùýùøùûüþEùûýþþ	
+$'-22.*'!
+
+
+
+
+
+	
+				"
+	
+					
+
+
+
+
+
+
+
+
+
+
+
+!"""$%%&).0,-.-,/--//14665455689:;;=?ABCFEFGJJLGEGIKMNQVWZZ[_Z\WVUTUUXWSSQNNKIGEBA?<;9410.,+,+(&"
+
+
+
+
+
+
+
+
+			ÿýþýûüûûûùûúøûúúüúùøúùøøøø÷öõö÷õ÷ôóõ÷ôòñòóòññòòóðéðñòñòòññðïððñðìëííîîíììëêìëëéèéèöïçééèééèèèéêéñèççèçééêêêëíîîíãìñççéëéèêêêëëííîíìììîðïîðïðñóôõññóòôöúúöõ÷÷÷÷ùüýøùúúýWŠ	üþþþÿ
+
+
+!#"" 
+
+
+
+
+
+
+
+
+
+			
+						
+
+
+
+
+	
+
+
+
+
+
+!  "#""**')++*,..-,--./0246666877;<=>=@CCEEEHIIKLMMIHGLSUUVZ]`b_]\[YWUUUVUSRQOOOKIGEA@=<;4321.,*((&"
+
+(0
+
+
+
+				ÿþýüüüüûúúúüúùüýùüùøøüÿüúúù÷ö÷÷ôõôóóôöñòòòñòòòñòóóññòòñòóñññðïññðïîîîîíîîííëììëêéééñíèééééèèèçééèìèèçæéèéëêëìíîïïäéíççéëéëëìëëëííííííííïøúîððñòòûûõòóôóóò
+
+ùö÷öøøùýùùúüúý>
+ÿÿýýÿÿ
+
+
+
+
+
+
+
+
+
+
+
+					
+
+		
+
+
+
+
+
+		
+
+
+
+
+P{3
+
+!+
+" !#"#%*)')**,,-./-,/0*03469887gf8?ABCEJJIKLNLLONNPQMLRVZ[YZ`de`_^[ZYWTTVUTTRPNOKLIDCC@=;7430-+*((&$!
+
+
+
+
+«ÊD
+
+		
+
+		ÿþþýýýýüûûüûûúûüüøùùøùýÿûüúùøù÷ôöôôôõóóòóôóòòóòòòóóòòóòòñòòòñ	üññïïïïîííîîìììììêëêêêééèçèëëééèçèèèéèèçèÜçééêìíîîïñääåçæçêíìììëìììíîîïîîîïóõïðññóóõóôôõóòòôÿÿøöûÿúùøúùúùûûüýôøýüÿýþÿÿ		
+
+
+
+
+
+
+
+
+
+	
+		
+
+	
+
+
+
+
+
+	
+
+
+
+
+
+
+Š
+^	
+$/' 
+!"#"#&%%&&(*,,,.////2cA5889;;:WX=BFHIJPPORSURTRRSSUSTZ]]^``cfedb_^\\YVUUSSSSVSMKKJFERŸÉJ54200-*('&%" 
+
+
+
+
+!
+
+
+
+			ÿÿýüýûüûûüüúüüûøùøøøùùùùùûùü
+ôöõõôõôôóò÷õóóòóòñòóòòôñññðñóð
+ýñðïïïïîííííìëëìëëêêëééèèèêíìèéèçèèèèèèèéæãèëêëîîîïðåæèéèèéìëììììíííîîîïîîîîîðñòòóõôóòõöóóóõõõööúýúøùùùúúúûúûûüüýþýýýý
+
+
+
+
+a.
+
+
+
+
+
+
+
+
+
+	
+
+,7
+		
+
+
+	
+
+^<
+
+
+
+
+-# ! !#""#%&'(.2*+-/0012š^88:;=>?=>DHLOPQSUU[\ZXYVXXXXXY]`^`dfggfehaa_]ZWXYURQQSSOLJJJIS
+ZY27432.,+)''% 
+
+
+
+
+
+
+
+
+			
+þÿþýýüüýþþúþúùúûúùùùøøúøùúø÷öþõõõôôôòóóóööôòñòóóóõòñòñññññòñîðóòïïïîïîííìììëìêêêëëêêéèêëëêèèèèèèççéèèéëåçëêëïîìíîåèééêéèéëìïîíððíîïðïîïðððñòóòòôòóòööõõôõöö÷øøøúúùùøûûúûýýüýýýýþÿÿþÿ		
+
+1
+
+
+
+
+
+
+
+	
+		
+
+0Þ+
+
+	
+
+
+
+
+
+
+   "5-$"#$%'((03*,-10012sT99;=?BDELQPSTWWXYZ_^]\]^_^^]]]^`bfhkjhigjeb`_]ZXXUSRPRUPLPMIGIsE88655/.-*))&"
+
+
+
+
+
+		
+	
+ÿþýþýûüûùûùúùúúúùûùù÷÷øøùùùø÷øóôõõõôüøùõóôõ÷ôòôõôôòõòòòòñòðòññïïöôïïïïïïïíììíìëêêìëêêêéëìëéèèéèéèèèçêêèêèéêìëìîîîîîåçèéêéééììîîîñðïïðóóïñóððñóòóòóôó÷ôõõõõ÷÷øøùùúúùùùûúûûûüüüýûþÿÿY
+
+
+
+
+,
+
+
+
+
+
+
+	
+
+
+
+4ï>
+
+
+
+
+
+
+ !"" !#G7'%((')*+,+,.,0/236/;;>?ACHKLV[VZ\]^c__afcbbcdcceddegiloonkkijgedalbXUTSQPSRMLNPQFC=9=876641/.,*''%
+
+
+
+
+
+
+
+	
+
+
+
+	ÿþþüüýûüûüúûùùøÿùùùùúûùùùúýõöööööý&ñôôõôó÷øóòòôóóóòòòóóòòñðõóððïðððïíììíìëëììëëìëêíìêêèèèéééêéíìêñëêëìììíîîîîïåèéèééêéíììííïïñññôôñòóññòôôôôôõô÷õöööö÷÷÷øùùúüüùúúüýüûûûüüüýÿR	
+
+
+
+
+
+
+
+
+	
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+"
+C!
+ "#$#%%#&%&'%&''-+*,-..//0/0136;;=@ABVUORUY\]aebdiefgnkhhhijklmlorqqrrrqlkkjgechbZ\ZURPOMKKHJJCB@@=:7420.-.,)('%!
+
+
+
+
+
+
+
+
+		
+
+ÿÿýýýüûûûûüûúûûøúúúúúùþÿùùøøøøù÷ø÷ö÷ùL
+ðóôõôôóòñòóóôôôñóñöôóòððôòððïïîíííììíìêëìììëîëêêêêêéèèéééìéíëéöëêëëëëìíîîíïêééêìêììïîíííðñóòòòòòóòòóôõöôõö÷öõöö÷÷øø÷ùùøúúúüüúúûüüüûüýþÿýüýþ	
+
+	
+
+
++:-
+
+
+
+	
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+p.
+
+!!#&'%&&$%'''&'((*+,-..-00211247?=?BED__SX]^_cfihjijnlopoooopqrstuy{wvttvxolljff`^\_^XTOLKIGEDA@@<=;8730-++*))(17!
+
+
+
+
+
+
+
+
+		
+ÿþýýýýûúúúûûúûüùýûùùúúúúúù÷ùþûø÷ù÷÷ö÷óõôóôôôôóòñòóòóôùòóòòòòñððïðñððïîííîîííìëêëììëëëêêéêêééêéèéëéçèêìéêêëëëëìîîíîùåèëñêîíïðïðððòòññòòòóôóóóóöõõ÷øù÷öö÷øøøøøùùúûúùúúûüûûûüýýýÿþýþÿÿÿ
+			
+
+
+
+!àW.
+
+
+
+
+
+
+	
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ""!!!(-"
+
+
+
+!"#$''(%&%$%%%''&)(()+./-./0234348>@ADGJLPU\bdfgilnnosvwxy{||yxxxyyz~}}ywv|tomljgc_^[ZYSNJIFBBA?=<><:5530-+**)('19"
+
+
+
+
+
+
+
+
+
+			ÿýýýýýýýûûúúúúúúøùúùùúÿøûû÷ý
+÷÷öõõô÷ôôóôõôóòóòñòóòòòòòòóòñòðñðïñóðððïïðïîíïñìëêìêëêëêêéêéèééèçèêéçèéçèêéêíïíìïîîïÿåéééëìííïîïðñóòòòòóôôôôóôôõöõùöú÷÷÷÷ø÷öøýýúúúûúûûûûûýûüýüüþþþþþþÿ
+	
+
+
+$$ír(+
+
+		
+
+
+
+
+	
+
+	
+
+		
+
+
+
+
+
+
+
+
+%)!!###!$#  
+
+
+
+
+
+"$'($#&'&%%%%&%%&'*+-..//.0355579>@BGLORW\adhllortvz~~xvusqmigeacjncUNJFMW>==:9=;:7300-,,*)('(+$"
+
+
+
+
+
+
+þþÿþýüûüüüûúúüüýùúúúûûûúùúûúøûýùøöööô÷ôôóôóóôóóòó÷øòóòóñòóòñòòðððòñðððïððïíìð÷ííëìììëêêééééèéêéèçèèçèééèéèéìððïòðîðçéèéêíííííîððñôöõôôõõõöôõõöõõõúøøø÷ö÷øùú÷)+öùùúúûúûûüýûûüþþþüýþýþÿ	
+
+
+
+
+
+hhC>"#&&"
+/b[
+
+
+	
+
+			
+
+		
+
+	
+
+
+
+
+
+"$$$##"!"" 
+
+  !!#&%&&%'&+$%&'%''()*,./012137577<<ACFMQTY_dilnqtx} ¡Ššš©€¢|xvtoihfch1Y¬OOKFMW<:::99776363///,)(('%%$!! 
+
+
+
+
+		ÿÿÿþþþþýüüüúûûýýùøúûúþÿûùúüûùøùúúùö÷ööúöóôôóóóõõôõóöüòóôôôóòñóòðñôõòïïïîíîíîïîîðíìîíëëêêéêêééêééèéèççééééêéëìïððïíîéêééêíìîíîððòòó÷÷óöùöõöööö÷÷÷ö÷÷øøø÷ø÷ûþ÷=Aôùùûüüûûûûüûýýþþüýþþþþ
+			
+
+
+
+9+9IQR;%yî
+
+
+		8	
+
+		
+
+		
+
+
+
+
+
+
+
+
+  !##"""!"!  
+ #%')((&#$%%&&''&&&*,+-12342479;89EBEGLQV\afjotux~
+€¹ª£š©¬®¬Š
+yvpkigdlÉÉKNNNB><:8:;75311?90//-+*++&.<!!
+
+
+
+
+
+		þþÿÿüþûüþüûùþùúûüûúúûúùúùùùüø÷öõøõóóôôõõôôóöúóóóòôóôõóóóôóññòóñïðïðññîîïíòïíîìëìêêééêêééèéèéèééêçéêêêëìíííîíïéêêëîïïïðñöôóôõöúù÷÷øùùúúúøøûùøùùù÷øøùúúûööüûûüüýýüüüüýþþþþýþþþþÿÿÿ		
+
+
+
+
+
+ 1{SåT(
+G|A
+
+
+
+
+M
+
+	
+
+
+		
+
+
+
+
+
+
+
+
+ !"%#$" ""
+
+ $(((,-%&&'%&''.*'*-.013555;@?R=?BGLORV\aioru}€¥š«±²±žÌºµ¶žµ°ª¥¥¢|wsnkhfo±œzRMON@>;:7696321075//.,,,,,&,8 
+
+
+
+
+
+
+
+	
+þþþýýüûûûûùÿûúúûûúûûûùùùøúùø÷öõ÷úõòóöõôóóóï
+/ùôóòóóóòòòñóóòððññðððóüùíîííòïììíëììëêéëìêêêêéèêêêèýðêêëëìíîïîíïìëìíííðîñòóóóõööüüúûûûûüüûûúúúúùùúùøùûûûûûûûûýÿüüûýýþüþÿþþþþþþþÿÿÿ	
+
+
+
+
+
+,C";ÕgÓe^+
+
+
+
+
+
+
+!	
+		
+
+
+
+
+
+
+
+
+
+
+	
+
+
+!""""! 
+!  
+
+
+
+
+ #'))*'%$$''''''))*,/233699::<?@CF]^TW_biou{€ºÌµŒœÁÄÈÓNãÂÄÄÁŒ·°¬ª§€¡}urmhfh^VVSMIC?><964543310--.--,--++,)!"
+
+
+
+
+
+		ÿÿþþþüýüüüüûúûûúüüûüüûûûûùùûúóö÷øùõôóõôóóôôóùýöõôóóòôöòòóû÷òòðñòññðîïïîîîïòíìíîííìëêéïñéëììíëëêìé2éêìíìïðñðìíêëôöííîñðóóõõ÷øùúýþýþþýþûýÿûúûøùùùùøøùûüþýüüýýüüÿýýýüþþþýþþþÿÿÿ	
+
+
+
+
+
+
+	 "=Íû8Q(#
+
+
+
+
+
+
+	
+	
+
+
+
+
+
+
+
+
+
+
+$x'
+   !"!
+
+
+
+!
+98#
+
+ #&'''(%'&&)''(*-/-/02458::;=@BFIMU]]adiowŽÅ¯žŸÇÈÌÒÚÜâêqýØÖÐÍÉÂŒ¹Ž²²­š£¢ytniea^ZTPLHC?><8542021//---31,--,-..&$!! 
+
+
+
+
+
+
+6		ûÿÿÿýþýýûüûüûûûúûûúûüüûüúúúùùøû!öùöõôôôôõóñóõôòôôôõóòòôóòòôóòñððñðððïïððîððïíííìëìëëëéëìéêéêîìéêîòêéëììììììííííëìñùôîîïñòôö÷ùúûýþÿÿýýüüûûûüûûûúüþÿÿþüüüÿþþþþÿþÿÿþþÿ		
+
+
+
+
+
+	 ñ!C&3kÆÁs7""
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+fÑi
+
+
+   ! 
+
+
+
+
+
+
+
+
+
+!
+
+**!#%"#&('&&'(&()(()--../23469;=?ABFIPRZ^fikqz
+€­·ÀÊËÒÙÞéî÷øùóï#úáÝ×ÒÌÆÁŒ»¹µ¯š§ vpic`]YRMJEB?<97331.//-,+,*A=,.-.-)('$" 
+
+
+
+T
+Q#ÿÿÿýýþüüûûûûúûúüûúúýýûúúüþüùøú
+Aý÷ù÷ôñô÷öôòñóôôôóóóôóóòóñóôòñòðïððïïðïðïîîïíííîíìëëëííîîéèèèêëîêêëìêêëëëëìíììííîëìíîííîññóõöùýýÿüþûúûýûúúûýþýýÿþüýýýþþþÿþþþþÿþÿ		
+
+
+
+
+
+'X%(<90+$
+
+
+
+
+
+
+
+
+		
+
+
+
+
+
+
+
+
+J!H
+
+
+ 
+
+
+
+
+
+
+
+
+!
+
+
+
+"! #%&&&%'''&'(,*-,,022359<<=@DFIOW]cgnrv}£©®ºÆÏÒÙâéôÿ
+öëãÜÚÕÍÊÆÁŸ¹±¬Š¡zqpf_^[RKIEB?=:841/-/--,+++<8,----+'%#" 
+
+
+
+
+
+
+	#
+;þÿÿþýýýýûüûûúúúûúúúûýýüûúúùùúùøòöøøöóòôõôóòòòôõôöõòòôôòñòóðññññðððïïïïðïïîïíííîííìííìííêéééêêêëîêêéëëêéëìììîïîíîëëëëîîðñóôö÷øþÿ	
+
+
+
+þüûûûüýûûÿþüýýüýþýýÿÿýÿÿýýýýþþÿ	
+
+
+
+
+
+
+
+0&
+
+
+
+
+
+	
+
+
+
+				
+	
+
+
+
+
+
+
+
+
+ 
+&8
+
+
+
+
+
+
+
+ 
+
+
+
+!%'&'&%''''((***-/99569<??CHEINS^hmp
+¡ª²œËÙäéïø
+!,178/"õíéãÜØ×ÔÆÀº³®šqv^^[QIGE@=>:74/.-/,+++*++,++,,-+)&$$!
+
+
+
+
+
+9ÿÿþýþþüüýüûúúûûúûüúûýýüúøùúûøøö÷øø÷ôóòóôóóôôõ÷ö÷ùôòôôóóòJìññððñññðñðïïïïîïîîííìíîíìëêêêéëíëêìêêìììììíïïîððïïîêêëìîîðñóôöøúý	
+
+
+ÿÿûûûûüüúüüýýþÿÿÿþÿþýþÿþÿþþÿÿÿÿÿÿÿ
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+					
+
+
+
+
+
+
+
+
+ 
+$9
+
+
+
+
+
+
+
+
+ "&('%&'&'&&%(**+-.3459;=>AFIHMSYenuzŠ­¶ÄÓßê÷$+1;ISYVPA.
+
+ùôíæáÛÎÊÇœµ«£
+xohb^WPKFC@=;874/.,,.,*)**,-,+,-,,*''$# 
+
+
+
+
+
+
+
+	
+ÿÿÿÿþüýüþüúüüûûüýüüüýüûúûûúùùùùøøøöõôõ÷öõööõøøööõóõõõôóü
+ïòòññññòôðððððîîîîííìíîííìëëêêéêìîììëëëììììððïððîïðïêêëíñõòòôõ÷øú
+!),*#
+
+þüýþþüüþþþþÿÿÿÿþÿÿþÿýþÿþ	ýý
+
+	
+
+
+ 
+
+
+
+
++	
+
+
+
+
+	
+
+
+
+
+
+
+
+ 
+
+
+
+
+!
+
+
+
+
+
+
+
+
+
+
+  !$&&&()(')/&),--12138;<>ACFJNS[alu{Š®²»Êáíó
+'.5@KWeqx{zn^L:*öîæÜÑÊÂ»±«¢|rkd[TOIDCA=7446/---0-)),,+,+,.-*+)(+&$!
+
+
+
+
+
+
+
+
+	
+þÿþýýýýýýûúûþþýüýþýûûûúùúøúøúùø÷÷öö÷÷õõ÷ö÷öõôôôõõõõôòòòññññññðñôïñðòïðïïðîîììëëíììëéêìììîîëêêêìííììííííîððîëìíîðòôóõöøúÿ
+.BZfZE2
+
+ÿþüûýþþÿÿÿÿþþÿÿÿÿÿÿ	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #%')())(+2)+,-.23489;?@CFHMSY`hox¢¯»ÅÑàïú'1<GUdtufYE5'îåÚÎÇŒµ¬£ricZTNHCA@=8;12--4,,++)-,++)*,*))(''%"!
+
+
+
+
+
+
+0ÿÿÿþþÿþþüüýÿüúûþþüýüþþûûú÷øù÷ùùùú÷ûùõôõööõö÷öõõôôóõùþõòòòòññòñðððððïðïððïïîîïïíìëëêëììëéëëìïëêìëêìííîîíëìïïîïïììîïïòòôõöùý&NJ?#
+þýüüþÿÿÿþþýýýþþÿÿÿ				
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+.!
+
+
+  "&'('')((++,,-.1568:<?ADHKPW]dks|¡¬ºÆÖæõ
+2@KWg{ªžŸ¿Ÿž§|p^N?*$gðëàÓÆŸž¯€tkdZSMHC@?=:=0.,,.+)21+10+**+*''''%&%"!
+
+
+
+
+
+
+(þþÿþüýýýúýýûúüûûýüüþûýþøøøøùøø÷þûöòïôø÷öõö÷øõôôõùûõòóóòòòòðòóñ÷üîïïïïðíêïîíîííìëìëêëêëêëíëëêëëëëìíííîîîîîíîëìîïïñòóõûùü/jEIÿÞN(ÿýüüþÿ	
+
+
+ÿýþýüüüýýüýþÿ			
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+5$
+
+ 
+
+
+ !%''(()')),-+..0579<=@DGKNSZahpwª·ÆÓçü
+)9K\kz¥žÅÕáêãÝ×Ä­
+rbS@-.)úñàÑÇ¿ž¯Š
+ymd]TLGB==<844/-,,,,-,)((),-,*'&%&&%#" 
+
+
+
+
+
+
+
+
+		ÿÿþþÿÿþþüûûüúûûüþþýýûþ	úøøúùùøøüûö2õø÷õ÷úûùõõöõöõôôóòóóòòóóò÷ûñòðñïï÷
+ôìííîííîíëëììììêëíìöííììíîííððïïïïîìíîîîïñòôùù5Í
+RìT)
+ÿÿýý
+T_
+þýýþþþýþÿÿ					
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+
+
+
+
+
+$
+
+
+
+
+
+
+
+!"$&''(()(++---.0159;<?AFJNRX_flu{
+šµÃÓäù!2CTg}§ÃÛíý
+öãÊ³uaO:
+	ñàÓÇÀž®¥{maYRLGC?;::44//.,-,+,*(()**)(')(''%$$# 
+
+@2
+
+
+
+
+
+		ÿ
+Hýÿþüüûüýþÿþýüüýüûùúûùûùùùùùúö'O!ó÷÷÷ùüúù÷õøö÷õõõóòòóóóóñòòñõùðñðîõòíííìììíëêëëëëììïìëñíííìîíîîîïïîïðïíîïïððòôö÷ÿ
+2zK)M ŽG%
+	ÿý
+USY
+uŒ÷ÿþþÿþþ
+ÿ	
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+*
+   !
+
+
+
+!
+)"
+
+
+!
+   #%&'(((()+*-,//136:<>ACFKPV]djqw~³ÀÑã÷
+
+3H]s¡¿Úö
+&7FROE0êÒžnYB&òãÕÇœ¶­€zk`WOIDA>:8642/1./.-++)'+-)('&%'+$%$"#"!
+
+
+
+
+
+
+
+	
+
+
+
+þþ©
+ûûûýýüüýýýýüûûûúûùúýúúùø÷øøùúúúûù÷ööùþüöøö÷úöôõôóóóóòòòòòñðóõïïðïíìîíöòìëììêêíñðëììíëëëíííìííííîîîïîïïíîîïðñòôõ÷þ
+*Y«	¹h5
+	ÿþÿþ %ñ
+3Lû&ÿþþ
+					
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+
+
+
+
+
+
+
+
+
+
+ "$(#
+
+
+
+$*
+
+   
+
+O-
+
+! !#%((())()++,/02369=@CEHMSX`iou{
+§ŒÍßù.F_xŽÏð
+"<Yhv{yr]>%
+íÎ¯w^E+ñãÕÆº³«¡zl_UNGB?;9742/..064,)''&')(&$#"#$&$"""!!
+
+
+
+
+
+
+$
+
+ÿÿþûýýûûþýüüüýýýüûüüúúùúûúúúùøøøùùù÷÷ùø÷ö÷þý÷ù÷÷ûõôõôôôöôòññõóçëñïïïððîîîíöòíëìëéëîðïëëëëëëììíìíìíííïîîïîïðìíîïññõôô÷øüÿ	"3CORD4%
+	ÿþýþÿULûöÿ	ÿÿ	
+
+	
+
+
+
+
+<
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
++,"
+
+!
+
+ ! 
+z;
+! 
+ !"&+))),1(,,-/0348;?BEHLPV]cksz¡®ÄÜï-A]zžÙþ%:Pm
+
+hH%ãÂ}aH/ýîßÏÁº±©yl_UMFA>;87630/-.0H1('&&'('%"""#$%$!'%"!
+
+
+
+
+
+þÿÿþþÿþýÿþýþýþþýýüÿÿýúøúúúùûúúûùùúùøøøù÷÷øøø÷ø÷ø÷öõöôôóõôòòòñ d2íïïðïñîïïïíííììññììëêëëìììììëëëììîîîïïððððñìíïðññöôõ÷ùûþ	 &'#
+
+þýýþþ
+		ÿÿÿ
+
+		
+
+
+
+
+
+
+I
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+! 
+
+$(
+ 
+ &! "!!""!#&)+,)-<*..-22469<ACFJNSX`fmwª·Íéþ&=Ts²Õö$Sm©Ž·»¹°£gAôÒ©cI1þêÛÎŸŽ­¥yk^TMF@=:865401,,+2-)&'((&%$""!!$$' $!"" 
+
+
+
+
+
+
+
+		ÿþÿþüÿþýüüýüûûþûûûùûùùøûûúûúùùùùøùø÷÷÷÷ööù
+øø÷öööõôôóóóòê?Ñxêïñîîðîðïïíìíìëõûòìëëêììëëíìëêëìììíïïïðððïðíîïððòóóõøúûþ
+
+
+
+
+ÿþþþÿÿÿbXÿÿÿ
+
+		
+	/%
+
+
+
+
+
+
+
+O
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "!  
+
+
+
+
+
+ 
+" 
+"   !!!"""%)*)**,0,-./4679:>ADGKPVZ`js|ª¿Øò	5Kf¥Ïû"Q{§ŽœÈËÌÊÂ¶€[,Ü±bF.þæ×ÊŒ®§ wk^TLE?;<>532..,+*(((&&&%$#""  !"" ! ##"
+
+
+
+
+
+
+
+Mÿ
+ýüüûþþüûùùûûúûþûùøøùùùùúùúúøøø÷öö÷öõù'øôõõô÷öôôóòòòò&!ïñòîíïîðïíììììêîõóìëëëììëëììëëìíìëíîîðñððïñîîîïðóóôõ÷ùûý	
+
+
+
+
+
+[
+þþýþÿþûVOýÿ		
+
+	
+
+*"	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"! %$
+
+
+
+
+ 
+   5$!!!#$#$&()*))*-....568:<?BFJMQV\dpz€³Êâü.D\xœð#S¡Ž¹ÃÌÕØ×ÓÌÃŽk7ßµ\A'
+ùãÑÆº¬¥uh]TLD?;:;531/-,*))('&$$$"!!!
+ !&   )$
+
+
+
+
+
+ThEÿ	ÿüÿþýýýýûýýüùøúùúûúùùùøúúûúùûûùøø÷÷÷ööö÷ôöõõõööôõôòòòòóóïíòðððïñîïîïîííëëììîïííììîîìíëììííííîîîòôñðëììîïïñòóóõöøúüýÿÿl
+ÿýüýþþýþöùÿÿ
+
+
+
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &$
+
+
+
+
+
+ #
+
+
+##!   !"#%&$&)+++*-,../257:<?BFIMRYaht¬ŸÔí#9Okª×BsŒÆÆÏÚßàÞÚÓÊŒp;Ù¯U;#ñÞÎÂžª€¢sdZRJD?<85320.-+*()(&%$$#"!   
+
+ (
+
+""
+
+
+
+
+ f
+
+	þýÿýüüþýüýüüýüýûûýúûùüúùùûûýûùúûûùûûø÷öö÷÷ùõö÷÷÷÷÷öóòôôóóôóòòñïðïñðïïðñððîîîìñóîïíéðíííìîîîíïîîðïðñïø
++íïïðñòóóõöøúüûüþÿÿ÷ýþþþýþþýýþÿÿÿÿÿÿ
+Rª		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %#
+
+
+
+
+
+
+
+  !#!  !#$$#%&&&(+,-,-//20249=@BDHLQW]fmy
+Š¶Éßù/KazÃô)_²ÎÕÖÝáââàÝ×Ì»m5Ð€wO5 ìÚÌœŽš¡rdXOHD@;8532/.-+,(((''&%%#"!! 
+
+
+ 
+
+ 
+
+
+
+
+
+
+
+
+Fn	
+þþþýÿÿÿþÿþþýû
+%ûûûûúûùúùùùüüûûûúúøùúø÷÷÷÷÷÷÷õ÷÷ö÷öôôôôôóôôóòòñðïòñððïôñððîîíìííì[ïëíìîîîîïðïïððïîìü7Eíîïïññóôõøùùúúûüýþþÿþÿÿþýøúýþýýþÿÿÿÿ[Ã
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+
+  
+
+
+
+  !'$##+)&(')+())+-1./802368<@BDHLOUZ`it¢®ÀÔê$=es®ÛFx¡ŸÏÚÞáãããáÞ×Ë·c+óÂnH.æØÌº²Š}pbWOIA;:8400..+**'%)&&%#$"! 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			Z|ÿýûýýýüýþýüúùùùùùùùùøùúúúûûùøøøø÷÷õõôôõøö÷ø÷õõøõòóòòñòòñððñððïïîíîíîîìííììëéCåìììëííìíîðîîîîïîíðòìïïðïñòõõõøøøûüûúüüýþþþÿüþýýý ÿýýþþþþÿþ
+F
+
+
+
+&
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+!!! 
+
+
+
+
+
+
+
+
+
+
+!$#"#%%&%$&)))(+-,..11335:=>@EJNSW[ak­²¯µÄ×ó
+*G[wœê
+V«ÄÔÜáããããáÜÓÅ­Qá¯
+]<#úÞÐÈŽ®¢
+zm`TOIMM65>U--+))&%%&$###!  
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+	,3ÿÿýýüý"ýýýüüüúúúøùùúûùøûúùùùøøøù÷õööõöõ÷öø÷úû÷ôôôôôóóññðñðñôïïîîíîíííííííîíìíñöîìììíííîðïîîîíïïííîïïññððòôòôõûùùùùúúúûûüüûüûüÿüûûúMûýýýýýýüý	ÿÿ
+
+
+
+
+
+
+
+
+"/,
+
+
+
+
+
+
+
+
+
+
+
+
+"$!!" 
+
+
+
+
+
+
+
+
+
+!!#$$$&*+(')**+..-./11458;?CEKQTW^ep¶Â¢ªºÌâú0Le§Éö,b°ÇÔÝáâãâàÝ×Íºn9ýÇrM/
+÷ØÈ»±¬ vk_TNOdb43Bc-,))('%%####"! 
+
+
+
+
+
+
+
+
+		+
+ÿþýýýýýû?Føüüüüüûøúøúúûûùøùùúùøøøøøù÷öõ÷öøõöøö
+þõôôôôóòóòóõññððïïðîïîíìììììíïîíííîííïîííîîîíîïîïîïñðïîïñññòõóõõ÷ö÷÷÷øøùúúúúúüûý
+ûüüùV/ûþþÿÿýüýÿýþÿÿ		
+
+		
+
+
+
+
+
+!)"
+
+
+
+
+
+
+
+!!!&#
+
+
+
+
+
+
+
+ 
+ !!"#$$$,.('')++-.../33568;ADINSZ_bju¥°œÓç9Sm¯Ôþ1d°ÈÓÚßááÜ×ÕÐÁ©}Má¬\;$ÿçÑÅ¹²§~vj^TKS[E540,-+)''&&$$$""""!
+
+
+
+
+'PO
+
+
+
+
+
+ÿÿýýþýþýüýüüüüüúûúúûûúùùøùúúúûûùùøøø÷öøù÷øù÷øúöööøùôóóóóôùòñïñïïïïïñïîîîíìîîîîìîîìíøðîìíìîîîïîîîðóñíîðïðóóòôõôõõö÷øúûúúùùúùúøûüûüþüøùûüþýýþþþþÿÿÿB	
+
+
+
+
+ 
+
+
+
+
+ !!#" 
+
+
+
+ !!%&$$$$'*+))+++-10//04468:=@EJOTY_gv~©µÃÕó!<YtžØý/c«ÃÏ×ÛÜÛÕÊÃœ©X+üÅiF,óßËÁ¶­€}uh\RKE=8323.+**&&$$#"#""#!!!
+
+:í
+
+
+
+
+
+ÿÿýÿþüýýù
+úüüûúûûûùùúùúùùùûúùúøûý÷÷÷÷øøø÷÷øõöõôôôôôôòòòòðññòðïïîîîíîíìííííííìììíììðîîíëìëîïìïðîíîîîîïðïïñòòóôõö÷ø÷øúùûüùøúúúûûùûüÿüüûüþþýýýÿÿþÿ	7	
+	
+
+
+
+
+2=
+
+    
+
+
+
+
+
+
+
+"$%#!#**'()++*,-///25558:?CFIMRY_gqy «·ÆÙñ
+&A\užÚú#S|ŽÂÌÑÑÏÌ»¢oX,Ô€vQ5
+
+ûêÖÄº¹« }zuk[OIA<7234.*)+%%%"!!"" 
+ !
+-Áâ
+
+
+	ÿÿþþþýþýüüúûüúûûûùùúùùúüýûûúøùøûþø÷÷÷÷÷÷÷÷÷öööú÷óõõóòòòòððñðïïñïïíîîîíìííëìíììëìëëíîíìíìììîìùÿòìïîíîîððïðòòóõööööõ÷÷÷øøø÷÷÷ø÷ýûûùûúúúúúúüüýýüýþýþþÿÿÿÿÿþ		
+
+
+
+0
+
+
+
+
+
+
+$*
+
+
+
+  
+
+
+
+
+
+
+
+
+
+
+ $# 3.&(&')**+,+1D055:79;@DIKNRY`emwŠ¯ŒËà÷+C]zµÓó?h
+«¹ŒÁ¿®QF1ÿÖ®];"ôãÎ¿·³« }{uwv_MH@:630//*)'&%'" "! 
+
+
+ 
+
+
+
+
+
+
+		ÿþýýýþþþýýýüýüûûüüùúûýúùúüûúúùùøùûùø÷øø÷÷úú÷õõöõõöõóòòðóóòñððððïððîîîîîíììììíìììììíñíìíììíìííííîîîíîïîðïòòòñòóôôõöõöø÷öøùö÷øþúÿþøùùùúúûûûüýüüüûüþÿþÿÿþÿ	
+	
+
+
+
+
+O#
+
+
+
+
+
+
+
+	
+
+
+ 
+
+ !"!  
+
+
+
+
+
+
+
+
+   "#!,)%')/2++,.21936:<=<<@FILPV[`gnuŠŽ¿Íäû-F^x®Ëè$Gjw^V&&üÖ³kE&ùëÜÇŒ³®ª {zvl^RMIA:73/.*)('&&$"!   
+
+
+
+
+
+
+
+
+	ÿÿÿþýýýýþþÿþþþüüüüý
+ýúÿûùúùúúùùùùùøù÷ùø÷øùúûýûýúõöôôóòòóòòòòðñððïïíîïîíííîììíìííííóüîìîííììíïîííííîîïðñðôøóõôôóôõõõ÷÷öõö÷÷ùüýøúüùúúùùúúúûýþýüýÿýýÿÿÿ
+
+	
+
+
+
+
+
+
+! 
+
+
+
+
+
+
+
+  !#" 
+
+
+
+
+! 
+#'!""#(/+'*./,--0201568;<=>BGMPQV\adÂ·Ž¿Ïäû+E[s£º×ö BduupWK=æ¿škM2
+
+ùîäÒ¿··¯š£ywsgZOIF@;72/..**&%$$$"
+
+
+
+!!
+
+
+
+
+ÿÿÿÿþþþþþýýýüüüýý
+ûúûúúúüþûúùøøøúúüùûùûøúýùùøõõõóóóðòòòñòññððòïîïïîíìíîííîîîììííîííîìëëìîîííîîïððïðñððôóôô÷õôôõõöööö÷÷úúøøùüøùúùüùùúûüüüýýþþþý
+ÿ
+
+
+
+
+
+"#("!#" 
+
+DR%
+
+'
+
+  
+
+
+ !!!1)"$#$)0-(13*.0.0/235689<>@DHMPSX]dl²·ÁÎâø
+&@Wn©ŸÙíý6FPKN3#
+áÉ°lN5!ñèÚÉºµ²±ªÃ
+~xuqcTLFC?852...)('$"$!
+
+
+
+
+
+
+
+		ÿÿÿÿÿþÿýýþþþýüýûñùýü
+ýÿúûûûúûÿûù÷ùúùùûøùúùø÷÷öööõôöõ÷0ïóóòòñòòñòïîîîîîìïðíîíïñïìîìììîíìïïîîîïñòíîîîðððññòóôöõõôõ÷öõ÷ööö÷øø÷úûúùùùùüüÿýûüüûÿýýþÿÿýÿ	
+
+
+
+
+ ""%)))*((&$#
+
+
+
+^w-
+/!
+
+
+
+
+  !!!-"!"#%%'('.1*05...1449;9<?ADIMQUY^fntz¯ºÃÐÞô
+ 7Pew©ºËÙé!
+	ôØŒ¡|cI2!õäÞÒÃ»º²­§šÂxti]QHC?;73/--.(&%$#% 
+
+
+
+
+
+
+
+
+
+
+	
+
+	ÿÿÿÿýýþÿýýþýþþýùpþüúþüýüûüúûúúüþüúøúúùøø÷÷øùø÷÷ö÷÷öõö÷öðóôóòñò÷ñññïððñðîïîííîîòðëîííîîííóóïíîïïîîîîîñðïñòòòóôóø÷öõõö÷öö÷ööö÷÷ø÷úùøúùùûúûýþýýýüýþþýþÿÿ	
+
+
+
+ !#
+#%),.2230.,)&"!
+
+		
+
+
+
+
+
+
+
+ "   !  
+ #$%%&')++-0.-.0538;<A@AFJNSW\agmt~­¹ÆÑáð0F\mx ¬¹Ç×âæìêÝÅ®lY@,
+üêÞØÉÄžžŽ¯Š¯wodVMGB=9640.,+/''#"!
+
+
+"
+
+!
+
+
+
+
+
+
+
+ÿÿÿÿþþÿÿþÿÿþþ÷
+©+þýýüûüýüüúùúûúüýúùùùùùøù÷øøûú÷ööõõõôõôññõôôôòóðôòòüõñððïîîíìîïîïðîîíîííìííîíííííîïïîîòôñòóôóòôõöõõôôõöõö÷ö÷÷÷÷ùùùøøùûùùúûüýýþýûüýýþÿÿ!
+
+
+""%),28;>>=;;3/+)(# 
+
+
+
+
+ ! ## !  "%'&()*,,++./21456:=BBDGKOSZ`cipv¬¹ÆÒáîþ(9M_hpy«¶ŽžºŽŠpZI7(þóâÕËÁœ··°«¥ysj_TLFA=842/-,*)''$!! 
+(&
+
+
+
+
+
+
+
+
+	ÿÿÿÿÿþÿÿþþýûûýüüûûüüþüüüûüÿüûùúùúùøýùøøûùøööôôôôóóóõ÷óõóñôððñò÷óîîîîíììììîîîîíïîîííììììììíîíîîïïïóöñòóóóóôôõôõõõöõõö÷öö÷÷øùùøøùúúùùúúüüüüûûüüþþÿÿÿ*		
+	
+$)+07<@BIIGGC=850*$!
+
+
+
+
+
+
+ 
+ !
+!"$"!%'()))+,+-.2;64569;?BDGKOT\bdiqwª¹ÇÒÞìø
+)>NV[^er~}oZI:,"	
+øíÜÐÄŒ·Ž²­¥~yri`VOIC?<830.+*'(%$#!
+
+
+
+
+
+
+
+
+
+
+
+		
+	ÿÿÿÿÿÿÿþý
+
+ÿýûûüüüüþüýýûÿ
+ýûûúùùûúùüúøùøøø÷ööõõôôóóóôñôòñóõòñòðïîíííììðòíîïíîíïîîìîíììììîîîîîïïððñóñôòòòóóóõôõöö÷öõõõöõööø÷øøø÷øøøúúùúüüûûüüüýþþþþ
+
+
+
+'(%-4:@FKOVVTQLHE@5-($
+
+
+! 
+
+
+   !
+
+#%'$#(()+)),--/23<85579FABDGKOT\adjqw§¹ÆÑÛçðÿ
++9BGHNYfoomed_UF9,"þñåØË¿žµ³®¬~tkb[ULFA=974/.,((&$'#"
+
+
+
+
+
+
+
+
+
+
+
+				ÿÿÿÿþþ
+ ýþýüüüýýÿýüüüþýüùúúùùùùøøùø÷øøø÷÷õööõõôòòòñ÷ôñôøóòñðîîïîíììðóíïðíïíîîíùõîíííííîïïîîïïîòñòóòòóôóôôõö÷÷ööööõöö÷÷÷÷øüøþúøùûüüüüûüþþüýþþÿþÿ	
+	
+
+"&*1=JJQ\glrle[ZVG;3.'!
+
+
+
+
+ "!!"! 
+!$&(&$41)++,++/14224579<YGBEHMPT]ceksy§·ÃÑØáéõÿ
+"+38=DLSTOHC;0( üõòîåÙÏÈÁ»·Žª¡ymd_VOGC@<742.+)('$##$ 
+
+
+
+
+
+
+
+
+
+
+
+
+	2-ÿÿÿþýÿÿüüþþýüüüüüýýüûüûúúýü
+ùúúúøø÷ùøùø÷ø÷öööööõõóòóòòüòòòôòñðïîîïðîîííîîïïîîíïïìøôîëëììëîïîîíîïîòòòòòô÷ôôöõõõ÷÷õö÷öö÷÷÷÷÷øøû÷þûùùûüýþüüýýþýþþþÿ	
+
+
+#'/9EN^iy©zq]NB71*"
+
+
+
+
+
+ !""""$
+!%&(&$72*+++/1,02144458=QFCEINQT^dfls{€¯¿ÎÖßåìóü
+$+-34321*$
+
+øóîèàÚÕÚÝËÄÀž® 
+rg^XQJGE@;62/,*(%%#$"!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		yþÿý
+
+ÿÿýþþýýþýþýýüûüýüüüüüûûûõ>øùùùøùùûúúùøù÷öö÷öõôõýÿóòòøòóñððòóñîîïïîïðíïððîîíîîîíîîìíëëìëíííííîïðñòóóóóùôôõõôõööööööø÷÷÷÷ø÷ø÷ö÷øùùúúúüüüûüþÿþýûÿÿ
+
+
+
+
+"$*3@KXm¯ÊðéÃ¥~dVJ>3,'!
+
+
+$ ""$  !$%%''')*)*5:-031544779<AEFHKPUY^emry³¹ÇÏÛßáçîô÷ú	
+
+ûôëäÞØÑÌÅâòÃŸ»Ž§{kaYTNGEC?:410-(&%$$"""
+
+
+
+
+
+
+
+
+
+
+	ÿÿÿÿÿþýþýýþüýýþþüûýüüüüúúúúúø÷ùøøùøûùúúøøùúøøôñó÷õõóôóóôòòòñò÷ôîíîðñîíïïïïîîîïíîíîììîìëëìììîòðîïïòòóóóóôóôóôõúú÷õõõ÷÷öö÷÷÷öù÷ö÷÷÷ùùúûúûüüþþýü	%ýÿþÿ
+	
+
+"(0:GSe²
+e¹Ô1ÈlZMA5-' 
+
+
+
+!%("! !!$"$)+**+*+,/4/13467::;?ADGJLQTZ`elt{~¶±»ÄÒÚÚÝãåæêïõúþ
+	õêãÜÔÎÈÇÄ»ÊÒžžµ¬ve\VQLFB@<831.+'&'%$#!!  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	ÿÿÿÿýýþÿýþÿüüüýüýûùùûûúúùùúøùÿùø÷ùøùúú÷
+÷÷ôõóôöóôóóòññòôóïîíðòíêîíîïïìíîëíëíìììíìëêëìîñïììíòòóóôõôôôôôøþýøõõõ÷÷öö÷÷÷÷ùøøøø÷øùúúúûýÿþýýþ
+)þþþýÿ	
+
+Z$
+#*3>JXqäk6šiñ¢x`RG;0)#
+
+
+
+
+
+
+  ###%$""%&'*/-++,-15145569;;==ABIKMPTZ_ektz~Š±ÅÉÑÔ×ÚÜÝßäèêìïóöøùóöðòßÓÌÊÆÁœŸºŽ¯«±³«rbXRLIDA>:62/,)&'%$$"!
+
+
+
+
+
+2F
+
+
+
+
+
+
+
+
+ÿÿÿþýüýýýþýýþýüûüýüûûûûûûúøøûøøúùøùùø÷÷øð[Á[îõõòóóóôøôóòðññòñððïîïííïîîïðíííììêìíëëììêîîëìëììëëóóôôôõõõõõö÷÷ö÷õôõö÷ö÷÷ööø÷ù÷øøøøùüûýþýýþþÿþÿþÿ
+c)
+
+#,4?N^|µÀªâæ·Ö±jOC8.&!
+"
+  
+
+
+
+  "&%&&&(',3/,--.002354789:<=?BFIMORW]cmwu|ŠÇÂÅÌÑÔÙ××ÜÝÞÞàâåãâßÖÕÍÇÁÅŒ¹¶³³¯«¯µ°€Âp`UNIFCA?;72.+)(($#""! 
+
+
+
+
+
+ )!
+ 
+
+
+
+
+
+
+
+
+
+	
+ÿÿþþüüþÿÿÿÿÿýýýýýýüúûüûúùùùûúþøýûùøøùïjê÷öôôóôôööõóñññòòððñññðññïïðïñïíïììíîìëëëêññììëìíìëôóôôôóóôóôóóöø÷õõõö÷öôõõõöö÷öøø÷øøþ
+ùûýüþÿÿþþÿÿ	
+
+"$+3@Q`¿È¹åæ¡œªeNB6,% 
+
+&3
+",, (
+  #'&'(&''(*-.,/312256889<<??@BEGJNQV[`q~qx~
+Š°œÆËÎÛØÏÒÓÓÑÓÖÔÏÎÉÄÃ»¶µŸ°®­ªª§¢³ØÌËr`RJFDBA?<72-,+)(##!"" 
+
+
+
+
+
+#3(
+
+
+
+
+
+
+	ÿÿþÿýþÿÿÿþýþýýþýýýûûüúùûúùùùúúúúûýÿüø÷öõõòóòõö÷õõòóòññóóòòññïîïððòðîïííìííëìíìíììíìììììöôôôôôôôôõôõ÷÷ö÷öõõöùôõöö÷ö÷øøùùøøý
+ùûýúÿÿÿ
+
+
+
+
+
+
+
+#)2@Q`ªëP
+%iÙs\RD4,$ 
+x9
+
+
+"%&'%'(*+++-/1443359:9:=?AABCEHKMQUZ_ciqtzŠŽ»ÄÇÏÏÊÊÈÆÇÆÇÄÀœ·²¯«©§  ¢   £€ËÄ|r^PGCB?>=951.-+()%"!  
+
+
+
+
++S=
+
+
+%
+
+
+
+
+
+
+
+
+	
+þþÿÿÿþÿþþÿÿþýþýüûüýýýûûûúùùûùù÷øøùø÷öøùøöôöóôõóòòòóðñðððññôóññññïîîîððîíòñîëììêêìììíííìììííôôôõôóóõôõõõôôööõõõõõõöööö÷÷ø÷øúùùúúúûûýù!Åþÿ
+
+
+
+
+
+!(1=L\vÀ
+Â¥[°}hVNA1("
+$E
+
+
+
+"$&'')1-*,,-011238;;;=@>AAADEILMQUWZ_ejrvy}©ŽŒÀÂÅÇÄŸºº¹·±²ªŠ¡ ¡
+~{zvomnfWKEA><;9632.+(&'% 
+
+
+
+&P>
+
+
+
+
+
+
+	
+ÿÿþÿýÿþþÿþÿÿýûÿþúûüþýûúüüûúùúøùúøøù÷ööõõôôóôôòòòòôðñññññðïðððòñïïïïîïîí÷öíììíëìíìíîííëëîíïòôóôóòóôõôôóôöøöôõóôôööõõö÷ö÷ø÷÷ùùùùùúûÿ!2ÿÿÿþÿþÿ	
+
+
+!&-7CPcz·ÚúëÇ­kYKC9-&!
+
+
+
+
+!#&'5.**+.../1125::;IODC@@DHIKMPVXW]egnruw{¢¶¹ž¹œœžµ±°¯§|{{{wtskfa`XOGB=986410/,(&#"!
+
+
+
+
+
+	
+
+
+
+
+
+	
+ÿþÿþÿÿÿÿüûúúùûüüýüýûúûúúúùùøø÷ø÷ööõõôóóòòóôóòòòòóòóòñññïïðïïïðñöíïîîìëííììëìíííííëëìííîòóóõôôôòóòòòòõ÷õôôôôôôôõõù÷÷ùû÷øùùúúùûüüþþýþÿÿÿþþÿ	
+	
+
+
+ %+3<FUgp~wl^NE:0*%!
+
+
+
+
+
+!"#&*)*++../123369:<wÞ|=BCBDGIJPWVTV^gdiotstx|}€©¯°³Ž°«§¢
+{xxwvtttqnjb\YSOKF@9541/,*)'&%#"" 
+
+
+ 
+
+
+
+/gD
+
+
+
+
+
+		
+ÿÿÿþýþÿÿÿûùøøøøøùûúÿüúúúùüú÷öúû÷ö÷õôóóóóóôóòñññôðñ÷õñððððïîìíîíîîììíìíìêëìííììëëìëëëôóôõóóôóóóòô÷õôôóóóõöõöõôøøøøùùøùùúûüýýþýýþÿÿýÿ	
+
+
+
+	
+
+"*5;@NRWbimjd[TOHA4+&"
+
+
+
+
+
+
+
+
+ ""!%&'&D@,-/23359::=MPDCDFFEGJLUYTUY^aemmnrtzxz~¯®~vrponmmnopjfa\_RMIEB>830-*11%&%$$!!
+
+
+
+
+
+
+0mI
+
+
+
+
+
+
+			ÿÿÿÿÿÿÿþýÿÿÿüúüûù÷ö÷ùúúýûúøùùúøøùø÷÷÷ööõóóòòòôòñññóõ÷óñï
+òïððñòðíîïîîîíííííëìîíììëìììíìëëõóòóõóóòöóó÷öõôòóôôõõôöõöõöúú÷ùøøøøûúûüüýüýýÿÿ					
+%
+%/68@DJORTQPJFB=7/'" 
+6
+
+
+
+
+
+
+##!$%%2;2+,.13568:;>@7@EBDFEEIJKNRSTWZ\_ghpmmpqtw{
+ 
+~{zwpokigeeghfef`ZXXvNMTG?=81-+$EM!##"!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+ÿÿþþúúýýûùøöûüúûúûûù÷ùùøø÷÷ø÷õõôóóôôòññóòñòóóôóòòñîïòñîîîïðîîîðîíîîòðëëìííîîëíêòóóóöóóóöóüòóôóóôôüûõõùõöö÷úúøøùúúúúúúûüþþpýþþK	
+
+
+@1
+"%(.4:>ABDDC@<71-+& 
+
+2
+
+
+
+
+"
+
+
+  ##&(&,+)-/014779;<AAAADFFFFGHJMOQRTVY^bbejmlnqruvwx|
+~~~}~~xvpkhedhe_^_`b_\[VSRQNrÜf<<?7.*'-/$#"! 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+	ÿþþÿþÿÿýúùûüÿýööøüüý
+ûýùùúùù÷ö÷øøøõôõööôòòòóñòñòðïñòñððòðîîîîîìììëìíìîíîíìììììëëëêííêëéôòòóóóòôóòôôôôóóôôôõ÷öôõ÷ööøøù÷÷øùúùúûüýüýýýþþýÿþ9
+
+
+
+
+ $$&+/2379;843/+(%# 
+
+
+
+ 
+
+ 
+"#$%,3,'+-./1467;<>@BBDKHEGGFHJLNPSVWY^_deiljnppqruv{}zzz}yxuvwxxrjdfc`]cbYUTVVURPNLJGH3982,(%#!!
+
+
+
+=G
+
+
+
+
+
+
+
+
+
+
+
+
+	ÿÿÿþþÿÿÿû÷úüÿõö÷úüûùùøøøùù÷öþüööööõõôòóôòôòðñððñññðñðîïïîííîïíìëëìîîíììììììëëëëêéëëëóôññðôòòññòøõñòóóòûòóôõõõùõö÷÷÷÷ùûûù
+úüþÿüýýýÿÿþÿÿ
+	
+
+
+
+
+
+
+ #$'),./-+*'%"
+
+
+
+
+
+
+
+
+ !!!(/*&()+-/2788:<>BCDGGFHGGIJLMQWXVY[^cdfmjjmnpqsszzssuvtsplsøvaa_V£TVTPOPQQKHIGDFGEF<751/-)%#"  
+
+
+
+Yx
+
+
+
+
+
+
+
+
+	
+
+
+þÿÿüøûþÿû÷÷ùúüüþÿÿùúúøøúûúø÷÷÷÷öõõòôô÷ôóôòòòñôóññïïïíïííëðêìììííëëííììîòòëëíïêëñòñòñóòòñòòòñññòóóøúóôóôõõ"üóõ÷÷÷øùûûúýüûýþÿýþþþÿÿ:þ
+
+	
+
+
+
+ $%&&&&&$$"
+
+
+
+
+
+
+
+
+
+!  "$%%%(+-.15789<=ABCEFEFFGIJKMQVUWY[^bceiiklnnpqqrsstpmlkhghbc\YVnOPMNLTvyFCCC@=>;87420.,'#!"!
+
+ 
+
+
+
+
+
+
+
+
+
+	
+
+
+ÿþþÿÿÿýûûüúùùùúûûûüþüûúûûøùýû÷ûû÷÷øøööõóóôøóòóñòóñõóððïïîíõùïíëìïëëñëëìëëëëìììíìêéêëêéóòñññ÷òòññòñòñðñòóõóóóóó÷öþýþõøøøøøúüüûúúþýýýüþýÿ
+	
+
+
+
+
+()"
+!##"
+
+
+
+
+
+
+
+%a/!! !#'%$(*,-/2479:;=@BDBPKEFHHILOSUWY]^_bbeghhjkllllmooljgedb`]ZYYWVSVRLIHHGIQOC??<:7766721-+)&# !
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+	ÿÿþýÿþýüüûúúúúúûúüüúùøüúúùúøúùö÷÷øüúõõôôôóóóóñòóòóòïððîîíííìììêëêêìêêëêéèéêêëìêèèèêééññïîïòðððñññòñðñññòòòòóóôôóùøõö÷ööøøøÿúûüûûý
+ÿþÿþ			
+
+
+
+
+
+
+
+
+/,
+
+
+
+
+
+
+
+
+
+
+&$
+
+0úM
+ !!"%$#&(((-.01688:=>A@JGDFDGIJMPSUX[[[\^`abcdffjjijikleda`_\ZYVVTRPMKHDCDDCB?=<;9665432/.+)'$ 
+
+
+
+
+!
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+ÿþÿÿþýýüüüûûûûúüúúøøüøúùø÷úùö÷÷øúùõõõö÷òóóóòòòòòñùøðïîíííìëìëêêëéééêëéèèèèêëêçèëèééîîíííîïîïñððññððñññòññòñòòôôõôôôôõö÷÷÷úûùúúûüýþþþÿÿþ
+	
+
+
+
+
+
+¹&
+
+
+
+
+
+
+
+
+
+
+
+
+'!
+
+(¿H
+
+  !#%''(.7GP3779:;>@>?ABJLGIKMPRUUVXXZZ\]```befddefea_^ZYYYXVTSLLKHECBBAA@?=86534340.,*('$""!
+
+!.
+
+
+
+
+(			
+
+		ÿÿþþüýþýüüüÿþüüúûûùúùùø÷ùø÷øùøöööõö÷ôõôõôóóòòñ÷öòñïïïíîìîîëììééééêêéèüüêëéèèëçèéìííîìíïïïððððòñðñññóñòòðòóôõóôõõõ÷øøøøøúûüûûûûýüýþþÿ	
+
+
+
+
+
+
+64
+
+
+
+
+
+
+
+
+
+c
+"H
+
+
+%!
+
+ !"%')-6EZ[35889;<>????KMFHHKMOPRSUVWWXY\]``_``_`aa_[e]VVUSQXpWEEECBB@?><:76533920+)(&%&#!!
+
+ 
+
+	
+				
+ÿÿÿÿþþþýýýüüýõüúûúùøùú÷þÿù÷øùùööøþ÷ùöúöõôóóóññòòóòðïïíîîïüììéèèéééèééòñéèççèèçççííîïïíïïððññðñòñññòóòôóôóóõö÷øõõ÷øùøøùøúüýûýüüýýýÿÿþ		
+
+
+
+
+
+
+
+
+
+#
+
+ bZ
+
+
+
+
+ /»
+.
+
+
+
+
+
+
+
+!##$)5<;&5476899<??>>CEDDFIIKLOSQQRTRTVW[\]\]^Z\\[Xb\STRPMN^OCCB@?><:;964431230-(%$+'"!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		ÿ	$\Z
+ÿÿþþÿþýýýýýýüüûú
+Húûúúùöøø÷þ÷÷÷øøööùøúøûöóòóòóòðñññòðïïðîîìôìêéêèééççèéèçèççççèæææíîîîîìîîïðððïððððñòññóóôõóôôöõóôõ÷øøø÷÷øúúûûûûûûüþþþþÿ	
+
+
+		!}
+
+
+
+
+
+
+,5
+
+
+
+
+
+
+
+
+
+
+
+!!
+
+ $*dÕA424767:<;<<>@ABDEEHIKONMNRaXRRTVZYYYVVWXVY^VQQONQNFCBA@?=;97654311..-.)&;,"# 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	|x;ÿýüûüýýýüûüýù
+úûúûúú÷øùø÷÷÷÷öö÷÷øñ÷ù÷öóùóñóóòñððóòîîðîíëêëêêëêèèééêêêêèèèèççææåìîîííìíîîïïïðððïïïñññòóòóóòóóóôôôõö÷÷ø÷øùùúúûûþüþýûúþÿÿ
+
+
+
+
+	
+
+	
+i_
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"!
+
+(²ÂN323566899;;<>>ACCCFGHGJJJOd[QQQQSTSSTUWVUWVTSKNNOMIFCA@>=;8763221/-.-+(%?.
+
+
+
+
+
+
+
+
+
+
+		æÝO
+		üüüýüýýüüýýûú÷úúüûøøøøø÷÷÷öööõõkø÷ôõõüøòõóñðïñòíííîïëìêëîêéèèêêìëììèççççææçåëíîííìïîîðððñðððñõõññòóñòñòóóóõöôõ÷÷ùóìøúúùûúü! ü ýÿ
+		
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#$)SŽ=20234466799:<=?BBBCEEEEEFHKONNMMOOOPRUWSSTTUWMOMJGHFB?=;;97651//1/,,+)'%*%
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+/jj
+
+þþýýýþýýýûüüúúúúúùýû÷úø÷øø÷÷÷ööõõ)¹ööôôôòýóõóññïîîîîîïïëìêëîëééêééêéêêçèçæææåææêêìíêìïíïïîîîïððòøöïððñðòññòôôõöõõööîkÜ+öúùüûüü
+üÿÿÿÿ
+
+			
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+.%
+!$(.""../12245456778:<????CCBBCDDGHIIHIJKLNOQRPQPUXYVTOLHDA><:988:92/--10,*)'%"
+
+
+
+
+' 
+
+
+
+
+
+
+
+
+	
+	
+	
+
+ÿýüýþýûûüûüüûûúúùùûúø÷øùø÷ø÷÷÷ööøøù÷öõöõôóñõóòñðñðïïïñóïíìíëìëëêëëêééééççééçæçææçêêêëëíììîíìííîðððñðïïïïðñððñôõôõöõõöízý/õúùüûú÷ùûüÿÿÿþþÿþ		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+##%#"'*-..1323344576678:==ABAA@ACBFFGFEGIJKLMNQRU[[\]\XSMFB><;98:<:31/-//-*(&#! 
+
+
+
+
+"2
+
+
+
+
+
+
+
+
+
+			
+	þüüýüûüüýüüüúüúýûûúøøùùúùùøùúøùû÷÷ööõ÷ööõôóòñþððððïðòïíìíìíëëêíêëëëëéèèçèèçææåæììëëìììììíîïïíïððïðòñïðððððòóòóõööö÷ø	ûùùúûúùûûûüûüþþÿÿÿþÿ			
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+"!! %%&*///013112333577:?=>?@?>@@oUCFDDFHJJKLOTX\]^ba`][VNFA><99:85343-.,,)(%"! 
+
+
+
+
+
+'
+
+
+
+
+
+
+
+
+				ûUCÿ	üýüúûûûüþûúúúýýúùùùùùùøûüúüúùõõôø÷ööôóóïðïïïîíííîðîííëëëìëîíìêèêéèççæääãåìêêêêêëëëììòñîîîîîðððîñïïððòòòóôõö÷ö÷öô÷ùùùúùùüúúúûýþþþÿþ
+				
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(%*)+,,/////01003446;9:=>>>@>·j>CBBEHJJKPWZ]bdfhgfd_ZUMF@<:9755332/.**)&#! 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			
+
+
+	ùeZ
+øw(÷ýûûýýüýüüúûüÿüûúúúùûú÷ýþûûÿûùø÷ú÷õôõôñññððððïîíòöðííííîîðïïîêéêéèçæææååæëìéèêêêêêêìíìîîììíïîîïðïðïðòñòòôôööõõöøøøùøøùúúúûùûþýýýýýÿÿ	
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+#!
+ 
+!$'()(),--..-.1311233587<<==?:AA@ADHJJLRX^eluz~}zulbZXWMB=;99751.0/*)(%%"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+	!"	
+
+ÿþýýýýýûüûýÿýýûúüüüüÿûýþþþþþB3ÿüûüú÷÷÷õôóòññððïîïïïïñïïîïñóïîðíêêêêéèçèçæåëùêéééêéêëëëëìììììîîîîðòòðññòòóóóööõö÷ùù÷øúøøúúùûûüýýýþþþþþ
+
+		
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+!"%&'()*,,,.0005B?/123358<;=>?AAABCGMMKOXam~¡¥¢vgixDB=>?951.--))'&'"  
+
+
+
+
+
+
+
+
+
+
+
+	
+	
+
+
+
+
+
+	
+ÿþýþþüûûûûûýÿüûûùüüüüûûýÿ
+ÿÿüýû÷õõ÷õñïïïîîííîîðìíìíîðîîíëéèéêèççèéåãèéêéëêëêëëìììíìíïïîîïïòòôòñðóóôôóõõö÷øùø÷øüùùúûúüýþýüýÿÿþþþÿþÿ	
+
+	
+				
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "!"$%()'((),00.2MO+0/012487;:COC>DFHLMOWar£¹ÇÒÑÌÅ»²£zxÉEH@<:961/,*)&%'#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+	ÿÿÿÿþýýþûûúúùûÿúüúûûýÿýüüüþÿý4|$òõõùøñïïðïïíìíîðíííïííîîîëìíéêèçééèäãéééçéèçèééééêêëìíìííïï÷ïïððññòóóôôôõõö÷÷ö÷øùùûøùúüýüüüüýþþþÿþþÿÿ
+		
+
+
+
+
+
+
+
+
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ !"%&-+(''),,23-.--.01284889<==?GKLNOVat«ÈÞðþøïìÜÆ¹®}bTQLE>::72/-*(&#$$ 
+
+
+
+"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+ÿÿþþþþþýüüûûûýùúøûûüýþýüÿ
+
+
+
+
+
+
+
+ÿ+ÑIî÷öõòòðïñðîííîíìëïïìëììììëûýççæçéèéäåéèèèçééêéçèìíëìííííìïïðïðôññòóóôõõõôõõøù÷÷øøùù÷ùùûúüüüüýýþÿÿþÿþþþþ
+		
+
+
+
+
+
+
+	
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '
+ "##&(''&(***,++,,,..293479<>?@CMQOU`p®Ðè':6"
+ñÙÇœ±w`TPKC;853/,)&%#" 
+
+
++
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			K>ÿþÿÿýýýüýýþüûüüüüýýýÿ	
+
+('033)
+	ûúøõóòóðïððïíîððîîïîíîîíìëëëëéèççèèçææèéèâX
+èòïåìíðííìíîîïïóòðñðñòóóôôôõôõööø÷øøøøùùùúûüýüüýýþýýþþþÿÿ	
+			
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ê 
+
+!
+!
+!!!"$%&&'(''())+-....1265BF;;=@FQUSaršÊê	Dqg?ùÞÄºªp\RNH?952/))&"#! 
+ Z
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+,Mí#þþýýüüûüüûûûýýýþÿÿ'<<EObg[J<2<$	ÿÿýúøöõòðñðñîîîóðîííìëëìííëëêëëéèèèæçæçèèéìôêëëêîðïïîííîïïðïñóñïòóòòôôôôõõõõööøøùøøùúüûûûýýýüüýþþþÿÿ
+
+							
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Ð
+
+
+
+
+
+ !#!"#$$'(('''(*++,.-,/013F;68;?JW[Zbw»ã0y¶ÝäËQð×ÂŽ~bRNJA:610+('"! 
+
+"#
+
+
+
+
+
+
+
+
+
+
+
+
+	
+	
+
+
+	
+
+
+
+				+òÚ%ÿÿþþýûýüüýûýûúùüýüÿÿ":S^m°·cItj%	þüùôóóññðîîðñíìíìíêééëëëëêëêéèèèæçéææèèèççëêêêéêììììíîîîòíðïòòñòòóôôôôôôõööö÷ù÷øøúûúúûûûýýûýýüþþøþÿþÿÿÿÿ
+			
+
+
+	
+	
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-
+&0
+
+
+! .#"!"$&&&'%%'()))**+-0/16457:>JX^foŠÉíM í.E+â=áÌžŠmVQMB95/-*'$""
+
+
+hn.!
+
+
+
+
+
+
+
+
+
+	
+
+
+		
+
+
+
+
+
+ÿÿþHAÿþþÿÿþýûüüûüýûùýýýþÿÿ"1[}Ž:' ùŒfR0üúþýõôôòñðîïñîëëíììêééëìëêëëêìéçéçææææçççèçèèèéêéêëëëìíííïìêïðïïïñóôôôôóóõöù÷÷÷úö÷øùøùúûúûüúùùûýüüýýþýýÿÿ	
+	
+
+				
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+$.
+
+
+%%" !"$%%%%))'''(+''*,.-/0348;>IZdmy²Ñî
+Q·"©·kÈSé×Á©sZOKD93/,''!"# 
+
+¥<
+
+
+
+
+
+
+
+
+
+
+
+	
+"
+
+
+
+
+
+
+
+		
+
+
+ýùùùþþ	ýüýüûýýýÿÿþÿ	$/E¹×5Ä¥=ê²J3"ýûùõôóóòóññðíîìíììëëëíìëëëëëëéêèêìçäååçççèèççééêëëëëëïîíîííðïïðïðòòðòõôõ÷÷øö÷õöøûùúûúù
+÷ùúûþÿüýþþýýÿ	
+					
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-$
+%
+
+
+!
+
+!!""'&%%'('&&(5=&)*+,-/25579>K]nw¹ÔóR¿NÁ×ÜÂ
+w
+òÞÅ©xaSMG=5/+'%"#$!"
+
+
+! 
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+ýøööøúøþüýýüûþþÿÿüþÿÿþ
+(7RÝ%¢' ù/ÚÂc4#	þú÷õóóòññððíðíííììêëëìëêéêëèééééçèçäåæççèèéèéêêëììëëìîîîïïòïñðññòñóóøûöõõõøù÷øùö÷øùùúùûû
+øúûüüüþÿþÿÿþþÿÿÿ		
+5C						
+	
+
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
++$
+
+
+ 
+
+
+
+ !"%"'&%%%#)/+/$'(*5--03347=I\rµÍçEŠFÎÜÛÈ42÷ßÅ¥u_OJE<5,(&#" 
+
+
+
+
+
+
+
+,+
+		
+
+
+
+
+	
+
+
+		
+					
+
+øõ÷ùûú÷ùÿÿþÿÿþýýüýþýüûûþüýÿþþ	%8uÇãnNº_úò1
+ýúøöõôòñññðïïîîíììëëëëëëêêêéêëëèçèçäæåååæèèçèéééëììëëíïíîíðîïïïðñóóòòóôôôôöøöøøö÷úùøøøùùúûúúúúùúüþÿýÿÿÿÿ	
+	
+				
+	
+
+
+
+						
+
+
+
+
+
+
+
+
+
+
+
+& "!"#"#%$(/*"#%&((0*--13989FYl~®Èåý1|ñÌ¿
+§@üâÅ¡mZLHD80+&$$#   
+
+XJ
+
+
+
+
+
+H1Ë»
+
+
+
+
+
+
+		
+
+
+	
+ýööúÿþúõþý
+ÿÿýÿÿÿÿþüüýýûüüüüýþýþ$4hÈöãBÇ4QUÎoé0
+ýù÷õôòòòðñïðîòñíëìêêëëíìêêëìêèééçççäåååãåæçææçèèéëìëëìîíîìíîîîîîðññòòòñòóõøý÷÷÷ø÷øùøøøùù÷ùúúûûúûüüþýþþþþþÿ
+			
+
+
+	
+
+	
+
+
+
+
+
+
+
+
+!%"
+
+
+
+'
+
+  !/*#$"(+$$$%'''''+,/2679BSbs
+šÂàóU¥afAð=ûàÀvbSHC@6/)&#%!
+
+ 
+rn%
+%
+
+
+
+
+."{y
+
+
+
+				
+					
+
+	
+
+
+þùõ÷üúöøý9
+þÿÿýüüûûûüþýþýýÿ#4D~ÚîÿX°éû3öÏv,	ü÷ûûóóóòðñðñïððîììëëëêìíìëëëééëéêææãäääéèäåçæéêèèêììëêìîôîíïîîïðïõõñòññòóô÷ø÷öø÷ôøø÷÷øøø÷øûùøúùùûúüüýþýýýýþS2û					
+
+
+
+	
+
+	
+
+
+
+
+
+
+
+
+'$
+
+ 
+
+
+
+
+
+
+ 
+E<"!!##$$"$%%&&%'),/258=L\i{ºØê*e§â÷æœ}3ûÚ²hVLE@;2-'$""!
+
+!-*
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+		
+
+
+
+	
+
+þùöøû
+úúýÿ?þþÿþýüûûûûþþÿþÿÿ
+*9N
+ÉÛNjZ%Òœµ]
+û÷øùóôóñððððïîïîííìíìêëììëììéêéèèçéèãããéæäåæçééçéêëììëëíñî
+òððïïõõòòòóôôõõõ÷ö÷ö
+ú÷øùùùù÷øö)öúúûüúüýýÿÿþýþ
+þÿ				
+
+
+
+
+
+
+
+	 
+
+
+
+
+
+
+
+
+
+
+
+  72!!""!""##$'&%$&(*-2569DTcs®ÈÚð
+-T~S
+ôÈsZLEA<6.)&%"  #
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+	
+	
+		
+	
+
+	
+ÿü÷÷úýÿù÷ûþýÿÿÿÿÿÿÿþÿýýüýûûûüýÿÿÿ
+,BSqºíòÌŒ{x5
+	þù÷õôõôóòñðññðñðîîîììììíìììëìëëéêççéèââãäãäæåæççèéêëììììííîòòòñññòóòòóóòñôùøöö÷
+úøúúúùùúú÷
+öúýûûûûþýþýÿý				
+
+
+
+	š?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+
+!#  ""##$&$#
+%)+.1357=IYfsžÊãõ5LQt<Øš}aNA<;82+'%$" 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+	
+
+
+	
+
+
+
+	ÿú÷øöøûø÷ýÿÿþþýýþþþüûûýüþþþÿ
+-=N`nšmXE0
+û÷öõôôóòòòñòððððîîíîííììëêëêëêëêéèèçáâáãääååååççèéìììíëììíîíØëñø÷òïññòóññüù÷öö÷û÷÷øøøùúùùù÷øùúüûüüþþýýýÿÿþüüo4
+
+
+
+
+
+	
+
+f,
+
+
+
+
+
+
+
+
+2#'
+
+
+
+
+
+ 
+
+    !#!"#!##+c,'*-03457?NXdv§ŒÍÚéú®AÛ«dQB8563/(%$! "
+
+
+
++P8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			
+
+	
+
+
+	
+
+
+
++ÿýúöôöùõøþÿþþþþÿýýýþýýúûüüûûüýýþ
+
+1BCKWJ=*
+	ýùõôôóòóôññðñðòððîíîîîîììëêëëêêêêéèçæâåæääååååæççèêëêêìêëêìîýÓ@ðóõðïññòòñìl3óõööööö÷÷øøúùøúûúûùúûúûÿýüýüüþÿþTP
+e.			
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+¯[;I 
+
+
+
+
+ ""! ! $"15('*.13426CPYbu¡¯¿Í×ÜããCô¥cSD7122/*&$" #
+
+!7)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+
+
+	
+
+
+
+
+
+	
+
+
+ÿþûøùþþÿÿÿþýüüþûüþüüýüýþþÿ
+
+ 
+þúø÷õõôóô÷òñññòóòñïððîîïíîïìëëêëêééèæçáåèåãääæåäåæçéééééêìëìïJeðîðððñññññï
+E
+òööøö÷öùø÷ùúøùúúúûûûûûúøûüüüüÿþþÿÿ;9	
+
+	
+	
+	
+
+
+
+
+
+
+
+¹"(
+
+
+
+
+
+
+
+
+
+  !! !"$#%,1,()+.23108EPV^l¡ª®±µ±t`PE91/00,&'-! 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+&(
+
+
+
+
+
+	
+	
+	
+
+
+
+	
+ÿÿþÿýÿýþüýüûüýÿÿÿ
+
+
+	þûø÷÷öõôòóõóóòòóôòñðððïíïööïìëêêéêèéèèèßââãâääçæäæêêèêêëìêìëîðøB
+ððððñóòññòõóëðö÷÷ùø÷üøøùúúùúúúûüûüû7ýþþÿÿÿÿ
+
+			
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ !! !!###$L=*'))-110019ENQWf|zzndVLB70.//-(%'+! 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			
+
+			
+
+
+
+
+	
+
+	
+	
+ÿÿÿÿýüýýþýüúúúûúûýÿÿÿ
+þüù÷ööôôôóóóôòóñòóñòñðîîîìíöõìììêêééëêééçâäåããåæåæåçðïèêêëïìëìïïðçìïïïïðóóñòóôôõõööù÷öüøùúúûûûüûûûüþü/ýÿþÿÿþÿ		
+							
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+!""#%J:)'((*+..--07AIKOV[dda^WOJE=5.+,,+(%$#  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+		
+ÿ
+ÿþÿÿÿüþþýûýüûûûüüûüýýþÿÿÿþýÿÿýýüúøöõöõóóôõôòñòòññòïðïïîîíììëëììíêêëéíêééåßãåããçæåæääæççéêéëîíëììîíîïïïïïðððñóòóôóôõ÷øü÷÷÷úúùúûûúúûûýüþüûüüþþþÿþÿÿÿÿ
+	
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+$JM
+"
+
+
+
+
+
+
+
+
+
+! 
+
+ ##"#%$&')%%'(+-,-./3:@DGKQSPLFB=81-**++($#"! 
+
+(
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+	
+
+
+	
+	/M			
+	
+		 ÿÿþþýÿüüüýúúûûûúúûúúüüüýýýýÿþþþûûûûüùøøøõööôóóõöóòððððñðïîîïîíííëëíêéìéêëéêéèæåßàáäâããääãäååæèèèééëêìëëëìîîîïïïïððñòóóòôöõ÷úõ÷ø÷øùùûúúúúûûýþûüüýüýýÿÿþÿÿ		
+
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+;D
+"
+
+
+
+
+
+#'
+!!!$!$&&'(%%$'))*+.//047;@DGHD>71-,)()**%#"  
+
+,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+
+
+	
+
+#8	
+	HIÿÿþþþþýÿÿýûûúúûûûùúúúùùûûûûûüüüýýþüúùø÷øøùøöõöõôóññòõöððïñððïïïîíîîìììùýéëêëééèèææßâßâáàâãããääåççèèêêìêìîìëìïóòïïðïðïïòôóóõôôöõööùùøøø
+	úüûúùûûûúúúüüýþýýÿÿÿÿÿÿÿÿú			
+
+		
+			
+
+
+
+
+
+
+
+
+
+
+ 
+C\&'!"#%'(&#"##%'((*,*,--/02468:60+*)&&&))$"! 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+		
+
+					§š+þ
+ÿþþþþýüûüüûûüúùþüùùúùúúûüûûûúûúùûùööøùôõôôôóóòñþõððòðòñïïíìíííìë$7çëêéééèçææßßßßáàáááââãååæêèééëêéëêêëðû÷ðîííîîïòòòóôóô÷øööûøøùùùúýýûúúüûûûûûûüýþþþþÿÿþÿ
+;
+
+
+
+
+
+		
+
+
+	
+
+
+
+
+
+
+
+
+$$" #!""#&!$&&'%$%$#$**&'**++-0.1/5183,+)'&&%'(# !
+
+
+
++"		
+
+
+
+
+
+
+
+
+
+
+
+
+		
+
+	
+
+			
+	Èæ=ûÿÿÿþþÿÿýþ	
+üÿüýýûýüúûúúùùúúúúúûúùøúûùùÿýøùùøöõü÷õõóòòóõ÷óùïïñðïñïïíììëëíë%ëêêééèçæçæàßààáááââãäåäåçèééêêëéêììëîíîïïîîïñðïðôóôõõ÷ú÷÷ùøøùùúûüüûûûüýüûûûûüýýþþÿþÿÿý¯0
+		
+
+
+					
+
+*
+
+
+
+
+
+
+
+
+
+ 
+
+!  !$"&&$%'%"#$%'()()*,->5A-..*('(&##$! 
+$
+
+
+
+
+
+
+
+	
+
+
+
+	
+
+
+		
+
+	%G		
+
+
+			
+EJ	þþ
+_ÿÿÿþÿýûüÿüüÿÿûûûúùùùúúùúùøøøùúøøýýù÷÷÷õôüÿ÷óø÷òóöùúñòôððððîïîîîììììììéçêêééèåççææâÝÞÞäãáááãääääåçèèèééèêêëëììîîííîðññïðóóôôõöù÷÷ùøøùúúúûûûüúûþüûúüýüüýýýÿÿ-û	
+	
+				F^
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "!!!$%&%'%"!! "$')%&'')@S*$&&(''%#"!!! "
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+		
+
+
+		(J
+
+				
+
+ýÿþCÿÿþýüüüûûüþþûþûûúûûùùûúùùùúùøøø÷ø÷öõõöþøóõôóö÷ñòòòòðññïïðñïîìììêëëëêèéëêïíææçàÜÝÞßßßááâããääåççææéëèêêéììëííìíïðððïîðòôôôõöõö÷÷øøö÷ùûüýýýüüúûüýþûüüýÿÿÿÿÿ	ý4€		
+
+	
+"7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ !   ##%*)%"!! !#&'""#$$&'%$#%$##"!    
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+	
+	
+								
+ÿÿÿýþÿÿýûûüüýüüúÿù
+ùúúúùøúúúøøöøøöõõõôôôôóôõññôòñòññðïïñîìíííìëëëììêêêã
+ÅèæçÜÜÜÞÝßààáâããäæææçççèêçéééêëìììííîïïïîîñòóõó÷ùöõö÷ùù
+ÿûýþÿÿÿþüýüþüýýüýÿþÿÿ3 					
+
+
+
+
+
+
+
+
+
+
+
+! 
+
+
+
+
+
+ !!"##)&#"#"! !"#!!"#!"""!!   
+
+
+
+U%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			
+		
+	
+		
+
+	ÿþýÿþþþýþýýùûúûþüüûþüÿÿüúúûûùùùúù÷÷ùýöôôôõôóôóòôõññòñïðððîòùðííëëìëêêéëììëééêîêççæÜÞßßßàààäåâæèäååæçèçéêêêëëìííîîîííïðîòõòõóõôõõö÷øøí|úÿýþüüýþüýýÿÿÿþÿÿÿÿÿ	
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ !+'$$%! $#!! !  ! 
+
+
+
+
+ 
+
+
+
+
+
+!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			
+	
+
+				
+	ÿÿÿþþýþýúûûüüûùüûýýûüüüûûøùüüûûùøøøøö÷øùöôôø÷õòóôòòòòôõðððïïòB)åîîììëëêééêééêéçéóèçåÜÝÖÝàßßßââáäåäæçåçèçéëêêëîõëîîìëêêìîñòòóõóôôõõö÷÷ùýþ'/þýüýüûüüýþþýþÿþþÿÿÿÿÿÿþÿÿÿÿÿ	
+	
+
+		
+	#
+
+
+
+
+
+_% 
+
+
+
+
+
+ 
+
+
+
+
+
+# #%$#
+ÁR"&
+  
+
+
+ 
+
+
+
+
+
+
+
+$#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+				
+
+	
+	
+
+ÿ	ÿÿþüúúûüûúùüýýüûûûùúúúùúúùùù÷øø÷ùù÷ö÷öó	ÿööõôóññòòóñðïïîð6
+éïìêìììëéèêèêïêçèñèäåÚãxÝÞßßààááâãäååçæèèíééêìðîìííìêêëéíòñòôõòõöôõõöøùùùûþg=PO
+þþýûýýüþýþÿþýþÿþÿÿþÿþÿÿÿÿþÿ			
+
+		"
+
+
+
+
+
+Lu" "
+
+
+
+
+
+
+
+
+
+
+
+ 
+ !!
+ï5z
+%4i*
+
+
+
+
+
+
+
+
+
+%%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+		
+
+	
+
+	
+
+
+
+ÿÿÿþÿÿþýüüüýýüûüýýúüûûøúúúùøøøùùøøùù÷÷ø÷õýù÷÷õóóòóòòóòóõññðöûóîðíììëëêêêëìëëëéèêéèèÛëUØÜÞßàááâáâåæäæææèèèèêêêëìîíìíììììïòðòòòóôôôõöö÷ùüýÿÏ{Zw	þýýüüüûüüýüýýýÿýþþýýþýÿÿÿÿÿ	
+	
+
+		
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+ !$f|@ ! jd]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2
+
+			
+				
+
+#	'/
+ÿÿþþýüþÿýüüüüöùûü
+úúúûûùùùøùøøùùö÷úùöôõ÷ööõóòóóóòöóñòðíëïîîîììììêéêëêêêëêêéçèçÜßH
+ÛÝßàáááââãåçæåæççéèéíìêìííìììîñòïîññðõõóóôôõöööúüý
+aüñ3
+ýýüüûüüüýþþþþþÿÿþÿýÿÿÿþÿÿþÿ
+
+$
+
+
+	
+
+	
+
+	
+	
+
+
+
+
+
+
+
+
+
+
+
+!$
+
+"   !K9
+#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+	
+
+
+	^`
+
+tÿþüýÿþýýüü/ ùÿùùúüúùùøùøøùú÷÷øøõõööõùøóóòòóòù
+ðóñîïîîîîîììíìêêëëêêêééêìèôéÚØËÖÞÝÞàçêäââãäææååçæêééììììíííëìðññïîñòñóóôõõõöö÷ùùúüÿ$ ÿþýüüýûüûüýþÿþÿÿþÿÿÿþÿÿÿýþþþÿ
+lH			
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+     #%
+
+"
+
+
+
+
+
+
+
+
+
+$ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			
+	Wa
+>g
+
+		
+þÿýýþüûDJ
+öÿþøùúúùøù÷øøøùù÷÷öõõõõõõ÷õóòòñññóúðóïíîîíîîíëëëêêëíëëéèèèèéç	ðÚÚÚÛÝÝÞàïöèáââãæçêæçèéééëëëìííìëìðñðñøñòñóòóóôö÷öøùùúýÿÿþûþýýüüÿÿÿý
+ÿÿÿÿýÿÿÿÿ		
+S;	C>
+
+
+		
+
+
+
+
+
+%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+QY
+
+
+
+	
+	
+
+	
+				GU	
+
+
+	
+
+
+ýýûüüýû
+#ùúùúùúúùùøùøøøøùú÷÷õôõõõõôóóõõòòòññïñòïîïïîîííìëëëéêëëéèéêèëéèñêÙØÛÛÜÝÞßèìåáâãåäåéåçèëééëëðïíîíëìíïîîòðñòóóòÿö÷öõ÷úûüýþÿýþýÿûûûüþýüüýþÿÿÿþÿÿÿÿ
+þÿÿþÿþ	Á°ü	
+				
+
+
+
+
+
+
+
+1
+
+!
+19
+
+
+
+
+
+
+
+
+
+
+
+
+
+,$
+2
+	p
+
+
+
+
+
+
+
+
+
+
+
+		
+
+		
+
+			
+
+
+		
+ÿ
+ÿÿüýýýüùöùûûúúúùùúúùøøø÷ø÷øøöõöôõõôôôóööóòòòññòñïïñîïîííìêëëíîêëéééêèéèèæèÛÙÛÛÜÝÝÞßßáááãäãäåæçæêêëêêïîìííìììííîîóðñòòòûùõööööùúûýüüüýýýûýûÿûýÿüüüüýþþþþþþýýÿÿÿÿÿþ
+
+	
+	
+
+	
+
+
+
+
+
+
+
+
+
+
+
+.6
+
+
+
+"
+
+
+
+ -%
+
+
+
+!
+
+
+
+	
+
+
+	
+		
+
+			
+!
+	
+ÿþþþüüýüüúúúúùøøúùùùùùùùù÷÷÷÷õ÷ö÷ö÷õóòóôõõôóòòòññðððïðîîðîìëîîëîðíêêêééèççæçæÞÛÙÚÛÜÞÞÞßßßßááãåäæææèéêééìëîõòìììììïðòððòòññòôôô÷÷÷ùùùúûûúúúùüûþøûüûûûûøúüüüýüüüýÿþÿÿÿÿÿÿÿýÿ
+
+	
+		
+
+
+		
+
+
+
+
+
+
+
+! 
+"
+
+
+
+
+
+	
+
+
+
+
+
+	
+
+
+	
+	
+
+		0	
+
+	ÿÿýüýýüûûúùúûúùúüûùúúùøü÷öø÷öö÷øöøúõòóóõõóòóóññðîðïîïîíïíììïîëëììéêêéèèæçåæåÙÚØÙÚÛÞÝÞßÞÞàááäåãåæçççééêëêîôñìííííðñðñòòññòóôôôö÷÷øüýúúúúùøùûüûùúúûûüù(!øüüüüüýþþýÿþþÿÿÿÿ			
+					
+
+	
+
+
+
+
+
+
+*(&
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+	
+
+	
+
+
+			
+	
+	ÿÿÿýÿüüûüûûúúýûúøúüúùúùøûÿ÷ö÷öõõööõôú÷óôôôóòñòòñððððïîîîíììììëëêêêééêêêèèæååäåÙØØÚÙÛÛÛÝÝÞßàááââãäååççèêëêêêëííìíîïïðïðñññòñòóõöõõ÷øûûøøøùùøùûûøùüúùùúú
+ùûûüüüûýþûýýþÿþþþþþþÿÿþ		
+			
+		
+		
+
+
+
+!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+			
+		
+		
+						
+	
+	ÿÿÿþýûýûüüúþûøøøùúøùø÷÷÷ö÷öõõõõõõóö÷ôýûóóñòòðñðïòððïîîíëììëëìëéêêèèêéèççæåååÛ×ÖÙØâãÜÛÜÞÞÞàãàáâáääçççéééêêêíììíîïîîïïðññóñòòõõôõöøø÷øùûúøøúúúùôùúùùúûøùûúûüüûûýþýþýþÿþÿÿÿþ	
+
+		
+
+	
+	
+
+
+
+
+
+
+/pc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			
+			
+		
+
+	ÿþÿüûûüüýûúùùùøøøøøø÷÷ö÷÷ööõôõóõóõöóñòññòñòñðñïïïîííìëìëëìëêêíïèééççæçæçäÔÖÖØ×ëíÝÚÜÝÝÞßãàáááããæåæèèèêêêëììíîïïïðððñðòòóóóõöö÷÷÷÷øùúúø÷÷ùùø
+	úøøúüûùúûúúúúûüýýüýýý
+üýÿþü·5
+
+	
+
+	
+
+
+	
+
+
+
+
+
+
+
+
+"$
+
+4
+x
+
+
+
+
+
+
+
+
+
+		
+		ÿÿÿþÿÿþýüûûüýÿüúùúùøøø÷÷ùú÷÷÷ô÷õõôôóôóó÷õ÷÷ñðññòòññïðïîïíîíììëêëëëëæýMRäìèææååæãÓÕÕÖØ×ØÚÛÛÝÞßÞÞßàáãããääåçççèèèéëëëìííîïðïñññòóóóüùõö÷÷öõö÷øøöö÷÷÷ø÷÷ùûûùùûúúúúúûþýþýýýý
+ÿ
+<Q	
+
+
+
+	
+
+
+
+
+
+
+
+N>
+_ÄY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+	
+ÿÿÿÿÿÿüüþûýýüüüùüúøøùøö÷÷÷÷øöõööôõôóôõôýñòñðñòðñððððïîðîîîííììëêëìæwâíéææåäåãÑÔÕÖ××ØÙßâÝÝÞßàßÞààâäãäãåææçççéêêëìòöíîïðñññóòòóüøóôööõôõ÷öööõõõùöøøùùøùøøúùùúúùúüÿûþýüþøùýÿÿ
+
+			
+
+
+
+
+
+
+
+
+
+:1
+ÙÀ
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+								)wSÿþýþüúýýýüúûûúøúûúøøø÷÷ûø÷ööõõôóô÷÷öóòòóóñññððððïîððîîîîíîîìéìîêêæäéççæææäååÎÒÔÕ×××ÖìóÙÚÚÜÞßßßßáäãåäååæèèçéëëëíøííðïðñðòñòòòóôõööõôö÷õõöõöõûøøùùøøùøøùùùùúúúûÿýÿýýþŽiûþÿ							
+		
+
+
+
+
+
+ )z
+
+
+
+
+
+
+
+
+
+
+
+											:'	ÿýüýüûûûþüûüüø÷øøøø÷øøøööööôóôóôôö÷õòòòòòòòñðððîïíîîííííìììëéééèêêéèæçæåæäãäÌÒÔÕÚÙ×ÙÙÚÛÛÛÝÞààààâããåæçéèççèêëíííììïîðïòòñóóòóõõôôõ÷÷õöö÷öøø÷÷ôøùøøøøøùùùùùùùûûûùüÿþýýýðöÿÿÿ
+
+
+	
+
+
+	
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+				
+
+		
+	ø	
+!
+ÿ
+
+
+ÿýýýýýûûúûüüûûúüúùùøø÷ø÷ýõõõõõõõôóô÷õòòóööññññññðððíîîîíìíììëééèéêééèçççæååäããÈÏÓÔÖÖÖÖØÙÙÚÛÜÞÝÞßàáââçèêðêåæçèêíîëëíïðïïðïïñòñóôóòóôõõôõõöõ÷ö÷÷÷÷øø÷÷ööùûùøùøùûüûþùúûüüüüþþÿÿÿ!
+		
+
+
+
+
+
+
+
+		
+
+
+
+
+
+"!
+
+ !"
+
+
+
+
+	
+
+
+				
+
+			>Ž
+	
+
+	
+
+	
+
+
+
+ÿþýýûúûûüûûüûûûúùùúûù÷÷öøøû÷õûô÷ôòôôôôôóòñòòñððððîíîîíìíìíìêêéèêëéèçéçäåæåäããÆÍÑÓÕÖ×ÙØ×ØØÚÛÝÞÞßàßáâââääçççèçèëëêêììïîïôðïðñòòóóòôöõôôôöõõõô÷ö÷øø÷÷÷÷ö÷úúùùùùúúøúúüüüûüýüþÿÿþþÿÿÿÿÿ	
+
+	
+					
+
+
+
+
+
+
+
+
+',
+
+"(*'#
+
+ )0
+
+
+
+
+
+
+
+
+	2'		
+	
+				
+ka3		F%U*
+
+
+þþþýüüüúûüúúúùùúøöø÷÷÷øöøþöõûøôùõóô÷ùûúõóñðððððððíïíïíìíìëëëëéèêêééæèçæåæääããÁËÐÓÔÕÖÖÖÙÙÚÚÚÛÝÞÞààáàãããåæèéééêêêêëííìïñðññðñòññòóõõôôôõôôôôõøöö÷÷ø÷÷÷÷øùúøùúöùúùûþûûüüüüüüýÿþÿþÿÿ
+ÿþþþýþ
+	
+	
+
+	
+
+
+
+
+
+
+
+
+
+
+'8GJA,PC
+
+
+
+
+
+
+
+
+	
+kQ		
+
+			
+		9ž'	
+
+IKš5
+
+
+	ÿÿýüýÿüûýúúùùõõ÷ùøöõöööø÷õùöôôôóõóóòíI
+°ñòóðïðïïííìïòïëëêéêëêèçéêí÷åååääåâãââ¿ÈÏÒÓÕÕÕÖÚÜÚÚÛÝÝßßàââááäãçèèéìíééëíìëíïïððñðòôôóóóóøùôôôôõõöõ÷õöõ÷øøøø÷øøùùøù(øûúúþúüûüýüûûýýýýþþýÿÿþÿ0]þÿÿþþþýÿ
+	
+
+
+
+
+
+
+
+
+
+!/|]/ 
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+	
+			
+	ûü
+
+%t#
+
+ÿþþÿýüüûúûõZU
+õ÷÷÷öö÷÷÷ööõöõòöòóóòíLnõñòññïððîíîîòðíììëêëììéèéééçåææååæäãââºÁÊÐÒÓÓÓÕÖ×ØÙÙÚÛÛÜàáààáâããääæèèêíêëêëììíìîïòññòóóòóôóòòóô÷ôõóóõõööõö÷ø÷÷øøøöó+sõüøúýùùúúûûüüûýÿýüýüüÿÿ:}%þÿÿýþþþÿ				
+
+
+
+
+
+
+!3OÐ* 
+
+
+
+
+
+
+
+
+	
+	
+
+			]
+
+
+	
+ÿÿþÿýûþûûùû÷;Iôö÷÷öö÷öõõöööõóøóòòòóA/öòòññðïïïîíìíììêêêêëëéèèéëîêæåæäãåâäââµ¿ÈÎÑÓÔÓÔØØÖåÙÜÛÝßààáàáãääåçèèêìêëììììííîîöðñóôóóóóóôõõôõóóóõõüõõ÷÷øø÷÷ùú÷öôúýøÿüûùúúûûûûüþþüý	*
+ýþþýþÿ		
+
+	
+
+
+
+ 4Ÿ«s-
+
+
+
+
+
+
+
+		
+		
+					,Ø
+
+
+
+ÿÿþþÿüúúúÿ÷÷÷÷öõõööôõôôôóôõóòòóñêîóñððïïïïïîííìíïìëêëëéêìêççèèçæååãââãâá²œÆÌÐÑØØÑÝöóÙåÙÚÚÞÝÞàßâãããääæçæîõôÿëíëííïíîððïòòóôõõóóôôóòòòòôôô÷÷õôõõõöö÷ø÷ö÷ùûüùøúûù÷øúúùúüüûüüû
+
+þýþÿÿÿýýþýþ				
+
+
+
+,L}j>'
++
+
+
+
+	
+
+
+
+
+
+	
+	
+
+					
+		
+
+		
+
+	
+)
+	
+
+
+
+
+!#" 
+
+ÿÿþûúúù÷õøùø÷ùøö÷öõõôóóóóóôôòù÷ñññòòðïïîïïïîíííííììêêêèèêêçåææåääåããáááá®¹ÂÉÏÐÓÔÒÖàá×ÙÙÚÛÞÜÝßßáääããåææçéëñþêëíïðîíîóòñöùùü÷ôõôóóôóóóóôóõóõôôõöö÷ùùøøùýþúüøùüøøùúùùúýýûüüûþÿýüýýþþþýýþÿÿÿÿ	
+		
+
+
+
+
+ $"" 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+	
+
+
+		
+					
+		
+
+$)
+#'.23/("
+	ÿÿÿþýþýûúúùùôõ÷ø÷÷ùøö÷õôôôôôôòóòòñúøñððððððïîîîïííìíìììêêêèçèéíîåååååãåââààêæªµ¿ÆËÏÐÑÒÒÓÕ××ÙÚÛÜÜÜßààâãããäèéçèéêòéêìîíìíïðñïðò#0îòòòôòóóóôóóôüöóôõöööøú÷÷øøøúûûýÿùùúûùøùúúûûüüüûýýþÿÿÿþþþþÿÿÿþÿ	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+				
+- .7BPTI=5(
+ÿþÿþýüýüûùøö
+õ÷õö÷öõôôóóóóóôòóñññóòððïîîïïîïñîííëêëìëëêêêèèèèèçäååããããâçâáäâÒŒºÃÉÎÐÐÑÒÔÕÕ×ØÛÜÚÛÝÞßßßáääãçèçèèéëîêêéìëìíîîîïðõùðññõþóòóòòñóôôôóóôõôõ÷÷ö÷øû÷÷ùøúúùüøùùùüûüýûûúûýþþýûýþÿþÿþþÿ			
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hê
+
+
+
+
+	
+		
+
+		
+
+				l7
+	)'8W¯ŸpL1 
+	üøþýüýüüùøöõ÷ö÷ùøõõõõôôòòòóôòðñïïððïïîîîîïðîîíìììììëëëééêêéæåäæåäãåãâäââãâÅ¶·ÀÇÍÏÐÒÓÖÙÕÖÙÝÚÛÛÝÞÞßààâããäåææèèèèèéìëëëìììîîïòýýñññïýôòòðñòóôóóóôõõöö÷ø÷õöö÷÷øûùüúøùùøúýüúüýüúûüýúüüýüýýÿ$ 			
+
+
+
+
+
+
+ &+0(
+
+
+
+
+	-
+
+
+
+
+			
+
+							úzþ$=
+%.H
+ºV¿[3#
+	výýýüüúúùúö÷ø÷÷÷ø÷ööõõôôóòòòóóñðïîðñðïîîðîíìíîëìíìëëêêéëëëëçéïêääãääââààááâªµŸÄÊÍÐÒÒÕÖÑÙÙÛÙÛÛÜßëâÞàèæâãäåççèêèèêìëëëìíîïïîïíîñññðôûòòòññóóòþõòôöõõõøú÷÷÷÷øùùúøüøøùüúúúÿûûûûûûþûüüýüýýþÿÿÿ
+		
+
+
+
+
+
+
+*«rÒ?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+									
+
+
+Jn4eœ
+"4X¹ž¡Çj:&
+û+ê"ÿþüûûûûúøøùù÷ø÷ööôööóôöóôòòñòññðîîððïïîîïîîíìíëìììëêîìéééééåéòíãäââââãàààáá¢±»ÂÈÌÐÏÏÎðqÓ×ØÚÚÛÞçáÞàåäáãåæçççèèîìêìéëìíîîîîîîïððòñðïñòñòòòñòöôóóóûûõööö÷ööøøø÷÷ýúøùùùúûûüýûùûûúýûüûýüüûýþ		
+	
+
+
+
+
+
+
+
+
+
+
+
+
+2#YJ
+
+
+$W
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+			
+								
+
+
+
+'K&:`ÙñÀÙ1p='
+	8dþüüûûüúùøûù÷÷õõö÷ú÷õô÷òóòñóóðððïððððîîîîíîîíìíìììëëîìéçèèæååééäãâãâãâáàßááÇÉµ¶ÀÆÌÏÐÐÎòwÓØ×ÙÙÚÜÜÞÞßààâãäåååææèñëêìêêëëìîíîîîîðñðïðððññòùñïóòóóóô÷öööôõöõõöö÷ö÷ûúöøùøùúúüüûúúúûüúúüûûùýþþÿÿÿÿÿÿ
+		
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+.ÄÒ9''
+
+
+@Ô
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+	
+	
+
+	
+							
+
+
+
+	
+
+	
+
+#2Uª
+gÊ^7%
+üýûûûýûúúúûù÷üûõöùü÷÷óóóòòñóóñðððñðððïîïðîíîîíîíìíëëêêéçèèçæåääåäããããâàààáàûð·³ŸÅËÏÑÑÓÔÔÌ×ØØØÙÛÛÜÝÞßÝÜáãåèèèææéïéèêéêëííííïðïññññððññòòó÷òñøóòôô÷÷öö÷÷÷öööø÷÷÷øúúúùúùúúûúúûúúüýüúûüüûüÿÿþ			
+
+;
+
+
+
+
+
+
+
+
+".
+
+
+
+
+
+
+$26+
+ 
+
+*
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+				
+		
+	
+	
+	
+	
+ -F~ÓîqÍxG, 
+	ÿýûüûüúùùùøøö
+ôööõõõôóóñòñòññððïðñðïïïïïîíìììïíììëêêéèéèèèæåããäããââçããàáàßµµª³¿ÅÊÏÑÑÒÓÔÕÖ×ØÛÚÛÜÛÝÞßöðáåçéèææíîêýëéëíîîíîððîñòðñòññòòòóóôóöúõööõõöö÷÷öõ÷ø÷ùøøúüûûùùúûúúúùúûúøúüûûüþÿû.Yø		
+		
+#"
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+$
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+		
+
+
+
+	
+
+
+
+
+	
+
+				
+				
+	
+
+&6H`_G5&
+		ÿþýüûúúùøùøø÷÷õóõôóôõóñòòòðòðñðïïïòñîîîîìíîììëîîëëêêéèèèççèæãâãããââáæâçààßß¢¯ŒÄÈÎÒÒÑÓÓÔÕÖØÛÚÙÚÛÝÞÙ:pÜãäääéðìëéÿëêìíííìíïîíïñðïññðòðòüýôöôÿòõöôôõôõöõõõööùö÷øýûüüùøøùøúûûûüùùùúüúúüüýÿÿÿÿ
+þ				
+
+
+
+
+
+
+		
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+		
+		
+
+
+
+	
+
+
+				
+
+&(,6?<6+$
+ÿüýûüùúù÷úøûùö÷÷ööööôòôóñòñïððñóñïðïñðíìíîìëíììëëîëëêêéççæåæçåââããâááàâàãßÞßßª¶ÀÇÌÐÒÐÑÑÓÔÕ×ÖÙØÙÚÚÜ×4dÜâäãåîùçéèæèêëìíííííðñïïïîïïðñðñûûñôòþúóóôôôõõõööõõöööö÷øûú÷øúùùøøúúúúûùùùûûûúüûüþþýþÿüý!¡Aü
+		
+	
+
+
+
+
+	
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+		
+	
+
+		
+			"
+	
+#&.%
+
+ÿþüüûüúúù÷øøûüùøù÷õöõóòóòñóòññðîòñïïîîîìììíòñëëëìêêëêéèèèççæææäââãããáààáßßÞÞÝÞ
+§³œÆÊÑÖÐÒÒÓÔÔÕÕ×ÙØÙÚÛàÜØÝááãåæëñèèçéèëêëííîîìðòîïðïïîïïïïòóððððóóóóôôõõö÷õõö÷÷öúøøüø÷øøùùøùúùùùùøùøùþüûûûüþýýþÿ%ÈOú		
+	
+		
+
+
+
+
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+	
+	
+	
+					
+
+
+
+
+
+
+ÿüþûûüûøøøøùüùöúùôööôòòñòóññïðïïðïïîîíìííïüêëîëëëëêèçèéçæçæåæåãããããáâáàààÞÞÞ ®ºÃÈÓÜÐÐÑÒÔÕÔ×Ö×ØÙÙÛßâáßàáäæçäßçæçééêêêíïïîìíííïòñðïðïïïðùòðïðñòóóôôôôõ÷õöö÷öúû÷÷û÷÷÷÷øøö÷ùùùøø÷øøùûûýùûýþýþþþÿþ
+)					
+
+
+	
+
+
+	
+
+	
+
+
+	"
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+	
+
+
+
+
+
+
+				
+
+	
+
+
+	
+
+ÿþþüûûûûùùùùøùù÷öúùõööõôóòñöòñòðïïîîïðïîííîíöììîëêëëêéèçèçææååææãããâáááááááßßß~
+©µÀÉÍÍÐÐÑÐÓÓÕÛ×ÖØÙÙÚÜÝÛÞâââäåïåææéééêëïòñïíìîîîðñðïðñïððýóôññññòòôõôôôõö÷õööúúøùýù÷øøòó÷÷÷øùùùùøøúøùüûüÿÿÿþþþÿÿÿüÿ				
+	
+
+
+
+
+	
+
+
+		
+
+
+B
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+Q,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+
+		
+
+	
+
+		
+
+		
+
+
+	
+
+
+
+
+
+	þýúûüûûùøøøùøøùùøöö÷ööö÷õñòïððòïîîîííðñïííííîìëëíëééêéèççæçæääåäãããââáàßÜÕßàÞÞÝz¥±ŸÈÍÎÏÏÑÑÒÔÖÕ××××ÙÚÛßêéÞàâââNäèæéèëêëëëííííîîïïïïïïñðïñ÷òöóññññòôôóôôôõ÷öõööø÷ùýùöøô)*þõööøùúøøùúù
+þýþþþþý
+ÿÿÿÿÿ		
+
+	
+
+
+			
+
+
+		
+
+
+
+
+	
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+vT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+
+		
+
+	
+		
+				ÿÿ
+
+
+
+
+
+
+ÿÿýúûùþúúûøøøøõö÷öôôöõóõùôòôîñòûñîîîîííîîîïðííðìëìêééèèæçæåååäæçääãáâââáä&ëÞÞÝÝt}¬¹ÄÊÍÍÎÐÒÒÓÔÔÜØ××ØÙØì+×àâáäû
+äååçëêèééëêéëíííîîîîïïîïîïïñðïñññôöôññóôóôõõôõõöõöù÷ö÷ñ11þôö÷ö÷÷÷÷øøú	ýüþüýýþþÿÿþþþÿ		
+			
+	
+
+		
+			
+
+
+
+		
+
+		
+
+
+
+
+
+
+
+
+
+
+&
+
+
+
+
+$#	
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+										
+						ýûûþ	úûûúøø÷q?óöõõöõõôõóóôñõòöñïïþöííîîîïîíìííìîíêéèéèçèçæåæçåäåæâáàáâõb&×ÝÝÝoy±·ŸÈÊËÎÏÐÑÐÒÕÓÔÖ×ØÙÙâõíÛÞàÞê>áæææõêçèéêêêëííîñïìíííîíïïïòðïððñøøñûþòóóóóôôõöõõõøøø÷÷óóøøöøö÷úø÷ùøùúúûüüþýþÿþþÿÿÿ			
+
+
+					
+	
+
+				
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+!n
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+	
+
+
+		
+								ÿÿÿþþýûþ
+ùùúùù÷÷²ñóóõõôóôóññòðñòðññíîíîíííìïõïëëëêëëéèèèèéîöëãããããäâáâáàáùÚÝÞÝmu~Š°¿ÌËÌÍÏÎÐÒÒÓÕÕÔÖØØØÚÜÝÝÞßàâçæåäçæééèéêëêìíííìííìíííïîîïïíïñðððòñíñôõ÷ôôôôõôôö÷ùøø÷ööùù÷÷÷úøùúùúûúûüýýýþÿÿÿÿÿÿÿÿÿ
+		
+	
+							
+
+	
+	
+
+
+
+
+	
+
+
+
+
+
+
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+<
+
+
+
+
+
+
+
+
+		
+								
+	
+
+		
+
+ÿÿÿÿþýýüüÿûÿ÷øúø÷ø÷ûE+öõôôõóòóñòðððððïîîëìììîíìíîðïëêìêêèçççæææäíêãâââââãæáâàÞààÝßÞÝÝÝjs}
+©žÃÉËËÍÎÐÏÐÔÓÕÕÕ×ØÙÙÛÝÝÝÞàáäääåæååçéççêêéêëëëíîííïïðïììï÷òîñðïïòóñðòóøÿòóôóõùý÷õ÷÷ööö÷÷÷÷÷÷ùýøøøúùûúúüüüüüüý"/
+ÿÿÿýÿÿþ
+18+3!
+
+	
+
+								
+
+				
+	
+
+
+			
+
+
+
+
+
+
+
+
+
+
+
+
+)
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+				
+
+
+	
+
+
+
+	
+
+
+þÿÿÿþýüúÿ	úúùøûù÷øø÷îòø÷õö÷óñòòñññïðïïïîìíìììëëëìíííêëììèéèçççæææçåââââáâãáààÞÞÞÝßÞÝÜÝgu{~¢°œÆÉÊËÍÎÎÏÒÑÔÓ××ÖØÙÚÚÛÜÜàäâáâãæåäåçëéèèéëëëëìíììíóííìíô
+øëõòíïõöòññòôõòóóôôúóööõõõö÷÷öööööøø÷ùùúøùúûûüûûü%8þþþýÿÿÿÿÿþ
+,.#
+WB
+		
+
+		
+
+
+		
+	
+		
+
+
+
+
+	
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+	
+	
+	
+	
+					
+
+
+		
+
+							ÿÿÿÿÿÿÿÿÿÿýþÿûüûúù÷÷÷øöö÷öõõööóòòóòóððïñððîîîííííìëëììííëììêêéèççæçåìîåâââââàááàÞÝÝÜÞÞÝÝÝdmu|ªžÂÉÏÍÌÐÓÒÒÒÓÔ×ÖÖØÙÚÚÚÜÞàáäëâãäãåã	Q
+áïéëììììîíìíìíîðñîíîîðòðîïòññòóóóõóõöóøöõõõ÷÷öö÷ø÷øøùøøøùûúúûýüüüýü÷ûþýþÿþýþþÿüýÿ
+
+
+(#
+	
+
+							
+
+
+		
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+		
+
+
+
+	
+
+	
+				
+
+
+	
+	þÿþýÿþþÿÿýüýûúüüùùö÷÷öõööõôõõôóóòóóóñðñðïïîíîíííìììëììììëëêèéêèçæåäåæåãæëæààßÞàáÝÞÛÜÜÜæßÛ]gpx¥²ŸÇÌÊËÏÏÐÏÐÑÔÔÓÕ×ØÙÙÛÝÜÝÞàäááãâääí÷ìßFDõèëëëìììíìíëëîïîííîîîïðïðïññòóóóóóõòôòó÷öõõõööõõõöøùù÷÷÷ùùûûûþýúúüýþýüüýÿþþþþþýþ
+þÿ
+							
+		
+
+
+
+		
+
+	
+
+	
+
+
+
+
+
+	
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+
+
+
+		
+	#'			
+þ$þüüm(ÿÿÿÿþþýýýþýûüýùúùùøùùø÷ööõôôôôôóóóòòñññðñïíïïìííììëëìëêêêêëêéèééææçæååääãåëèàßßÞÞÝßÞÜÞÜÜÝÛÚXakr{­¹ÃÉÊËÌÍÎÏÓÒÓÔÔÕÕ×ÙÚÛÜÝÝÞáâàãâäååææççóóëëëëëëëììíïíëíîíëîïîíðððððððñóóòôòôòóóò÷÷õõööööö÷÷øøøø÷÷ùùÿûûûúúúûüüýþ
+ýÿþþÿýþýB÷ÿÿÿþ	
+
+					
+
+	
+
+
+			
+
+	
+
+
+
+	
+
+
+
+	
+
+
+
+
+
+
+
+	
+
+
+
+	
+
+
+
+		
+
+		
+
+		
+		
+			
+
+-
+
+ÿþÿÿÿ,þþÿøžCüþþÿÿÿÿþÿýýüüüýýýýüúûøùù÷ùù÷õöõôôôóóóóóòñòðððïðíïîììîíëëëìííêêêìëéïèéçææææææåääããáßßÞÝÞßÞÞÝÜÜÚÛÚS[dmv¥³ÁÆÈÊÊÍÍÏÐÐÒÓÓÓÔ×ÙÙÙÚÛÜÝààßàáâãããæççææèêëëëêììëëëëííìììîîíîïííîðñðñòòóõòöòóóóôôóõöõõõôõö÷÷õõöøøøüúûûúùúûüüý#5ûýüþÿþþÿþþýªP÷ÿÿÿÿÿþÿ	"
+	
+
+			
+		
+
+
+			
+
+	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+
+3$
+	
+				
+	
+	
+	
+ÿÿ4w
+ýÿÿ*þÿÿþþÿÿÿþüûûýþüüúúûúúù÷÷ú÷ôõõôó÷÷òóóñññòñïïíðïííííììëëììììëëëêêéëçççååææåäããâáâààÞÞÝÝÝÝÝÜßèÞÚÙPW_ir|«ºÂÈÊÊÌÍÐÛÔÑÒÓÔÕØÚÙÙÚÛÝÝÞßßßããããåææææçèðñéëëííìííîïîìíííõóïîïïðñðïðòòôõóõôóòñöõôôôöø÷öööööö÷÷öùùúùüûûûúúûýýûûýýÿýþþýþ÷üÿýýþýÿ
+	
+
+						
+	
+
+	
+
+
+
+
+		
+
+
+
+
+
+		
+
+
+
+
+
+
+
+
+	
+
+
+
+	
+
+
+
+	
+	
+				þÿÿþÿþþ
+ÿýÿÿÿÿÿþÿþÿÿÿþüûüûþûûûùûúú÷øöø÷õôõôôúûôóòññóñðððòðïîíííìëëììëëììêëêéèèêèèçéèæåääääääàââÞÞßÜÜÜÜÜäÞÚÚLS[dmw£±œÅÉÉËÌÏÖÓÐÐÒÓÔ×ØØÙÚÛÜÜÞÞÞßááâããäóïèçèêëêêëëííîííìëíììòüøðîîîïðððïðñôññóóñññ÷õôóòôõôööööõ÷ø÷öø÷ùùúûúúûúúûûùûýþýýüýþýþÿÿÿÿýüüþýþ	
+
+	
+		
+			
+		
+
+	
+		
+
+
+
+
+
+5	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	
+
+
+
+	
+	
+
+				
+
+
+
+
+
+ÿþÿÿÿÿÿÿÿýÿÿþüûûþþýþþÿþûúúùùø÷÷÷÷õööôõõö÷óððòòòòïóùúðíííìììëëëëêêëêêíèèèèêèèèéæååäääãããááâÞÞßÝÝÝÜÛÜÛÚÚFNW_iqzª·ÁÈÉÊÌÎÎÑÑÒÒÓÕ×ØØÙÜÝÝÜÝÝàààââãäæëêèèééééêëëíìëìîíííîïòòðïïîðòòñóññòòòóóôòòôö÷÷õõöõö÷ùûüøþøøøøúúùþýüûüüûúûüþþÿýþÿþþþüþÿÿþ
+
+				
+					
+
+
+
+
+
+
+
+
+		
+
+
+
+)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+				
+		
+	
+	
+
+ÿþÿÿÿþÿþý
+ÿÿþþÿÿüüþüüýýýýüúüüúüÿüûþùú÷÷÷õööøøõö÷öõóòñôüùññðððòø÷ïíìíìììììêëëêêêêïèçèéççççæäããããâáááßßÞÝÜÝÜÜÝÜÛÛÚÚÚ?JS[clu£±¿ÉÉÉËÌÍÎÏÑÒÒÔÖØØØÚÜÝÝÜÜßÞâáàâçæääæèèèèéëêëëíêêëîîîîíîííîîîïïîðòñðñòòøòòòòòóöõòòóóõõôôôú÷÷÷÷øùùúúúûúúúùùüüýýþýÿþýýýþþýþÿþþÿÿ	
+
+
+	
+
+
+		
+
+	
+		
+	
+
+
+
+
+
+
+		
+	
+				
+
+
+
+
+	
+		
+	ÿÿþÿÿÿþþÿþþþþÿÿþÿÿþþýüüýûûûüûüýüüûúúùúù÷÷øøøøöõ÷ùùõôôöôòóñùþïððïðððîîìììííëëìëëìêêêêêèçèéçææååäãâãâáàáàÞÞÜÝÛÜÚÚÛÝÚÚØ×Ø8GSX]gpy®ÛÞÆÈÊËÌÌÍÏÑÓÔÔÖ××ØÚÛÜÛÜÝÞâàßáääååæèççéíìèëêìëëêëììííìíííñòîìíðóñðñññóñòòñòòôôóòòôôóý	öþ#÷øùû÷ùùõ- ÿúûúúûûûûüýüýþþýþüýÿþÿþÿÿÿÿþþÿÿ	
+
+
+
+
+	
+		
+
+
+#
+		
+
+
+					
+
+				
+
+		
+
+		ÿþÿÿþýþþýþþýüüþþþþÿÿÿÿþüþþûýúûúüûúúúûûúûûùøø÷øö÷÷øööõö÷ôóóóòòòñôøòðïðïïðñîîíìëííìëëëëêééêêçççççæææååäãâââàààßÞÜÜÝÜÜÜÚÚÛØÚØ××1ANTYclt}¥Õ×ÎËÉÊËÍÎÏÐÒÓÓÔÕ×ØÚÚÚÚÜÝÞÞßàáâääååææçèëêééèêêëðïêìíìëíïððííîòùòðñññûóñòòòôóòòòõöô÷ùöüüøýøø÷øøùÿüüûúúúúúûüüüüýþþþýþÿýýþüûþÿþþþÿþþÿ	
+
+
+	
+
+			
+
+)
+
+
+
+			
+
+		
+		
+	
+		
+				ÿUÓhúÿÿÿþþÿüýþýÿýýþýýþýüýþþýüüüüüýýüüúûüúúúúúúúûùùø÷ùù÷÷÷÷÷ôóóòòù÷òòòñððñóïðïîïîííííìììíìëëëêèèééèæææææçæäääâááâàßßßßÞÝÜÜÚÛÚÚØ×Ø×××'5BNW^gnx£°ÌÌÈÈËÍÏÏÐÑÓÔÓÕÖØÚØÚÛÜÞßÞàáâãåäåååææççéééêêêï¯çììñîíîòôèãïðóññððñ÷ùòñòòïóôòóóôôóôôõ÷ô÷ùöööøøýúùýýûûûúûüüûûüýüýýþÿýþýýüýþþÿÿÿÿÿÿÿÿ
+4		)
+
+		
+
+	
+	
+
+
+
+	
+			
+			
+				
+					>³^ÿÿ&'	þþÿÿÿþþýþÿþþþýüýýüüüüýþüýþüüýýüüþüüüýüüûúùùùúúøùûùøöööøõõóôõõòñúùòñòñðïðòïïîîííìííìììëìëêêêêèçèèæææææææäãâãâààáßÝÝÞÞÝÜÚÛÙØÙØ×Ø×ÕÖ× .;JSXais} ¯žÃÈÈËÌÍÎÎãåÕÓÔÖØØØÙÛÝÝÞÞâáâáããäååææççèèêìëêîlýêíìòñîíîéTzëîîððððñòññòñõ	ÿòòôôôô÷úõôôõôöõõöøøúùÿúúûúùûýüúùûûýýýüüüüýýýýýþþþþþýÿÿÿÿ6X)		
+
+	
+
+			
+
+
+
+			
+	
+
+	'þ-Qûþþÿÿþþÿÿþþþþýýýþýüýþýýýüûüýüýüúüüüüûüüûúúúùøøøûúøú÷õöõôóô÷û÷õóòòóóòñðððñïñíîîîìîìíëëëìëééééçççææçæçååääãááãâááßÝÝÝÝÛÚÚÚØ×ØØÖ×ÖÕÕ×&4AKS\dmw¬²œÆËÌËËÍÌéêÒÒÔÕÖÖ×ØÛÜÜÜÞáàààááâäåæççèéëìêëééèÜéìííîîíìíèFlìîîïîðïðððññðôýóòòóôö÷÷ôóõóõõõõõõøø÷ûüúùùùøúûùúøøøøûüüýûûüýüýþþþþýüýÿþÿÿÿÿÿ	
+					
+
+	
+	
+		
+
+	ÿ
+	ýýþýýþÿýûüüýýüûüüûûüþþýýýýýþýüúûûûúøúúüúùùùù÷öøø÷÷÷öøöôõòóòóóòññðñòññðñòïïîíîïííìíëêëëëíîêèçççæéæççäãããâááäåááàÜÜÜÜÚÙÚØÙ×ÖÖÕÔÕÖÕÖ,=INV_gp|ª¶ÀÎÌÉÊËÍÍÎÑÒÔÕÖÖØØÚÚÛÛÝÞÞÞßááâãåèéèçêìëèéééêéêìììëëïñïîõøïíîîîñîïðððððñóõõòòñòõöõóôõõóõõõõööö÷úúùùù÷÷ùúøö÷÷øùùúõûüüüüýýþÿýûüýþýþýÿÿÿ			
+		
+
+
+			
+	
+
+þþÿþýüþþþþþüüýÿÿüüüüüþýýýýýýýþüûûúøûûüüúùûúøø÷úÿúöö÷÷õõõóóöõòòññóóòñòòòððîïïïíìíìëëìëêóôèèèææçêæçæåãäãâáàãçãßßßÝÛÚÚÙÛØØ××ÕÕÔÕÖÕÓ$2@HQYajt~¢¯ºÄÇÎÏÌÌÏÒÒÑÓÔÕÖ×ÙÚÚÚÛÜÝÝßßàáããæêêèçèçééééêêéêíìëìëõöîííííîïïîñïîðððñññðôõóñûÿòôôóôö÷õõõöõööö÷ùúùùùùùúúøøúúùùøx÷ýüüýýýúûüþþþÿþÿ
+	
+				
+			
+
+
+
+
+
+
+
+		
+
+		
+
+
+							ÿþþþþýýüüüÿýüýüûûÿýýûüüüþûüûüüûúùùøøùùø÷÷÷ø÷ö÷ùû÷õöôõóóóóòøúöóññðñòñðïïðîîîíïìëìëêêêêêéééèèçæææåæåäãäâááÞâæàÜÞÞÝÚÙÚÚÝ××ÖÖÔÖÖÕÔÓÍ
+
+,9DLU]foy§ŽÀÅÜÜÐÎÑÖÔÐÒÔÔÖØÙÚÚÚÚÝÜßàáááââäæææçççêééçêèèêëëìììñðìíîîíîðïîðóþòïïðññðôôòñüòôñòôõõõôõ÷öööö÷ùùùùùùùùø÷øúûúøø
+÷üüüüûüûþÿýþþÿþüÿÿþ		
+
+	
+	ÿÿþþþýþÿÿýþüüýüûúûûýÿýûüûûûúûüûüûüúúùùùúøøøöõõö÷÷÷÷øöõõõõôôóññòõõõóóñïðïîîïíîïïëøðíìêêêéèéééèèçèèæçåååäãâãâàáíçêîáÛÛÚÙÚÚÚÞ×ÖÕÕÔÖÙÕÓÐÈ"0=GNW`js{
+«žÂÇÉÌÌÍÏÏÐÑÒÔ×ØÙÙÛÙÜÜÛÞÞãâàááãäååæçèéçççèçèéééêëìêíîëìíìíîîîïø"ôïïðððïòóóñóóòõòòóôóôôõöõõ÷÷÷ùùøúúøøøöõøøùûú÷ù
+úûüýüûûüþýüýüüýüÿþÿÿÿÿ	
+	
+
+
+
+ÿÿÿþýýýþþýþýÿüûûûûúüýúüûüüúûüúùûúúøúøùø÷÷÷÷ööööö÷öõõõöõôôóóòñõóðñòòððððñðòíííõïñîíêééêëêééèçççèèèçæäããääãâßä/		#ðÚÛÚÛÚÚÚØ×ÕÖÕÖÕÔÓÒÌÂ	&5BJRZdlv¥²ŒÅÈÉËËÌÏÐÐÑÒÔÖÜÙÙÙÝÛÜÜÝÞßàáâãäääççèéèççèçéêéééëêëôóêìíììííïîõñîðñðïðñôóñññóôóóóôóôõõõöõ÷÷÷øøùúú÷øù÷õööøùúúøóùüûûûüýüýþüúüüüýüÿþüþÿþÿÿÿ		
+ÿÿþþþþýþþÿýþüýüüÿüþýüýýýýüüýûûýûúúúúùø÷øùùùùöö÷÷÷ööööôôöóôóõøõòòòòòññïððïîîñúûîëììêëêêííëëèçèææèçæåääãäåâàáøÝààÞÜÜÜÛÛÙØØÖÙÕ××ÔÓÐÆŒ
+,9DLV^fox«¶¿ÆÉÉËÍÎÐÐÐÒÝå×ØØÚÛÛÜÛÝÞÞÞàãåääæèèçèèèçèçèèéèéëëíñïëíîííîíîïðìðïïòñððñõôòóõöôôóóôôõõõöù÷÷÷÷ùøùúùùøúûöòöö÷ùüüüùýüüüýþÿþþýýýýþÿÿÿ*
+ÿ			
+
+
+
+
+þþÿÿÿþýýþýþýûþüúýýýýüýüüüüûüúûûúùúùøø÷øøø÷÷öõ÷öööõõõôõòóóõôôóñòñïïîîñïîíîîðìëíìêìëêêëêêèæææåæñîãâããââàéçàÝÜÜÝÛÚÙÙÙÙØ×Õ×ÕÔÔÔÓÐÊ¿Ž	&2?IR[glt¢¯ºÄÊÌÍÍÏÑÓÔÛùÕ×ØÜÝÜÝÜÝÞàáãååææèéèèéëêèêêêçéêêëëðïìëíîíîíîïïõòïïñðññññõõóôôõôõôôõôöõö÷õ÷÷øøøùúùøøúúõQõõö÷ûûý9ùûýþþÿÿýýýüüýýÿÿÿÿÿ	
+)		ÿþþÿÿÿýüûüüüüûûùúþþüûûûûûúûúùúûùúøùøùøùøö÷úøõõöööôõóóóôòòñóóòððñðïë
+,úíðìíììíîîíëëêéêêéèèçææåæåäãââäâàßàÞÝÝÛÚÚÛÚÙÙÙ×ÖÖÖÕÔÔÓÒÐÊÂž¬
+
+)6CLVienw¥±ŒÅÊËËÌÎÏÑÕÓÕÖÖØÛÜÛÜÜÞÞßàáâäåçéêéèéèèèèëìíèèèêëêêêéêëêëëìîíîðîïòðïðððóòðóðìòôõòôóõôöõñõ÷÷ööøùù÷÷úùóTõõø÷ûúúS2ùýýýýýüüüûûûüÿýÿÿÿýÿÿ
+
+	
+	
+ÿÿÿþþþýþýüüûûûüüûûùúýÿýûúúúúúûùúúúùùùø÷øùûùö÷úøõõõöõôôóôóóòñòññòñðððíê
+òíïïñôýïìëëëëêèçèêéæççæäõ!èåãáâáßàÞÞÝÝÜÜÜÜÚØØØÙÕÖÕÔÔÒÓÑÍÄ»¯€
+!/=GOY_ir{©µÁÈËÌÌÍÎÏÏÒ××ÖØÙÙÚÜÝÝÝÞßâäæèêëêêèçèééççíîçéìñîééêëêêêêêîîïðïïïïðñððòòññ
+"õõôóòóóôõ÷÷÷÷öö÷øø÷ö÷øüôî÷ùúùüúù(	ùüýþþýüûüüûüýýýþÿþþÿÿÿÿÿÿ						
+	
+
+ÿþ	ÿÿÿýÿþüüýüüüüüúúûûûúúúùúûùúúúúùùø÷÷úüùööö÷öõôõõóóôôóòòòñðñññððïîïö÷íìíîñ÷ÿñìëëíëéèççêïñëççß
+ýåäáââàßáàÝÜÜÜÛÛÚØØ×ÖÔÖÔÔÔÔÒÐÉ¿Ž§&5@JQZcou~¢®ºÃÊÌÍÏÎÐÐÒÔ×××ØÙØÚÜÞÞßáâåëñõóðêèèéêæçèçççèéèéèééêêçèêêëîííîïðïîîððñóôóéE³5ðõôóôóóóö÷ø÷÷ö÷øùøöõõùý÷øøüùøúøúõúþüüÿýüûüüûüýþýþýýýþÿÿý
+m
+
+
+
+
+ÿÿþþÿÿþþüûüüûûúûúüýüýüúúûúúùùøøøúúøøøø÷øùú÷öõôöõôóôôóóóôóòññïðñðññïïððìììììíïñïëëêìééèéèçêíêæçâõ/ìâááààßáâßÜÝÜÙÙÙÚ×ÖÖÔÕÕÒÒÓÑÐÌÃž«
+,9DNU^kox§Ž¿ÆÊÌÍÏÐÒÓÒÔÙ××ØÚÛÛÖHQÿáèú1S$ùíèèèææçééèèééèççèéêéèéêéëìííîîððïîïððóôòì2%ïòóñóòôóôö÷÷ö÷÷ø÷÷÷ööø÷øùõ÷ööø÷öP
+øüûûûûûúúüýþýýùüýýþÿÿ
+
+þ
+
+Z7e	,7ÿ[
+
+ÿÿÿÿþýüýýÿýüûüûûûùúûýÿýúùúúûûúøøù÷øúùùøøø÷ööúùùøôõõôóôôòòôöóòðñððñððóóïîîîíìëìììëììëêêêêéêéçççæåæåâ×ààààßàßàßÜÛÝÜÚÙØØ×ÖÖÕÔÓÑÑÔÑËÄº¯£"/<HOWair{«žÂÇÉÌÎÎÐÒÒÔÔÖÖ××ÚÛÕMMøáâ:=Úîêçåçççèîééèèçæõõèçèèèèèéìîìííííîîïïïñøöðòòïòòñññòòôóõõõ÷÷ööõõö÷õõöõöúþ÷÷óAŒEñúúúùùùùúúûûýüüûýýüþþþÿþ)5( )	ÿþþÿÿÿÿÿþþýþþþýüþüýüþüûûûúúúüýüúûüúúûúøùúøøúøùøø÷÷÷÷ø÷ùùõôõôõôôóóôöòõóòððððñòñðííîíììíîíêëïìêêêêééèçæææåääääááááààÞÞÝÝÜÜÚÚÚØ×ÖÕÕÕÔÒÑÑÑÍÅŒ³Š
+&4@JRZdlt¢°»ÃÈËËÍÎÐÒÒÔÔÕÖ×ØÚÛííããã6bÜìéçæèèæèóéççëëç	çæèéèèèéëìíîìíòðïðïïóýûñòôôòòôññðôóóôôõ÷öö÷÷÷öööõöõôÿ/úøø'
+øùûûùúûûùûüûüüûüýüüüýýýüýÿÿAn
+üþ
+
+
+	ÿÿþþýþþÿÿÿÿþþýýýýýüþûûûüýûúûûúúûûûûýüúúùùùúùøúûø÷ø÷üø÷÷öööøøõõôôôóôóôòñôòñññðóóïîïîíììëíëíîêëíêëêêééèççæææåãããäâáàâáßÞÝÝÝÜÛÚÙÙØÖÖ×ÕÓÒÑÐÒÏÉÀ¶ª
+
++8DMT]fnx§³¿ÇÈÊÌÍÍÐÐÓÔ×ÖÖ×ÚÛØÚÞáè@Sîæìåæäæççèçççèíëéèçèêééèêëììííîïîïîïðñòòðòõñòóõôòòóóöõôõööõùùõööôóôóúùøùúøùúúúùøúþý÷ùûûüþûüþüûûüüüüýýýþþÿÿ7
+		ÿÿþþýþüþýýÿþþýýýüüüýûûûüüúúúúùúûúúüüùùûúùùûøøüú÷÷ø÷	ý÷øööö÷þþôôóôôôòóñòðñðñññöôîîïîíììëñííìëêéëêëééèæææåäåäããáãàßààÝÜÜÜÛÚÚÚÙ××ÖÖ×ÔÖÒÑÑÐËÅº®¡}
+#0>GOV`jq{«·ÁÈÊÍÎÌÏÐÑÒÖÕÖÙÚÚÛÜÞàåëçäèéæçîååäåæçææçèéççêéææçééêêéëìííîìîîïðñðòóññððñóóöòóõôôöõõöõõö÷÷õõõõóóôõööõöýûúøøúýúøø÷ù÷÷÷ùúúûûüûüýüüýþþþþÿÿÿþÿþ
+ÿü
+
+þýÿþüýýýÿÿýÿþüúûüþþüüúûùøúøùúúùùûûù÷ùúûúùøøûùùøù÷ü÷÷ööõóÿòóóôôòòòñòòóòððñóòîîííìíìëòñêìêêéêêêééèåææåãäåââáâßÞÞßòéßÜÛÚØ×××ÖÕÔÔÓÓÒÐÏÌÆŒ°¥~x'6AIQZdlt~£¯ºÄÉÌÌÍÎÎÐÑÓÔØÚÙÚÚÚÝàâããääãäãâäæäääæççééèçèèèçæçèèêìéëëììíëëìñòððóóðïðñððñòôúóóóòôõöõôõ÷÷õôööô÷õóôöö÷ûúøø÷øøö÷÷÷øø÷÷øùúúú$üúûûüüþýùûÿÿýÿýþÿÿÿÿý
+ý
+
+	
+ÿÿþÿÿþÿýþþýþþþÿüüýýýýüýýüûûûúùúü÷øûúøùúúùøùùùùø÷÷ùøøöö÷ö÷öööõõôö÷ôóòòôñòñðñòððñðïïîîíîíììêëìòîèééèéééèç÷ôåæåääâãâáààßÞÝÙx£ÔÚØÛäâÖÔÔÔÓÓÒÑÑàÎÀ³šys
+,;DLU]gm
+Š²œÆËÊËÍÏÐÒÓÓÕÖÖØÙÚÞÞßààáááâãáâæäääååçéêææêêççæçèéêìèëêëêéëëëïðîïòòïïñòððñóóóóöôóòù÷ôóõöõõúýõõõôôôôö÷ø÷÷÷÷÷ööõö÷ø÷÷ùùùûþûúùùúýýþþþþýüÿþÿþÿÿþÿ	
+	þþÿÿÿÿÿþýýþýÿþüþýûúüüýÿýûúúúúøùú÷ùüüúúùùùùùøøúüûø÷ø÷÷õöõööõööõôôööôòóòòòòóññîïðïîîîïîîïîîðêêééçééèéééèæùöåæææåáââàààÞßÝÙ_ÔÚØÚâßÕÕÔÔÓÒÒÑÐíßºª {un>$1>GPW`h}«žÀÉÉËÌÍÏÑÒÓÓÕÕÖØìõåÛÞßßßááâááâãäåååææçææçèçèèçèéêéîëêéìëëêëììîðòòïðððï÷
+ññóÿÿõòòóôõôôõ÷ûôôöõôóóõö÷øùøø÷ø÷ö÷÷÷ùøöúüûùúùüÿûúûùD¿|öþýþýþþþÿýÿýþþýÿÿò
+ÿÿýýþýÿþÿþýúüÿÿþþýúúûûûüøüùøúûúúúøúÿýøøùøûû÷øøöõöõööööööõõôóóóóóòóñóñïïðïîîîîîííîîøðêëñèêéêééèéèçæåæçæåàâáààßÞÝÝÞÞãÞÚÙØ×ÖÔÖÖÔÓÒÑÑÐÌÓÌ±¢
+}vphP
+&5AKRZdks}¢°ºÄÈÊËËÍÏÐÑÒÓÓßßæëáÛÝÞßààáààáâáåååæååæå÷õçéééèèéëéëêêéëíîíëëëíðòòðððïòøùòòóúùóòóóóõôôõõõùýôôóõõúõõõ÷þú÷øö÷øø÷ö÷÷÷ø÷ùøùùúùûùùüûúóh"Åïýþþýýþþþÿþþÿþÿÿÿÿÿ	Ý(ÿÿþþüþýýÿüúýýûüýþþúøùúøúùúúùøùúúø÷
+õ÷ø÷ùüü÷öõ÷þùööööõõôóóôóóòóòñòððððïðîíîïîííííèú õêêöéêèèèéçæææåååäãâààààßÝÞÝÝÝÛØÙÛÙØØÖÔÕÕÔÒÐÐÎÍÈº¯Šxpib,:EMU]fox¥²ŒÄÉÉÊÍÎÏÏÑÐÒÝÝ××ÙÛÜÞÞàßßààáááäååääåæã
+äççèéëéêééêéèèêíííëêîòóòïïïðòôóñññòòñòôóòôôóôøùõôóóôöõõööõ÷ûúø÷÷ùù÷÷ööööøúùøùúùøúùúúúúüþýýûýÿÿþýÿþþÿÿþÿÿÿ
+
+5ÿÿÿÿÿÿÿÿÿÿþüþüüüþþüüþýýýúüþüùúüúúùúûúùùùùúùùúûùùùù÷÷ùöù÷õUñöùøöõóóóòòóññóóòñðïïïííîîïðíìðôêééééêèééèëêèèæåæååäãâáâåâàÞÝÝÜÜÜÛÚÚÛØØ×ÔÓÓÒÒÑÐÏËÈÀŽ©ysjc]$1<GOW_irz§ŽŸÆÈÊÌÍÍÐÚßàÖÔÖ×ÙÚÛÜÝÞÝÞßßàßáâäåããäåäöôäçèçèèèèèééèéèéëëìëêíðññîïððïðñððññòñòóóòôôôõôôôóóóóõöôõ÷öúø÷÷ø÷ùù÷öõõö÷÷øø÷øùù÷øùøùúþÿþýýþÿþûûýþÿþþþþÿÿÿþÿÿÿÿÿÿ
+
+
+ÿþÿþÿÿÿÿÿÿÿþþüüýûûúþÿþþýûûûûúûúüüüûùúùøþúûûùúûúúùýþöøùø÷õ÷÷ø÷öõú÷õöø÷ööóñññòòññòôñòïîííîíîîíííìïòêêìêéêêçèêöìçççèçääåäãàãëäàÞÞßÛÜÝÜÛÙØØ×ÕÕÔÓÒÑÐÐÏÉÁ·«¡{unh`X(4?IRZcjr{«·ÁÆÊËËÌÏÛæå×ÓÖ×ØÙÙÚÛÜÛÜÞÞÞÞÞàâääââäåããåçççéåæççéèèèçêêêêéëîíîòïîïîïïïððññòñòóóóôóóóóôôóòðôóóõõöøúùþúöö÷øøøöôôõ÷ôöö÷÷øøøøøùùúûüûù+
+þüüüÿþþþþþþþþýÿþÿÿþþÿÿÿÿÿÿÿÿþÿÿþýþýüþþÿýûûüüûûüüýûûúúøøþúúúúûúúùøöøúùùøøø÷ööööõõõõööõôòóóòóòóòôôóñðîïîîñðïîîîìííëëëééêèèëùìæçèçæäääååááâààßààÜÝÜÜÜÚÚÙ×ÕÔÔÓÒÑÏÎÌÄž®¢
+}vogkaQ
+
++7COV\emv¡¯ºÂÉÉÊÎÍÎÓÔÓÔÕÖ×ÙÚÚÛÜÜÝÝÞßßßààãäââäååæççææéçççèééêêèêééêéìöõîòðîïððñññòòóôóòóóóòòóõöõõõõôõôôõõ÷ú	ÿ÷øøøø÷õôóô÷ô÷ùúøùøúùúúúüýýýüûûÿýýÿÿÿÿÿþÿÿÿÿÿÿÿÿ
+ÿÿÿÿÿþÿÿþþþþÿÿýýýÿýüüûûûûüüûúûùùúúøúùúúúûúûúùúú÷øûúø÷÷÷øööõû÷õõóóôôóòóóòòóóñòñððïñðïðòðíìììììëêéééêéèçëéæåçæäåäääããááááßÞÝÞÛÛÚÙÚÞÜ×ÕÔÓÒÒÒÐÏÌÄ»²­š~vokbdZH
+"0=LRW`hpyŠ±œÅÊÌÍÍÏÏÑÓÔÕÖ×ØÚÚÛÜÜÜÝÝÞáâàßáããååååççææçéçèèèéêëìêéééêëìôôîððïððïñññòòóóññðòòññòôõõôôôõôõõóõõùtŒA÷÷øùùøõóôöõõõø÷ùùù÷úùúúùû
+	ûþüûüýþüüþýþþþþÿÿþþýþÿþþþÿ
+	ÿþþþÿÿÿÿÿÿÿÿÿÿþþÿÿþþþþþþüÿüþýýüûüýüûûûûúúúúüùúùúøùøúùúùùùùøøøùùø÷ùø÷ö÷÷÷ôööûøôü÷ñòòòñòòòòóóñññïðîïîîïîîîîìëìêéééèçéæççæåæäããäääãâááàßÞßÞÛÜÜÙÛÛØ×âÝÕÕÔÒÑÑÑÏÎÇœ²¬³²ypijaTKA
Index: /BAORadio/libindi/v1/examples/tutorial_ccdpreview.c
===================================================================
--- /BAORadio/libindi/v1/examples/tutorial_ccdpreview.c	(revision 500)
+++ /BAORadio/libindi/v1/examples/tutorial_ccdpreview.c	(revision 500)
@@ -0,0 +1,421 @@
+/*
+   INDI Developers Manual
+   Tutorial CCDPreview
+   
+   "CCD Preview"
+   
+   In this tutorial, demostrate the ccdpreview feature, and simulate the readout of a CCD camera. 
+   
+   Refer to README, which contains instruction on how to build this driver, and use it 
+   with an INDI-compatible client.
+   
+   For use with Kstars: click "Connect"; click "ON"; click "Start" 
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <zlib.h>
+#include <math.h>
+
+/* INDI Core headers */
+#include "indidevapi.h"
+#include "indicom.h"
+#include "eventloop.h"
+#include "base64.h"
+
+#define mydev         	"Device with Data Transfer"
+#define IMAGE_CONTROL   "Image Control"
+#define COMM_GROUP	"Main Control"
+#define IMAGE_GROUP	"Image Settings"
+#define	POLLMS			100
+#define WIDTH ((int) CtrlN[0].value)
+#define HEIGHT ((int) CtrlN[1].value)
+#define BYTESPERPIX ((int) CtrlN[3].value)
+#define BYTEORDER ((int) CtrlN[4].value)
+#define FWHMPIX (CCDInfoN[0].value)
+#define FOCUS (FocusN[0].value)
+
+void uploadStream(uLong maxBytes);
+void readoutSim();
+void makepic();
+
+/*INDI controls */
+
+/* These properties with these names are required display a video stream*/
+static ISwitch PowerS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty PowerSP	= { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+static ISwitch StreamS[2]={{ "ON", "", ISS_OFF},{"OFF", "", ISS_ON}};
+static ISwitchVectorProperty StreamSP={mydev, "CCDPREVIEW_STREAM", "Video Stream", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE,StreamS, NARRAY(StreamS),"",0};
+static INumber CtrlN[] = {{"WIDTH", "Width", "%0.f",16., 512., 16., 256.},
+	{"HEIGHT", "Height", "%0.f", 16., 512., 16., 256.},{"MAXGOODDATA", "max. good data value", "%0.f", 1., 256.0*256.0*256.0*256.0, 0., 30000.},
+	{"BYTESPERPIXEL", "Bytes/pix", "%0.f", 1., 4., 1., 2.},{"BYTEORDER", "Byte Order", "%0.f", 1., 2., 1., 2.}};
+static INumberVectorProperty CtrlNP = {mydev ,  "CCDPREVIEW_CTRL", "Image Size", COMM_GROUP, IP_RW, 60, IPS_IDLE,CtrlN, NARRAY(CtrlN),"",0};
+/* These properties with these names are required by the indi client to calculate the FWHM in arcsec*/
+/* The FWHM here is in units of pixels. The Pixelsize here is in units of microns. */
+static INumber CCDInfoN[] = {{"CCD_FWHM_PIXEL", "FWHM[pix]", "%0.2f",0., 100., 1., 3.},
+	{"CCD_PIXEL_SIZE", "Pixelsize[mu]", "%0.1f",0., 100., 1., 15.5}};
+static INumberVectorProperty CCDInfoNP = {mydev ,  "CCD_INFO", "CCD Info", COMM_GROUP, IP_RO, 60, IPS_IDLE,CCDInfoN, NARRAY(CCDInfoN),"",0};
+
+
+
+/* Blob for sending image (required but the names can be chosen freely)*/
+static IBLOB imageB = {"CCD1", "Feed", "", 0, 0, 0, 0, 0, 0, 0};
+static IBLOBVectorProperty imageBP = {mydev, "Video", "Video", COMM_GROUP,
+  IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0};
+  
+/* Start / Stop Switch (not required, and only defined in this specific driver)*/
+static ISwitch ReadoutS[2]={{ "Start", "", ISS_OFF},{"Stop", "", ISS_ON}};
+static ISwitchVectorProperty ReadoutSP={mydev, "readout", "Readout", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE,ReadoutS, NARRAY(ReadoutS),"",0};
+/* Adjustable Focus (not required, and only defined in this specific driver)*/
+static INumber FocusN[] = {{"Focus", "Focus", "%0.f",0., 100., 1., 40.}};
+static INumberVectorProperty FocusNP = {mydev ,  "Telescope", "Telescope", COMM_GROUP, IP_RW, 60, IPS_IDLE,FocusN, NARRAY(FocusN),"",0};
+
+
+/* 1 if "readout simulation" is running, 0 otherwise*/
+volatile int readout_is_running=0;
+/* The number of bytes read from the "virtual CCD" up to now */
+volatile uLong readout_bytes_done=0;
+/* 1 if readout simulation is aked to stop, 0 otherwise*/
+volatile uLong readout_stop=0 ;   
+  
+/* a buffer to hold a 16 bit image to be displayed*/
+unsigned char *image;
+
+/* in this tutorial we simply calculate the FWHM from the focus-position
+   in a real driver you will have calculate from the FWHM from the image you
+   took with your CCD. For example you can write a fitsfile and use 
+   sextractor (sextractor.sourceforge.net) to make a list of all detected 
+   objects with their "FWHM_WORLD" parameters and take the median of
+   that list. But make your FWHM is in units of pixels.
+*/
+double fwhm()
+{
+	return 0.3*sqrt((FOCUS-50.0)*(FOCUS-50.0))+1.0;
+}
+
+/* Initlization routine */
+static void readout_start()
+{
+	if (readout_is_running!=0)
+	    return;
+	
+	/* start timer to simulate CCD readout
+	   The timer will call function previewSim after POLLMS milliseconds */
+	image=malloc(WIDTH*HEIGHT*BYTESPERPIX);
+	readout_bytes_done=0;
+	readout_stop=0;
+	readout_is_running = 1;
+	CtrlNP.s=IPS_OK;
+	IDSetNumber(&CtrlNP, NULL);
+	makepic();
+	IEAddTimer (POLLMS, readoutSim, NULL);
+}
+
+
+void ISGetProperties (const char *dev)
+{ 
+
+  if (dev && strcmp (mydev, dev))
+    return;
+
+  IDDefSwitch(&StreamSP, NULL); 
+  IDDefSwitch(&ReadoutSP, NULL);
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefNumber(&CtrlNP, NULL);
+  IDDefNumber(&FocusNP, NULL);
+  IDDefNumber(&CCDInfoNP, NULL);
+  FocusNP.s=IPS_OK;
+  IDSetNumber(&FocusNP, NULL);
+  CCDInfoNP.s=IPS_OK;
+  IDSetNumber(&CCDInfoNP, NULL);
+  CtrlNP.s=IPS_OK;
+  IDSetNumber(&CtrlNP, NULL);
+  IDDefBLOB(&imageBP, NULL);
+  
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], char *blobs[], char *formats[], char *names[], int n)
+{
+	
+       /* ignore if not ours */ 
+       if (dev && strcmp (mydev, dev))
+         return;
+
+	/* suppress warning */
+	n=n; dev=dev; name=name; names=names; 
+
+}
+  
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+	    
+	/* Connection */
+	if (!strcmp (name, PowerSP.name))
+	{
+	  IUUpdateSwitches(&PowerSP, states, names, n);
+   	  PowerSP.s = IPS_OK;
+          IDSetSwitch(&PowerSP, NULL);
+	  return;
+	}
+	
+	if (!strcmp (name, StreamSP.name))
+	{
+	  IUUpdateSwitches(&StreamSP, states, names, n);
+   	  StreamSP.s = IPS_OK;
+          IDSetSwitch(&StreamSP, NULL);
+	  return;
+	}
+	
+	/* Readout start/stop*/
+	if (!strcmp (name, ReadoutSP.name))
+	{
+	  IUUpdateSwitches(&ReadoutSP, states, names, n);
+   	  if (ReadoutS[0].s==ISS_ON) {
+		readout_start();  
+	  }
+	  if (ReadoutS[1].s==ISS_ON) {
+		readout_stop=1;  
+	  }
+	  ReadoutSP.s = IPS_OK;
+          IDSetSwitch(&ReadoutSP, NULL);
+	  return;
+	}
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	
+       /* ignore if not ours */ 
+       if (dev && strcmp (mydev, dev))
+         return;
+
+	/* suppress warning */
+	n=n; dev=dev; name=name; names=names; texts=texts;
+	
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+	/* ignore if not ours */ 
+       if (dev && strcmp (mydev, dev))
+         return;
+       
+       /* suppress warning */
+       n=n; dev=dev; name=name; names=names; 
+       
+	if (!strcmp (name, CtrlNP.name)) {
+		if (readout_is_running==0) {
+			IUUpdateNumbers(&CtrlNP, values, names, n);
+		}
+		else {
+			 IDMessage (mydev, "The Parameters can not be change during readout\n");
+		}
+		CtrlNP.s=IPS_OK;
+		IDSetNumber(&CtrlNP, NULL);
+	}
+	if (!strcmp (name, FocusNP.name)) {
+		if (readout_is_running==0) {
+			IUUpdateNumbers(&FocusNP, values, names, n);
+		}
+		else {
+			 IDMessage (mydev, "The Parameters can not be change during readout\n");
+		}
+		FocusNP.s=IPS_OK;
+		IDSetNumber(&FocusNP, NULL);
+	}
+}
+
+
+void uploadStream(uLong maxBytes)
+{
+	
+   unsigned char *Data, *compressedData;
+   int r=0,offs=0;
+   unsigned int i =0;
+   unsigned char j;
+   static uLong old_maxBytes, sendBytes;	
+   uLongf compressedBytes=0;
+   uLong  totalBytes;
+   /* #0 Allocate buffer*/
+   totalBytes     = WIDTH*HEIGHT*BYTESPERPIX;
+   Data       = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes);
+   compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
+   if (Data == NULL || compressedData == NULL)
+   {
+     IDLog("Error! low memory. Unable to initialize fits buffers.\n");
+     return;
+   }
+   if (maxBytes<old_maxBytes) {
+     old_maxBytes=0;
+   }
+   
+   /* #1 fill transferbuffer ("Data") with data read from the imagebuffer ("image")*/
+   if (maxBytes>totalBytes) {
+	maxBytes=totalBytes;
+   }
+   j=0;
+   for (i=old_maxBytes; i < maxBytes; i+= 1) {
+     if (BYTEORDER==1) {
+       	Data[i-old_maxBytes]=image[i];
+     }
+     if (BYTEORDER==2) {
+       if (i%(2*BYTESPERPIX)==0) {
+         offs=i/2;
+         }
+         if ((i%(2*BYTESPERPIX))<BYTESPERPIX) {
+	 Data[i-old_maxBytes]=image[i-offs];
+         }
+        else {
+          Data[i-old_maxBytes]=image[WIDTH*HEIGHT*BYTESPERPIX-(i-offs)];
+       }
+     }
+   }
+   sendBytes=maxBytes-old_maxBytes;
+   compressedBytes = sizeof(char) * sendBytes + sendBytes / 64 + 16 + 3;
+   
+   /* #2 Compress it */ 
+   r = compress2(compressedData, &compressedBytes, Data, sendBytes, 9);
+   if (r != Z_OK)
+   {
+ 	/* this should NEVER happen */
+ 	IDLog("internal error - compression failed: %d\n", r);
+	return;
+   }
+   /* #3 Send it */
+   imageB.blob = compressedData;
+   imageB.bloblen = compressedBytes;
+   imageB.size = sendBytes;
+   strcpy(imageB.format, ".ccdpreview.z");
+   imageBP.s = IPS_OK;
+   IDSetBLOB (&imageBP, NULL);
+   free (Data);   
+   free (compressedData);
+   old_maxBytes=maxBytes;
+   
+}
+
+
+/* readout the "virtual CCD" over time*/
+void readoutSim (void *p)
+{
+	readout_bytes_done+=WIDTH*BYTESPERPIX*8;
+	uploadStream(readout_bytes_done);
+	/* again */
+	if ((readout_bytes_done<WIDTH*HEIGHT*BYTESPERPIX)&&(readout_stop==0)) {
+		IEAddTimer (POLLMS, readoutSim, NULL);
+	}
+	else {
+		/* Here you should calculate the fwhm from your image*/
+		FWHMPIX=fwhm();
+		free(image);
+		CCDInfoNP.s=IPS_OK;
+		IDSetNumber(&CCDInfoNP, NULL);
+		readout_is_running=0;
+	}
+}
+
+/* Writes a simulated star to the image buffer*/
+void makestar(int x, int y, unsigned long f,int boxsize,double fwhm)
+{
+	int i,j,b;
+	unsigned long val;
+	float rr;
+	for (i=x-boxsize/2;i<x+boxsize/2;i++){
+		for (j=y-boxsize/2;j<y+boxsize/2;j++){
+			if ((i<0)||(j<0)||(i>WIDTH-1)||(j>HEIGHT-1)) {
+				continue;
+			}
+			rr=exp(-2.0*0.7*((x-i)*(x-i)+(y-j)*(y-j))/(fwhm*fwhm));
+			val=0;
+			for (b=0;b<BYTESPERPIX;b++) {
+				val+=(unsigned long) image[BYTESPERPIX*i+WIDTH*BYTESPERPIX*j+b]*pow(256.0,b);
+			}
+			val+=f*rr;
+			if (BYTESPERPIX==1) {
+				val=val/256;
+			}
+			for (b=0;b<BYTESPERPIX;b++) {
+				image[BYTESPERPIX*i+WIDTH*BYTESPERPIX*j+b]=val % 256;
+				val=(val-(val % 256))/256;
+			}
+		}
+	}
+}
+
+/*Write a simulated bias with readout noise to the image buffer */
+void makebias(unsigned long bias,unsigned long noise)
+{
+	int i,j,b;
+	unsigned long val;
+	for (i=0;i<WIDTH;i+=1){
+		for (j=0;j<HEIGHT;j+=1){
+			val=bias;
+			val+=(unsigned long) (noise*(rand()/(1.0*RAND_MAX)));
+			if (BYTESPERPIX==1) {
+				val=val/256;
+			}
+			for (b=0;b<BYTESPERPIX;b++) {
+				image[BYTESPERPIX*i+WIDTH*BYTESPERPIX*j+b]=val % 256;
+				val=(val-(val % 256))/256;
+			}
+		}
+	}
+}
+
+/*Fill the image buffer with some pseudoastronimical data*/
+void makepic()
+{
+	unsigned long i,x,y,b;
+	double rr;
+	makebias(200,6);
+	/*some faint stars*/
+	for (i=1;i<50;i++) {
+		x=(int) ((WIDTH-1)*(rand()/(1.0*RAND_MAX)));
+		y=(int) ((HEIGHT-1)*(rand()/(1.0*RAND_MAX)));
+		rr=pow((rand()/(1.0*RAND_MAX)),2.0)+pow((rand()/(1.0*RAND_MAX)),2.0)
+		  +pow((rand()/(1.0*RAND_MAX)),2.0);
+		rr*=10;
+		b=(int) (10000.0/(rr+1));
+		makestar(x,y,b,3*fwhm(),fwhm());
+	}
+	/*some bright stars*/
+	for (i=1;i<50;i++) {
+		x=(int) ((WIDTH-1)*(rand()/(1.0*RAND_MAX)));
+		y=(int) ((HEIGHT-1)*(rand()/(1.0*RAND_MAX)));
+		rr=pow((rand()/(1.0*RAND_MAX)),2.0)+pow((rand()/(1.0*RAND_MAX)),2.0)
+		  +pow((rand()/(1.0*RAND_MAX)),2.0);
+		rr*=10;
+		b=(unsigned long) (10000.0/(rr+1));
+		if (BYTESPERPIX>1) {
+			b=(unsigned long) b*(pow(256.0,BYTESPERPIX-2.0));
+		}
+		makestar(x,y,b,3*fwhm(),fwhm() );
+	}
+	/*some  stars of defined brightness */
+	for (i=1;i<3;i++) {
+		x=(int) ((WIDTH-1)*(rand()/(1.0*RAND_MAX)));
+		y=(int) ((HEIGHT-1)*(rand()/(1.0*RAND_MAX)));
+		b=65000;
+		makestar(x,y,b,100,fwhm());
+	}
+	makestar(WIDTH/2,HEIGHT/2,65000,100,fwhm());
+}
Index: /BAORadio/libindi/v1/examples/tutorial_dome.c
===================================================================
--- /BAORadio/libindi/v1/examples/tutorial_dome.c	(revision 500)
+++ /BAORadio/libindi/v1/examples/tutorial_dome.c	(revision 500)
@@ -0,0 +1,202 @@
+#if 0
+    Inter-driver communications tutorial - Dome Driver
+    Copyright (C) 2007 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <zlib.h>
+
+#include "indidevapi.h"
+#include "eventloop.h"
+#include "indicom.h"
+
+#define mydev           "Dome"
+
+#define MAIN_GROUP	"Main"
+#define SNOOP_GROUP     "Snooped"
+
+/* Connect/Disconnect */
+static ISwitch PowerS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty PowerSP	= { mydev, "CONNECTION" , "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+
+/* Dome Open/Close */
+static ISwitch DomeS[]           	= {{"Open", "", ISS_ON, 0, 0}, {"Close", "", ISS_OFF, 0, 0}};
+static ISwitchVectorProperty DomeSP	= { mydev, "Dome Status", "", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DomeS , NARRAY(DomeS), "", 0};
+
+/* The property we're trying to fetch from the rain driver. It's a carbon copy of the property define in rain.c, we initilize its structure here like any
+   other local property, but we don't define it to client, it's only used internally within the driver. 
+
+   MAKE SURE to set the property's device name to the device we're snooping on! If you copy/paste the property definition from the snooped driver
+   don't forget to remove "mydev" and replace it with the driver name.
+*/
+static ILight RainL[]			= {{"Status", "", IPS_IDLE, 0, 0}};
+static ILightVectorProperty RainLP	= { "Rain", "Rain Alert", "", SNOOP_GROUP, IPS_IDLE, RainL , NARRAY(RainL), "", 0};
+
+void ISGetProperties (const char *dev)
+{ 
+  /* MAIN_GROUP */
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefSwitch(&DomeSP, NULL);
+
+  /* Let's listen for Rain Alert property in the device Rain */
+  IDSnoopDevice("Rain", "Rain Alert");
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
+
+void ISSnoopDevice (XMLEle *root)
+{
+
+  IPState old_state = RainL[0].s;
+
+  /* If the "Rain Alert" property gets updated in the Rain device, we will receive a notification. We need to process the new values of Rain Alert and update the local version
+     of the property.*/
+  if (IUSnoopLight(root, &RainLP) == 0)
+  {
+
+    // If the dome is connected and rain is Alert */
+    if (PowerSP.s == IPS_OK && RainL[0].s == IPS_ALERT)
+    {
+	// If dome is open, then close it */
+	if (DomeS[0].s == ISS_ON)
+		closeDome();
+	else
+		IDMessage(mydev, "Rain Alert Detected! Dome is already closed.");
+    }
+    else if (old_state == IPS_ALERT && RainL[0].s != IPS_ALERT)
+		IDMessage(mydev, "Rain threat passed. Opening the dome is now safe.");
+
+  }
+
+}
+
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+
+	/* Connection */
+	if (!strcmp (name, PowerSP.name))
+	{
+	  if (IUUpdateSwitch(&PowerSP, states, names, n) < 0)
+		return;
+
+   	  PowerSP.s = IPS_OK;
+
+	  if (PowerS[0].s == ISS_ON)
+		IDSetSwitch(&PowerSP, "Dome is online.");
+	else
+	{
+		PowerSP.s = IPS_IDLE;
+		IDSetSwitch(&PowerSP, "Dome is offline.");
+	}
+
+	  return;
+	}
+
+	/* Dome */
+	if (!strcmp (name, DomeSP.name))
+	{
+	
+	  if (PowerSP.s != IPS_OK)
+	  {
+		  IDMessage(mydev, "Dome is offline!");
+		  return;
+	  }
+	  
+	  if (IUUpdateSwitch(&DomeSP, states, names, n) < 0)
+		return;
+
+	DomeSP.s = IPS_BUSY;
+
+	if (DomeS[0].s == ISS_ON)
+	{
+		if (RainL[0].s == IPS_ALERT)
+		{
+			DomeSP.s = IPS_ALERT;
+			DomeS[0].s = ISS_OFF;
+			DomeS[1].s = ISS_ON;
+			IDSetSwitch(&DomeSP, "It is raining, cannot open dome.");
+			return;
+		}
+				
+		IDSetSwitch(&DomeSP, "Dome is opening.");
+	}
+	else
+		IDSetSwitch(&DomeSP, "Dome is closing.");
+
+	sleep(5);
+
+	 DomeSP.s = IPS_OK;
+
+	if (DomeS[0].s == ISS_ON)
+		IDSetSwitch(&DomeSP, "Dome is open.");
+	else
+		IDSetSwitch(&DomeSP, "Dome is closed.");
+
+	  return;
+	}
+     
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+       /* ignore if not ours */ 
+       if (dev && strcmp (mydev, dev))
+         return;
+
+	/* suppress warning */
+	n=n; dev=dev; name=name; names=names; texts=texts;
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) {}
+
+void closeDome()
+{
+	DomeSP.s = IPS_BUSY;
+
+	IDSetSwitch(&DomeSP, "Rain Alert! Dome is closing...");
+
+	sleep(5);
+
+	DomeS[0].s = ISS_OFF;
+	DomeS[1].s = ISS_ON;
+	
+	DomeSP.s = IPS_OK;
+
+	IDSetSwitch(&DomeSP, "Dome is closed.");
+	
+	
+}
+
Index: /BAORadio/libindi/v1/examples/tutorial_one.c
===================================================================
--- /BAORadio/libindi/v1/examples/tutorial_one.c	(revision 500)
+++ /BAORadio/libindi/v1/examples/tutorial_one.c	(revision 500)
@@ -0,0 +1,194 @@
+/*
+   INDI Developers Manual
+   Tutorial #1
+   
+   "Hello INDI"
+   
+   We construct a most basic (and useless) device driver to illustate INDI.
+   
+   Refer to README, which contains instruction on how to build this driver, and use it 
+   with an INDI-compatible client.
+
+*/
+
+/** \file tutorial_one.c
+    \brief Construct a basic INDI driver with only one property.
+    \author Jasem Mutlaq
+*/
+
+/* Standard headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+
+/* INDI Core headers */
+
+/* indidevapi.h contains API declerations */
+#include "indidevapi.h"
+
+/* INDI Eventloop mechanism */
+#include "eventloop.h"
+
+/* INDI Common Routines */
+#include "indicom.h"
+
+/* Definitions */
+
+#define mydev		"Simple Device"				/* Device name */
+#define MAIN_GROUP	"Main Control"				/* Group name */
+
+/* Function protptypes */
+void connectDevice(void);
+
+/*INDI controls */
+
+/* We will define only one vector switch property. The CONNECTION property is an INDI Standard Property and should be implemented in all INDI drivers.
+ * A vector property may have one or more members. */
+
+/* First, we define and initilize the members of the vector property */
+static ISwitch PowerS[]          	= {
+							  {"CONNECT"			/* 1st Swtich name */
+							  , "Connect" 			/* Switch Label, i.e. what the GUI displays */
+							  , ISS_OFF 			/* State of the switch, initially off */
+						          , 0					/* auxiluary, set to 0 for now.*/
+						          , 0}					/* auxiluary, set to 0 for now */
+							 
+						         ,{"DISCONNECT"		/* 2nd Swtich name */
+						         , "Disconnect"			/* Switch Label, i.e. what the GUI displays */
+						         , ISS_ON				/* State of the switch, initially on */
+						         , 0					/* auxiluary, set to 0 for now.*/
+						         , 0}					/* auxiluary, set to 0 for now */
+						     };
+						     
+/* Next, we define and initlize the vector switch property that contains the two switches we defined above */
+static ISwitchVectorProperty PowerSP    = { 
+								mydev			/* Device name */
+								, "CONNECTION"  	/* Property name */
+								, "Connection"		/* Property label */
+								, MAIN_GROUP	/* Property group */
+								, IP_RW			/* Property premission, it's both read and write */
+								, ISR_1OFMANY	/* Switch behavior. Only 1 of many switches are allowed to be on at the same time */
+								, 0				/* Timeout, 0 seconds */
+								, IPS_IDLE		/* Initial state is idle */
+								, PowerS			/* Switches comprimising this vector that we defined above */
+								, NARRAY(PowerS)	/* Number of Switches. NARRAY is defined in indiapi.h */
+								, ""				/* Timestamp, set to 0 */
+								, 0};				/* auxiluary, set to 0 for now */
+
+
+/* void ISGetProperties (const char *dev)
+*  INDI will call this function when the client inquires about the device properties.
+*  Here we will use IDxxx functions to define new properties to the client */
+void ISGetProperties (const char *dev)
+{ 
+  /* Tell the client to create a new Switch property PowerSP */
+  IDDefSwitch(&PowerSP, NULL); 
+}
+  
+/* void ISNewSwitch(...)
+ * INDI will call this function when the client wants to set a new state of existing switches 
+ ** Parameters **
+ 
+ * dev: the device name
+ * name: the property name the client wants to update
+ * states: an array of states of members switches (ISS_ON and ISS_OFF)
+ * names: names of the switches. The names are parallel to the states. That is, member names[0] has a state states[0], and so on...
+ * n: number of switches to update, which is also the dimension of *states and names[]
+*/
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+      /* Let's check if the property the client wants to change is the PowerSP (name: CONNECTION) property*/
+     if (!strcmp (name, PowerSP.name))
+     {
+          /* If the clients wants to update this property, let's perform the following */
+	  
+	  /* A. We update the switches by sending their names and updated states IUUpdateSwitches function. If there is an error, we return */
+	  if (IUUpdateSwitch(&PowerSP, states, names, n) < 0) return;
+	  
+	  /* B. We try to establish a connection to our device */
+   	  connectDevice();
+	  return;
+     }
+}
+
+/* void ISNewText(...)
+ * INDI will call this function when the client wants to update an existing text.
+ ** Parameters **
+ 
+ * dev: the device name
+ * name: the property name the client wants to update
+ * texts: an array of texts.
+ * names: names of the members. The names are parallel to the texts.
+ * n: number of texts to update, which is also the dimension of *texts and names[]
+*/
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+        /* Even though we didn't define any text members, we need to define this function. Otherwise, the driver will not compile */
+	/* Since there is nothing to do, we simply return */
+	return;	
+}
+
+/* void ISNewNumber(...)
+ * INDI will call this function when the client wants to update an existing number.
+ ** Parameters **
+ 
+ * dev: the device name
+ * name: the property name the client wants to update
+ * values: an array of values.
+ * names: names of the members. The names are parallel to the values.
+ * n: number of numbers to update, which is the dimension of *numbers and names[]
+*/
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+         /* Even though we didn't define any number members, we need to define this function. Otherwise, the driver will not compile */
+	/* Since there is nothing to do, we simply return */
+        return;
+}
+
+/* Note that we must define ISNewBLOB and ISSnoopDevice even if we don't use them, otherwise, the driver will NOT compile */
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
+void ISSnoopDevice (XMLEle *root) {}
+
+
+/* void connectDevice(void)
+ * This function is called when the state of PowerSP is changed in the ISNewSwitch() function.
+ * We check the state of CONNECT and DISCONNECT switches, and connect or disconnect our fake device accordingly */
+void connectDevice(void)
+{
+
+  /* Now we check the state of CONNECT, the 1st member of the PowerSP property we defined earliar */
+  switch (PowerS[0].s)
+  {
+     /* If CONNECT is on, then try to establish a connection to the device */
+     case ISS_ON:
+      
+      /* The IDLog function is a very useful function that will log time-stamped messages to stderr. This function is invaluable to debug your drivers.
+       * It operates like printf */
+     IDLog ("Establishing a connection to %s...\n", mydev);
+
+      /* Change the state of the PowerSP (CONNECTION) property to OK */
+      PowerSP.s = IPS_OK;
+      
+      /* Tell the client to update the states of the PowerSP property, and send a message to inform successful connection */
+      IDSetSwitch(&PowerSP, "Connection to %s is successful.", mydev);
+      break;
+      
+    /* If CONNECT is off (which is the same thing as DISCONNECT being on), then try to disconnect the device */
+    case ISS_OFF:
+    
+       IDLog ("Terminating connection to %s...\n", mydev);
+       
+      /* The device is disconnected, change the state to IDLE */
+      PowerSP.s = IPS_IDLE;
+      
+      /* Tell the client to update the states of the PowerSP property, and send a message to inform successful disconnection */
+      IDSetSwitch(&PowerSP, "%s has been disconneced.", mydev);
+      
+      break;
+     }
+     
+}
+
+/* That's it! check out tutorial_two where we simulate a simple telescope! */
Index: /BAORadio/libindi/v1/examples/tutorial_rain.c
===================================================================
--- /BAORadio/libindi/v1/examples/tutorial_rain.c	(revision 500)
+++ /BAORadio/libindi/v1/examples/tutorial_rain.c	(revision 500)
@@ -0,0 +1,145 @@
+#if 0
+    Inter-driver communications tutorial - Rain Driver 
+    Copyright (C) 2007 Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <zlib.h>
+
+#include "indidevapi.h"
+#include "eventloop.h"
+#include "indicom.h"
+
+#define mydev           "Rain"
+
+#define MAIN_GROUP	"Main"
+
+/* Connect/Disconnect */
+static ISwitch PowerS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty PowerSP	= { mydev, "CONNECTION" , "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+
+/* Rain Alert Property. The dome driver will listen to updates on this property. 
+   The rain driver does not need to take any action to make this property available to other driver,
+   the INDI framework takes care of handling inter-driver communication
+*/
+static ILight RainL[]			= {{"Status", "", IPS_IDLE, 0, 0}};
+static ILightVectorProperty RainLP	= { mydev, "Rain Alert", "", MAIN_GROUP, IPS_IDLE, RainL , NARRAY(RainL), "", 0};
+
+static ISwitch RainS[]           	= {{"On", "", ISS_OFF, 0, 0}, {"Off", "", ISS_ON, 0, 0}};
+static ISwitchVectorProperty RainSP	= { mydev, "Control Rain", "", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, RainS , NARRAY(RainS), "", 0};
+
+void ISGetProperties (const char *dev)
+{ 
+  /* MAIN_GROUP */
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefLight(&RainLP, NULL);
+  IDDefSwitch(&RainSP, NULL);
+}
+
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
+void ISSnoopDevice (XMLEle *root) {}
+  
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+
+	/* Connection */
+	if (!strcmp (name, PowerSP.name))
+	{
+	  if (IUUpdateSwitch(&PowerSP, states, names, n) < 0)
+		return;
+
+   	  PowerSP.s = IPS_OK;
+
+	  if (PowerS[0].s == ISS_ON)
+		IDSetSwitch(&PowerSP, "Rain Collector is online.");
+	  else
+	  {
+		PowerSP.s = IPS_IDLE;
+		IDSetSwitch(&PowerSP, "Rain Collector is offline.");
+	  }
+	  return;
+	}
+
+	/* rain */
+	if (!strcmp (name, RainSP.name))
+	{
+		if (PowerSP.s != IPS_OK)
+		{
+			IDMessage(mydev, "The Rain Collector is offline!");
+			return;
+		}
+		
+	  if (IUUpdateSwitch(&RainSP, states, names, n) < 0)
+		return;
+
+	 RainSP.s = IPS_OK;
+	 IDSetSwitch(&RainSP, "Rain status updated.");
+	 
+	 if (RainS[0].s == ISS_ON)
+	 {
+		 RainL[0].s = IPS_ALERT;
+		 RainLP.s   = IPS_ALERT;
+		 IDSetLight(&RainLP, "Alert! Alert! Rain detected!");
+	 }
+	 else
+	 {
+		 RainL[0].s = IPS_IDLE;
+		 RainLP.s   = IPS_OK;
+		 IDSetLight(&RainLP, "Rain threat passed. The skies are clear.");
+	 }
+	 
+	   return;
+	}
+			
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+ 
+       /* ignore if not ours */ 
+       if (dev && strcmp (mydev, dev))
+         return;
+
+	/* suppress warning */
+	n=n; dev=dev; name=name; names=names; texts=texts;
+	
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+       
+}
+
Index: /BAORadio/libindi/v1/examples/tutorial_three.c
===================================================================
--- /BAORadio/libindi/v1/examples/tutorial_three.c	(revision 500)
+++ /BAORadio/libindi/v1/examples/tutorial_three.c	(revision 500)
@@ -0,0 +1,323 @@
+/*
+   INDI Developers Manual
+   Tutorial #3
+   
+   "Simple CCD Simulator"
+   
+   In this tutorial, we employ a BLOB property to send a sample FITS file to the client.
+   
+   Refer to README, which contains instruction on how to build this driver, and use it 
+   with an INDI-compatible client.
+
+*/
+
+/** \file tutorial_three.c
+    \brief Simulate a CCD camera by using INDI BLOBs to send FITS data to the client.
+    \author Jasem Mutlaq
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <zlib.h>
+
+/* INDI Core headers */
+#include "indidevapi.h"
+#include "indicom.h"
+#include "eventloop.h"
+#include "base64.h"
+
+#define mydev         	"CCD Simulator"
+#define COMM_GROUP	"Main Control"
+
+/* Handy macro */
+#define currentTemp	TemperatureN[0].value
+
+void uploadFile(const char* filename);
+void ISPoll(void * p);
+
+static double targetTemp	= 0;
+
+/*INDI controls */
+
+/* Connect/Disconnect */
+static ISwitch PowerS[]          	= {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
+static ISwitchVectorProperty PowerSP	= { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
+
+/* Exposure time */
+static INumber ExposeTimeN[]    = {{ "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., .5, 1., 0, 0, 0}};
+static INumberVectorProperty ExposeTimeNP = { mydev, "CCD_EXPOSURE", "Expose", COMM_GROUP, IP_RW, 60, IPS_IDLE, ExposeTimeN, NARRAY(ExposeTimeN), "", 0};
+ 
+/* Temperature control */
+ static INumber TemperatureN[]	  = { {"CCD_TEMPERATURE_VALUE", "Temperature", "%+06.2f", -30., 40., 1., 0., 0, 0, 0}};
+ static INumberVectorProperty TemperatureNP = { mydev, "CCD_TEMPERATURE", "Temperature (C)", COMM_GROUP, IP_RW, 60, IPS_IDLE, TemperatureN, NARRAY(TemperatureN), "", 0};
+
+/* BLOB for sending image */
+static IBLOB imageB = {"CCD1", "Feed", "", 0, 0, 0, 0, 0, 0, 0};
+static IBLOBVectorProperty imageBP = {mydev, "Video", "Video", COMM_GROUP,
+  IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0};
+
+void ISGetProperties (const char *dev)
+{ 
+
+  if (dev && strcmp (mydev, dev))
+    return;
+
+  /* COMM_GROUP */
+  IDDefSwitch(&PowerSP, NULL);
+  IDDefNumber(&ExposeTimeNP, NULL);
+  IDDefNumber(&TemperatureNP, NULL);
+  IDDefBLOB(&imageBP, NULL);
+
+  IEAddTimer(1000, ISPoll, NULL);
+  
+}
+
+/* Note that we must define ISNewBLOB and ISSnoopDevice even if we don't use them, otherwise, the driver will NOT compile */
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
+void ISSnoopDevice (XMLEle *root) {}
+
+  
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	/* ignore if not ours */
+	if (dev && strcmp (dev, mydev))
+	    return;
+	    
+	/* Connection */
+	if (!strcmp (name, PowerSP.name))
+	{
+	  IUUpdateSwitch(&PowerSP, states, names, n);
+   	  PowerSP.s = IPS_OK;
+          if (PowerS[0].s == ISS_ON)
+          	IDSetSwitch(&PowerSP, "CCD Simulator is online.");
+          else
+		IDSetSwitch(&PowerSP, "CCD Simulator is offline.");
+	  return;
+	}
+	
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+       /* ignore if not ours */ 
+       if (dev && strcmp (mydev, dev))
+         return;
+
+	/* suppress warning */
+	n=n; dev=dev; name=name; names=names; texts=texts;
+	
+}
+
+
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+
+    /* Exposure time */
+    if (!strcmp (ExposeTimeNP.name, name))
+    {
+
+     /* Let's make sure that our simulator is online */
+     if (PowerS[0].s != ISS_ON)
+     {
+       ExposeTimeNP.s = IPS_IDLE;
+       IDSetNumber(&ExposeTimeNP, "CCD Simulator is offline.");
+       return;
+     }
+
+      IDLog("Sending BLOB FITS...\n");
+
+      ExposeTimeNP.s = IPS_BUSY;
+      ExposeTimeN[0].value = values[0];
+ 
+      return;
+    } 
+
+    /* Temperature */
+    if (!strcmp (TemperatureNP.name, name))
+    {
+
+     /* Let's make sure that our simulator is online */
+     if (PowerS[0].s != ISS_ON)
+     {
+       TemperatureNP.s = IPS_IDLE;
+       IDSetNumber(&TemperatureNP, "CCD Simulator is offline");
+       return;
+     }
+
+      targetTemp = values[0];
+
+      /* If the requested temperature is the current CCD chip temperature, then return */
+      if (targetTemp == TemperatureN[0].value)
+      {
+        TemperatureNP.s = IPS_OK;
+        IDSetNumber(&TemperatureNP, NULL);
+        return;
+      }
+      
+      /* Otherwise, set property state to busy */
+      TemperatureNP.s = IPS_BUSY;
+      IDSetNumber(&TemperatureNP, "Setting CCD temperature to %g", targetTemp);
+
+      return;
+    }
+
+}
+
+/* Open a data file, compress its content, and send it via our BLOB property */
+void uploadFile(const char* filename)
+{
+   FILE * fitsFile;
+   unsigned char *fitsData, *compressedData;
+   int r=0;
+   unsigned int i =0, nr = 0;
+   uLongf compressedBytes=0;
+   uLong  totalBytes;
+   struct stat stat_p; 
+ 
+   /* #1 Let's get the file size */
+   if ( -1 ==  stat (filename, &stat_p))
+   { 
+     IDLog(" Error occoured attempting to stat file.\n"); 
+     return; 
+   }
+   
+   /* #2 Allocate memory for raw and compressed data */
+   totalBytes     = stat_p.st_size;
+   fitsData       = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes);
+   compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
+   
+   if (fitsData == NULL || compressedData == NULL)
+   {
+     IDLog("Error! low memory. Unable to initialize fits buffers.\n");
+     return;
+   }
+   
+   /* #3 Open the FITS file */
+   fitsFile = fopen(filename, "r");
+   
+   if (fitsFile == NULL)
+    return;
+   
+   /* #4 Read file from disk */ 
+   for (i=0; i < totalBytes; i+= nr)
+   {
+      nr = fread(fitsData + i, 1, totalBytes - i, fitsFile);
+     
+     if (nr <= 0)
+     {
+        IDLog("Error reading temporary FITS file.\n");
+        return;
+     }
+   }
+   
+   compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
+    
+   /* #5 Compress raw data */ 
+   r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9);
+   if (r != Z_OK)
+   {
+ 	/* this should NEVER happen */
+ 	IDLog("internal error - compression failed: %d\n", r);
+	return;
+   }
+   
+   /* #6 Send it */
+   imageB.blob = compressedData;
+   imageB.bloblen = compressedBytes;
+   imageB.size = totalBytes;
+   strcpy(imageB.format, ".fits.z");
+
+   /* #7 Set BLOB state to Ok */
+   imageBP.s = IPS_OK;
+   IDSetBLOB (&imageBP, NULL);
+
+   /* #8 Set Exposure status to Ok */
+   ExposeTimeNP.s = IPS_OK;
+   IDSetNumber(&ExposeTimeNP, "Sending FITS...");
+   
+   /* #9 Let's never forget to free our memory */
+   free (fitsData);   
+   free (compressedData);
+   
+}
+
+/* Poll device status and update accordingly */
+void ISPoll(void * p)
+{
+
+   /* We need to check the status of properties that we want to watch. */
+
+   /* #1 CCD Exposure */
+   switch (ExposeTimeNP.s)
+   {
+     case IPS_IDLE:
+     case IPS_OK:
+     case IPS_ALERT:
+	break;
+
+     /* If an exposure state is busy, decrement the exposure value until it's zero (done exposing). */
+     case IPS_BUSY:
+	ExposeTimeN[0].value--;
+
+        /* Are we done yet? */
+        if (ExposeTimeN[0].value == 0)
+        {
+          /* Let's set the state of OK and report that to the client */
+          ExposeTimeNP.s = IPS_OK;
+ 
+          /* Upload a sample FITS file */
+          uploadFile("ngc1316o.fits");
+
+          IDSetNumber(&ExposeTimeNP, NULL);
+	  break;
+        }
+
+	IDSetNumber(&ExposeTimeNP, NULL);
+        break;
+   } 
+
+   /* #2 CCD Temperature */
+   switch (TemperatureNP.s)
+   {
+     case IPS_IDLE:
+     case IPS_OK:
+     case IPS_ALERT:
+	break;
+
+     case IPS_BUSY:
+     /* If target temperature is higher, then increase current CCD temperature */  
+     if (currentTemp < targetTemp)
+        currentTemp++;
+     /* If target temperature is lower, then decrese current CCD temperature */
+     else if (currentTemp > targetTemp)
+       currentTemp--;
+     /* If they're equal, stop updating */
+     else
+     {
+       TemperatureNP.s = IPS_OK;
+       IDSetNumber(&TemperatureNP, "Target temperature reached.");
+
+       break;
+     }
+
+     IDSetNumber(&TemperatureNP, NULL);
+     break;
+   }
+
+   /* Keep polling alive */
+   IEAddTimer (1000, ISPoll, NULL);
+
+}
Index: /BAORadio/libindi/v1/examples/tutorial_two.c
===================================================================
--- /BAORadio/libindi/v1/examples/tutorial_two.c	(revision 500)
+++ /BAORadio/libindi/v1/examples/tutorial_two.c	(revision 500)
@@ -0,0 +1,387 @@
+/*
+   INDI Developers Manual
+   Tutorial #2
+   
+   "Simple Telescope Simulator"
+   
+   In this tutorial, we create a simple simulator. We will use a few handy utility functions provided by INDI
+   like timers, string <---> number conversion, and more.
+   
+   Refer to README, which contains instruction on how to build this driver, and use it 
+   with an INDI-compatible client.
+
+*/
+
+/** \file tutorial_two.c
+    \brief Implement a simple telescope simulator using more complex INDI concepts.
+    \author Jasem Mutlaq
+*/
+
+/* Standard headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <sys/time.h>
+#include <time.h>
+
+void show_runtime(int state) {
+	static struct timeval tv;
+	struct timeval tv1;
+	double x, y;
+
+	if (state) {
+		gettimeofday(&tv, NULL);
+	} else {
+		gettimeofday(&tv1, NULL);
+		fprintf(stderr, "Ran for: %fmsec\n", (double)(tv1.tv_sec * 1000.0 + tv1.tv_usec / 1000.0) - (double)(tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0));
+	}
+}
+
+/* INDI Core headers */
+
+/* indidevapi.h contains API declerations */
+#include "indidevapi.h"
+
+/* INDI Eventloop mechanism */
+#include "eventloop.h"
+
+/* INDI Common Routines */
+#include "indicom.h"
+
+/* Definitions */
+
+#define	mydev		"Telescope Simulator"		/* Device name */
+#define MAIN_GROUP	"Main Control"			/* Group name */
+#define	SLEWRATE	1				/* slew rate, degrees/s */
+#define	POLLMS		250				/* poll period, ms */
+#define SIDRATE		0.004178			/* sidereal rate, degrees/s */
+
+/* Function protptypes */
+static void connectTelescope (void);
+static void mountSim (void *);
+
+/* operational info */
+static double targetRA;
+static double targetDEC;
+
+/* main connection switch
+  Note that the switch will appear to the user as On and Off (versus Connect and Disconnect in tutorial one)
+  Nevertheless, the members _names_ are still CONNECT and DISCONNECT and therefore this is a perfectly legal standard property decleration
+   */
+static ISwitch connectS[] = {
+    {"CONNECT",  "On",  ISS_OFF, 0, 0}, {"DISCONNECT", "Off", ISS_ON, 0, 0}};
+
+static ISwitchVectorProperty connectSP = { mydev, "CONNECTION", "Connection",  MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE,  connectS, NARRAY(connectS), "", 0 };
+
+/* Equatorial position. EQUATORIAL_EOD_COORD is one of INDI's reserved Standard  Properties */
+static INumber eqN[] = {
+                                /* 1st member is Right ascension */
+    				{"RA"				/* 1st Number name */
+				,"RA  H:M:S"			/* Number label */
+				, "%10.6m"			/* Format. Refer to the indiapi.h for details on number formats */
+				,0.					/* Minimum value */
+				, 24.					/* Maximum value */
+				, 0.					/* Steps */
+				, 0.					/* Initial value */
+				, 0					/* Pointer to parent, we don't use it, so set it to 0 */
+				, 0					/* Auxiluary member, set it to 0 */
+				, 0},					/* Autxiluar member, set it to 0 */
+				
+				/* 2nd member is Declination */
+    				{"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}
+};
+
+static INumberVectorProperty eqNP = {  mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow",  MAIN_GROUP , IP_RO, 0, IPS_IDLE,  eqN, NARRAY(eqN), "", 0};
+
+
+/* Equatorial EOD Coord Request. This property is for requesting changes to target equatorial coordinates. However, the CURRENT coordinates are reported in EQUATORIAL_EOD_COORDS above.*/
+static INumber eqNR[] = {{"RA_REQUEST" ,"RA  H:M:S" , "%10.6m" ,0. , 24., 0., 0., 0, 0, 0},
+			 {"DEC_REQUEST", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}};
+static INumberVectorProperty eqNPR = {  mydev, "EQUATORIAL_EOD_COORD_REQUEST", "Equatorial Request",  MAIN_GROUP , IP_RW, 0, IPS_IDLE,  eqNR, NARRAY(eqNR), "", 0};
+
+/* Property naming convention. All property names are lower case with a postfix to indicate their type. connectS is a switch, 
+ * connectSP is a switch vector. eqN is a number, eqNP is a number property, and so on. While this is not strictly required, it makes the code easier to read. */
+
+#define	currentRA	eqN[0].value		/* scope's current simulated RA, rads. Handy macro to right ascension from eqN[] */
+#define	currentDec	eqN[1].value		/* scope's current simulated Dec, rads. Handy macro to declination from eqN[] */
+
+/********************************************
+ Property: Movement (Arrow keys on handset). North/South
+*********************************************/
+static ISwitch MovementNSS[]       = {{"MOTION_NORTH", "North", ISS_OFF, 0, 0}, {"MOTION_SOUTH", "South", ISS_OFF, 0, 0}};
+ISwitchVectorProperty MovementNSSP      = { mydev, "TELESCOPE_MOTION_NS", "North/South", MAIN_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, MovementNSS, NARRAY(MovementNSS), "", 0};
+
+/********************************************
+ Property: Movement (Arrow keys on handset). West/East
+*********************************************/
+static ISwitch MovementWES[]       = {{"MOTION_WEST", "West", ISS_OFF, 0, 0}, {"MOTION_EAST", "East", ISS_OFF, 0, 0}};
+ISwitchVectorProperty MovementWESP      = { mydev, "TELESCOPE_MOTION_WE", "West/East", MAIN_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0};
+
+/* Initlization routine */
+static void mountInit()
+{
+	static int inited;		/* set once mountInit is called */
+
+	if (inited)
+	    return;
+	
+	/* start timer to simulate mount motion
+	   The timer will call function mountSim after POLLMS milliseconds */
+	IEAddTimer (POLLMS, mountSim, NULL);
+
+	inited = 1;
+	
+}
+
+/* send client definitions of all properties */
+void ISGetProperties (const char *dev)
+{
+	if (dev && strcmp (mydev, dev))
+	    return;
+
+	IDDefSwitch (&connectSP, NULL);
+	IDDefNumber (&eqNP, NULL);
+	IDDefNumber (&eqNPR, NULL);
+	IDDefSwitch (&MovementNSSP, NULL);
+	IDDefSwitch (&MovementWESP, NULL);
+	
+}
+
+void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+	return;
+}
+
+/* client is sending us a new value for a Numeric vector property */
+void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
+{
+	/* Make sure to initalize */
+	mountInit();
+	
+	/* ignore if not ours */
+	if (strcmp (dev, mydev))
+	    return;
+
+	if (!strcmp (name, eqNPR.name)) {
+	    /* new equatorial target coords */
+	    double newra = 0, newdec = 0;
+	    int i, nset;
+	    
+	    /* Check connectSP, if it is idle, then return */
+	    if (connectSP.s == IPS_IDLE)
+	    {
+		eqNPR.s = IPS_IDLE;
+		IDSetNumber(&eqNP, "Telescope is offline.");
+		return;
+	    }
+	    
+	    for (nset = i = 0; i < n; i++) 
+	    {
+	        /* Find numbers with the passed names in the eqNP property */
+		INumber *eqp = IUFindNumber (&eqNPR, names[i]);
+		
+		/* If the number found is Right ascension (eqN[0]) then process it */
+		if (eqp == &eqNR[0])
+		{
+		    newra = (values[i]);
+		    nset += newra >= 0 && newra <= 24;
+		}
+		/* Otherwise, if the number found is Declination (eqN[1]) then process it */ 
+		else if (eqp == &eqNR[1]) {
+		    newdec = (values[i]);
+		    nset += newdec >= -90 && newdec <= 90;
+		}
+	    } /* end for */
+	    
+	    /* Did we process the two numbers? */
+	    if (nset == 2)
+	    {
+		char r[32], d[32];
+		
+		/* Set the mount state to BUSY */
+		eqNP.s = IPS_BUSY;
+		eqNPR.s = IPS_BUSY;
+		
+		/* Set the new target coordinates */
+		targetRA = newra;
+		targetDEC = newdec;
+		
+		/* Convert the numeric coordinates to a sexagesmal string (H:M:S) */
+		fs_sexa (r, targetRA, 2, 3600);
+		fs_sexa (d, targetDEC, 3, 3600);
+		
+		IDSetNumber(&eqNP, NULL);
+		IDSetNumber(&eqNPR, "Moving to RA Dec %s %s", r, d);
+	    }
+	    /* We didn't process the two number correctly, report an error */
+	    else 
+	    {
+	        /* Set property state to ALERT */
+		eqNPR.s = IPS_ALERT;
+		
+		IDSetNumber(&eqNP, "RA or Dec absent or bogus.");
+	    }
+	    
+	    return;
+	}
+}
+
+/* client is sending us a new value for a Switch property */
+void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+	ISwitch *sp;
+
+	mountInit();
+	
+	/* ignore if not ours */
+	if (strcmp (dev, mydev))
+	    return;
+
+	
+	if (!strcmp(name, connectSP.name))
+	{
+		/* We update switches. This is different from the way we used to update switches in tutorial 1. This is 
+	 	* to illustrate that there are several ways to update the switches. Here, we try to find the switch with names[0],
+	 	* and if found, we update its state to states[0] and call connectTelescope(). We must call IUResetSwitches to erase any previous history */
+	 
+		sp = IUFindSwitch (&connectSP, names[0]);
+	
+		if (sp)
+		{
+	    		IUResetSwitch(&connectSP);
+	    		sp->s = states[0];
+	    		connectTelescope();
+		}
+	}
+	else if (! strcmp(name, MovementNSSP.name)) {
+		sp = IUFindSwitch (&MovementNSSP, names[0]);
+		if (sp) {
+			IUResetSwitch(&MovementNSSP);
+			sp->s = states[0];
+			show_runtime(sp->s);
+			IDSetSwitch (&MovementNSSP, "Toggle North/South.");
+		}
+	}
+	else if (! strcmp(name, MovementWESP.name)) {
+		sp = IUFindSwitch (&MovementWESP, names[0]);
+		if (sp) {
+			IUResetSwitch(&MovementWESP);
+			sp->s = states[0];
+			show_runtime(sp->s);
+			IDSetSwitch (&MovementWESP, "Toggle West/East.");
+		}
+	}
+	
+	
+}
+
+/* update the "mount" over time */
+void mountSim (void *p)
+{
+	static struct timeval ltv;
+	struct timeval tv;
+	double dt, da, dx;
+	int nlocked;
+
+	/* If telescope is not on, do not simulate */
+	if (connectSP.s == IPS_IDLE)
+	{
+		IEAddTimer (POLLMS, mountSim, NULL);
+		return;
+	}
+
+	/* update elapsed time since last poll, don't presume exactly POLLMS */
+	gettimeofday (&tv, NULL);
+	
+	if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
+	    ltv = tv;
+	    
+	dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6;
+	ltv = tv;
+	da = SLEWRATE*dt;
+
+	/* Process per current state. We check the state of EQUATORIAL_EOD_COORDS_REQUEST and act acoordingly */
+	switch (eqNPR.s)
+	{
+	
+	/* #1 State is idle, update telesocpe at sidereal rate */
+	case IPS_IDLE:
+	    /* RA moves at sidereal, Dec stands still */
+	    currentRA += (SIDRATE*dt/15.);
+	    IDSetNumber(&eqNP, NULL);
+	    break;
+
+	case IPS_BUSY:
+	    /* slewing - nail it when both within one pulse @ SLEWRATE */
+	    nlocked = 0;
+
+	    dx = targetRA - currentRA;
+	    
+	    if (fabs(dx) <= da)
+	    {
+		currentRA = targetRA;
+		nlocked++;
+	    }
+	    else if (dx > 0)
+	    	currentRA += da/15.;
+	    else 
+	    	currentRA -= da/15.;
+	    
+
+	    dx = targetDEC - currentDec;
+	    if (fabs(dx) <= da)
+	    {
+		currentDec = targetDEC;
+		nlocked++;
+	    }
+	    else if (dx > 0)
+	      currentDec += da;
+	    else
+	      currentDec -= da;
+
+	    if (nlocked == 2)
+	    {
+		eqNP.s = IPS_OK;
+		eqNPR.s = IPS_OK;
+		IDSetNumber(&eqNP, NULL);
+		IDSetNumber(&eqNPR, "Now tracking");
+	    } else
+		IDSetNumber(&eqNP, NULL);
+
+	    break;
+
+	case IPS_OK:
+	    /* tracking */
+	   IDSetNumber(&eqNP, NULL);
+	    break;
+
+	case IPS_ALERT:
+	    break;
+	}
+
+	/* again */
+	IEAddTimer (POLLMS, mountSim, NULL);
+}
+
+/* Note that we must define ISNewBLOB and ISSnoopDevice even if we don't use them, otherwise, the driver will NOT compile */
+void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
+void ISSnoopDevice (XMLEle *root) {}
+
+
+static void connectTelescope ()
+{
+	if (connectS[0].s == ISS_ON)
+	{
+	    connectSP.s   = IPS_OK;
+	    IDSetSwitch (&connectSP, "Telescope is connected.");
+	} 
+	else
+	{
+	    connectSP.s   = IPS_IDLE;
+	    IDSetSwitch (&connectSP, "Telescope is disconnected.");
+	}
+}
Index: /BAORadio/libindi/v1/fq.c
===================================================================
--- /BAORadio/libindi/v1/fq.c	(revision 500)
+++ /BAORadio/libindi/v1/fq.c	(revision 500)
@@ -0,0 +1,233 @@
+/* a fifo queue that never fills.
+ * Copyright (C) 2005 Elwood C. Downey ecdowney@clearskyinstitute.com
+ * includes standalone commandline test program, see below.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+ */
+
+/** \file fq.c
+    \brief a fifo queue that never fills.
+
+   Generic FIFO Queue.
+
+   an FQ is a FIFO list of pointers to void, each called an "element".
+   elements are added at q[head]. there are (nq) elements in the list. the
+   element to be removed next is q[head-nq]. there are (head-nq) empty slots
+   at the front of the q array. there are (nmem-head) elements available at
+   the end. if the head reaches the end, existing enties are slid to the front
+   of the array and total memory is adjusted up or down as required.
+   
+   example:
+      
+    <-------------------- nmem = 17 --------------------------------->
+    <-- head - nq = 6 --->   <-- nq = 4 -->  <---- nmem - head = 7 -->
+    ---------------------------------------------------------------------
+    |   |   |   |   |   |   | x | x | x | x |   |   |   |   |   |   |   |
+    ---------------------------------------------------------------------
+      0   1   2   3   4   5   6   7   8   9   ^ 
+                                             head = 10
+ 
+     \author Elwood Downey
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "fq.h"
+
+struct _FQ {
+    void **q;				/* malloced array of (void *) */
+    int nq;				/* number of elements on queue */
+    int head;				/* index into q[] of next empty spot */
+    int nmem;				/* number of total slots in q[] */
+    int grow;				/* n elements to grow when out of room*/
+};
+
+/* default memory managers, override with setMemFuncsFQ() */
+static void *(*mymalloc)(size_t size) = malloc;
+static void *(*myrealloc)(void *ptr, size_t size) = realloc;
+static void (*myfree)(void *ptr) = free;
+
+static void chkFQ (FQ *q);
+
+/* return pointer to a new FQ, or NULL if no more memory.
+ * grow is an efficiency hint of the number of elements to grow when out of
+ *   room, nothing terrible happens if it is wrong.
+ */
+FQ *
+newFQ (int grow)
+{
+	FQ *q = (FQ *)(*mymalloc)(sizeof(FQ));
+	memset (q, 0, sizeof(FQ));
+	q->q = (*mymalloc) (1);		/* seed for realloc */
+	q->grow = grow > 0 ? grow : 1;
+	return (q);
+}
+
+/* delete a FQ no longer needed */
+void
+delFQ (FQ *q)
+{
+	(*myfree) (q->q);		/* guaranteed set in newFQ() */
+	(*myfree) ((void *)q);
+}
+
+/* push an element onto the given FQ */
+void
+pushFQ (FQ *q, void *e)
+{
+	chkFQ (q);
+	q->q[q->head++] = e;
+	q->nq++;
+}
+
+/* pop and return the next element in the given FQ, or NULL if empty */
+void *
+popFQ (FQ *q)
+{
+	return (q->nq > 0 ? q->q[q->head - q->nq--] : NULL);
+}
+
+/* return next element in the given FQ leaving it on the q, or NULL if empty */
+void *
+peekFQ (FQ *q)
+{
+	return (peekiFQ(q,0));
+}
+
+/* return ith element from head of the given FQ.
+ * this can be used for iteration as:
+ *   for (i = 0; i < nFQ(q); i++)
+ *     void *e = peekiFQ(q,i);
+ */
+void *
+peekiFQ (FQ *q, int i)
+{
+	return (q->nq > 0 ? q->q[q->head - q->nq + i] : NULL);
+}
+
+/* return the number of elements in the given FQ */
+int
+nFQ (FQ *q)
+{
+	return (q->nq);
+}
+
+/* install new version of malloc/realloc/free.
+ * N.B. don't call after first use of any other FQ function
+ */
+void
+setMemFuncsFQ (void *(*newmalloc)(size_t size),
+           void *(*newrealloc)(void *ptr, size_t size),
+	   void (*newfree)(void *ptr))
+{
+	mymalloc = newmalloc;
+	myrealloc = newrealloc;
+	myfree = newfree;
+}
+
+/* insure q can hold one more element */
+static void
+chkFQ (FQ *q)
+{
+	int infront;
+
+	/* done if still room at end */
+	if (q->nmem > q->head)
+	    return;
+
+	/* move list to front */
+	infront = q->head - q->nq;
+	memmove (q->q, &q->q[infront], q->nq * sizeof(void*));
+	q->head -= infront;
+
+	/* realloc to minimum number of grow-sized chunks required */
+	q->nmem = q->grow*(q->head/q->grow+1);
+	q->q = (*myrealloc) (q->q, q->nmem * sizeof(void*));
+}
+
+#if defined(TEST_FQ)
+
+/* to build a stand-alone commandline test program:
+ *   cc -DTEST_FQ -o fq fq.c
+ * run ./fq to test push/pop/peek and watch the queue after each operation.
+ * the queue test elements are char, please excuse the ugly casts.
+ */
+
+#include <stdio.h>
+
+/* draw a simple graphical representation of the given FQ */
+static void
+prFQ (FQ *q)
+{
+	int i;
+
+	/* print the q, empty slots print as '.' */
+	for (i = 0; i < q->nmem; i++) {
+	    if (i >= q->head - q->nq && i < q->head)
+		printf ("%c", (char)(int)q->q[i]);
+	    else
+		printf (".");
+	}
+
+	/* add right-justified stats */
+	printf ("%*s nmem = %2d head = %2d nq = %2d\n", 50-i, "", q->nmem,
+							    q->head, q->nq);
+}
+
+int
+main (int ac, char *av[])
+{
+	FQ *q = newFQ(8);
+	int c, e = -1;
+	void *p;
+
+	printf ("Commands:\n");
+	printf (" P  = push a letter a-z\n");
+	printf (" p  = pop a letter\n");
+	printf (" k  = peek into queue\n");
+
+	while ((c = fgetc(stdin)) != EOF) {
+	    switch (c) {
+	    case 'P':
+		pushFQ (q, (void*)('a'+(e=(e+1)%26)));
+		prFQ(q);
+		break;
+	    case 'p':
+		p = popFQ (q);
+		if (p)
+		    printf ("popped %c\n", (char)(int)p);
+		else
+		    printf ("popped empty q\n");
+		prFQ(q);
+		break;
+	    case 'k':
+		p = peekFQ (q);
+		if (p)
+		    printf ("peeked %c\n", (char)(int)p);
+		else
+		    printf ("peeked empty q\n");
+		prFQ(q);
+		break;
+	    default:
+		break;
+	    }
+	}
+
+	return (0);
+}
+#endif /* TEST_FQ */
+
Index: /BAORadio/libindi/v1/fq.h
===================================================================
--- /BAORadio/libindi/v1/fq.h	(revision 500)
+++ /BAORadio/libindi/v1/fq.h	(revision 500)
@@ -0,0 +1,31 @@
+/* a fifo queue that never fills.
+ * Copyright (C) 2005 Elwood C. Downey ecdowney@clearskyinstitute.com
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+typedef struct _FQ FQ;
+
+extern FQ *newFQ(int grow);
+extern void delFQ (FQ *q);
+extern void pushFQ (FQ *q, void *e);
+extern void *popFQ (FQ *q);
+extern void *peekFQ (FQ *q);
+extern void *peekiFQ (FQ *q, int i);
+extern int nFQ (FQ *q);
+extern void setMemFuncsFQ (void *(*newmalloc)(size_t size),
+   void *(*newrealloc)(void *ptr, size_t size),
+   void (*newfree)(void *ptr));
+
Index: /BAORadio/libindi/v1/indiapi.h
===================================================================
--- /BAORadio/libindi/v1/indiapi.h	(revision 500)
+++ /BAORadio/libindi/v1/indiapi.h	(revision 500)
@@ -0,0 +1,388 @@
+#if 0
+    INDI
+    Copyright (C) 2003 Elwood C. Downey
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#ifndef INDI_API_H
+#define INDI_API_H
+
+/** \mainpage Instrument Neutral Distributed Interface INDI
+    \section Introduction
+    
+    INDI is a simple XML-like communications protocol described for interactive and automated remote control of diverse instrumentation.\n
+ 
+ INDI is small, easy to parse, and stateless. In the INDI paradigm each Device poses all command and status functions in terms of settings and getting Properties. Each Property is a vector of one or more names members. Each property has a current value vector; a target value vector; provides information about how it should be sequenced with respect to other Properties to accomplish one coordinated unit of observation; and provides hints as to how it might be displayed for interactive manipulation in a GUI.\n
+ 
+ Clients learn the Properties of a particular Device at runtime using introspection. This decouples Client and Device implementation histories. Devices have a complete authority over whether to accept commands from Clients. INDI accommadates intermediate servers, broadcasting, and connection topologies ranging from one-to-one on a single system to many-to-many between systems of different genre.\n
+ 
+ The INDI protocol can be nested within other XML elements such as constraints for automatic scheduling and execution.\n
+ 
+ For a complete review on the INDI protocol, please refer to the INDI <a href="http://www.clearskyinstitute.com/INDI/INDI.pdf">white paper</a>. 
+ 
+\section Audience Intended Audience 
+
+INDI is intended for developers who seek a scalable API for device control and automation. Hardware drivers written under INDI can be used under any INDI-compatible client. INDI serves as a backend only, you need frontend clients to control devices. Current clients include <a href="http://edu.kde.org/kstars">KStars</a>, <a href="http://www.clearyskyinstitute.com/xephem">Xephem</a>, <a href="http://pygtkindiclient.sourceforge.net/">DCD</a>, and <a href="http://www.stargazing.net/astropc">Cartes du Ciel</a>. 
+
+\section Development Developing under INDI
+
+<p>Please refere to the <a href="http://indi.sourceforge.net/index.php/Manual">INDI Developers Manual</a> for a complete guide on INDI's driver developemnt framework.</p>
+
+<p>The INDI Library API is divided into the following main sections:</p>
+<ul>
+<li><a href="indidevapi_8h.html">INDI Device API</a></li>
+<li><a href="indicom_8h.html">INDI Common Routine Library</a></li>
+<li><a href="lilxml_8h.html">INDI LilXML Library</a></li>
+<li><a href="http://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/cfitsio.html">CFITSIO Library</a></li>
+</ul>
+
+
+\section Help 
+
+You can find information on INDI development in the <a href="http://indi.sf.net">INDI sourceforge</a> site. Furthermore, you can discuss INDI related issues on the <a href="http://sourceforge.net/mail/?group_id=90275">INDI development mailing list</a>. 
+
+\author Elwood Downey
+\author Jasem Mutlaq
+*/
+
+/** \file indiapi.h
+    \brief Constants and Data structure definitions for the interface to the reference INDI C API implementation.
+    \author Elwood C. Downey
+*/
+
+/*******************************************************************************
+ * INDI wire protocol version implemented by this API.
+ * N.B. this is indepedent of the API itself.
+ */
+
+#define	INDIV	1.7
+
+
+/* INDI Library version */
+#define INDI_LIBV	0.6
+
+/*******************************************************************************
+ * Manifest constants
+ */
+
+/** \typedef ISState
+    \brief Switch state.
+*/
+typedef enum 
+{
+    ISS_OFF,		/*!< Switch is OFF */
+    ISS_ON		/*!< Switch is ON */
+} ISState;				/* switch state */
+
+/** \typedef IPState
+    \brief Property state.
+*/
+typedef enum 
+{
+    IPS_IDLE,		/*!< State is idle */
+    IPS_OK,		/*!< State is ok */
+    IPS_BUSY,		/*!< State is busy */
+    IPS_ALERT		/*!< State is alert */
+} IPState;				/* property state */
+
+/** \typedef ISRule
+    \brief Switch vector rule hint.
+*/
+typedef enum 
+{
+    ISR_1OFMANY,	/*!< Only 1 switch of many can be ON (e.g. radio buttons) */
+    ISR_ATMOST1,        /*!< There is only ONE switch */
+    ISR_NOFMANY         /*!< Any number of switches can be ON (e.g. check boxes) */
+} ISRule;				/* switch vector rule hint */
+
+/** \typedef IPerm
+    \brief Permission hint, with respect to client.
+*/
+typedef enum 
+{
+    IP_RO,		/*!< Read Only */
+    IP_WO,		/*!< Write Only */
+    IP_RW		/*!< Read & Write */
+} IPerm;				/* permission hint, WRT client */
+
+/* The XML strings for these attributes may be any length but implementations
+ * are only obligued to support these lengths for the various string attributes.
+ */
+#define	MAXINDINAME	32
+#define	MAXINDILABEL	32
+#define	MAXINDIDEVICE	32
+#define	MAXINDIGROUP	32
+#define	MAXINDIFORMAT	32
+#define	MAXINDIBLOBFMT	32
+#define	MAXINDITSTAMP	32
+
+/*******************************************************************************
+ * Typedefs for each INDI Property type.
+ *
+ * INumber.format may be any printf-style appropriate for double
+ * or style "m" to create sexigesimal using the form "%<w>.<f>m" where
+ *   <w> is the total field width.
+ *   <f> is the width of the fraction. valid values are:
+ *      9  ->  :mm:ss.ss
+ *      8  ->  :mm:ss.s
+ *      6  ->  :mm:ss
+ *      5  ->  :mm.m
+ *      3  ->  :mm
+ *
+ * examples:
+ *
+ *   to produce     use
+ *
+ *    "-123:45"    %7.3m
+ *  "  0:01:02"    %9.6m
+ */
+
+/** \struct IText
+    \brief One text descriptor.
+*/
+typedef struct {		
+    /** index name */	
+    char name[MAXINDINAME];	
+    /** short description */
+    char label[MAXINDILABEL];		
+    /** malloced text string */
+    char *text;				
+    /** pointer to parent */
+    struct _ITextVectorProperty *tvp;	
+    /** handy place to hang helper info */
+    void *aux0;   			
+    /** handy place to hang helper info */
+    void *aux1;				
+} IText;
+
+/** \struct _ITextVectorProperty
+    \brief Text vector property descriptor.
+*/
+typedef struct _ITextVectorProperty {
+    /** device name */
+    char device[MAXINDIDEVICE];		
+    /** property name */
+    char name[MAXINDINAME];		
+    /** short description */
+    char label[MAXINDILABEL];		
+    /** GUI grouping hint */
+    char group[MAXINDIGROUP];		
+    /** client accessibility hint */
+    IPerm p;				
+    /** current max time to change, secs */
+    double timeout;			
+    /** current property state */
+    IPState s;				
+    /** texts comprising this vector */
+    IText *tp;				
+    /** dimension of tp[] */
+    int ntp;
+    /** ISO 8601 timestamp of this event */			
+    char timestamp[MAXINDITSTAMP];	
+    /** handy place to hang helper info */
+    void *aux;				
+} ITextVectorProperty;
+
+/** \struct INumber
+    \brief One number descriptor.
+*/
+typedef struct {
+    char name[MAXINDINAME];		/** index name */
+    char label[MAXINDILABEL];		/** short description */
+    char format[MAXINDIFORMAT];		/** GUI display format, see above */
+    double min, max;			/** range, ignore if min == max */
+    double step;			/** step size, ignore if step == 0 */
+    double value;			/** current value */
+    struct _INumberVectorProperty *nvp;	/** pointer to parent */
+    void *aux0, *aux1;			/** handy place to hang helper info */
+} INumber;
+
+/** \struct _INumberVectorProperty
+    \brief Number vector property descriptor.
+    
+    INumber.format may be any printf-style appropriate for double or style "m" to create sexigesimal using the form "%\<w\>.\<f\>m" where:\n
+    \<w\> is the total field width.\n
+    \<f\> is the width of the fraction. valid values are:\n
+        9  ->  \<w\>:mm:ss.ss \n
+        8  ->  \<w\>:mm:ss.s \n
+        6  ->  \<w\>:mm:ss \n
+        5  ->  \<w\>:mm.m \n
+        3  ->  \<w\>:mm \n
+	
+   examples:\n 
+ 
+   To produce "-123:45", use \%7.3m \n
+   To produce "  0:01:02", use \%9.6m 
+*/
+typedef struct _INumberVectorProperty {
+    /** device name */
+    char device[MAXINDIDEVICE];		
+    /** property name */
+    char name[MAXINDINAME];		
+    /** short description */
+    char label[MAXINDILABEL];		
+    /** GUI grouping hint */
+    char group[MAXINDIGROUP];		
+    /** client accessibility hint */
+    IPerm p;				
+    /** current max time to change, secs */
+    double timeout;			
+    /** current property state */
+    IPState s;				
+    /** numbers comprising this vector */
+    INumber *np;			
+    /** dimension of np[] */
+    int nnp;
+    /** ISO 8601 timestamp of this event */			
+    char timestamp[MAXINDITSTAMP];			
+    /** handy place to hang helper info */
+    void *aux;				
+} INumberVectorProperty;
+
+/** \struct ISwitch
+    \brief One switch descriptor.
+*/
+typedef struct {			
+    char name[MAXINDINAME];		/** index name */
+    char label[MAXINDILABEL];		/** this switch's label */
+    ISState s;				/** this switch's state */
+    struct _ISwitchVectorProperty *svp;	/** pointer to parent */
+    void *aux;				/** handy place to hang helper info */
+} ISwitch;
+
+/** \struct _ISwitchVectorProperty
+    \brief Switch vector property descriptor.
+*/
+typedef struct _ISwitchVectorProperty {
+    /** device name */
+    char device[MAXINDIDEVICE];		
+    /** property name */
+    char name[MAXINDINAME];		
+    /** short description */
+    char label[MAXINDILABEL];		
+    /** GUI grouping hint */
+    char group[MAXINDIGROUP];		
+    /** client accessibility hint */
+    IPerm p;				
+    /** switch behavior hint */
+    ISRule r;				
+    /** current max time to change, secs */
+    double timeout;			
+    /** current property state */
+    IPState s;				
+    /** switches comprising this vector */
+    ISwitch *sp;			
+    /** dimension of sp[] */
+    int nsp;
+    /** ISO 8601 timestamp of this event */			
+    char timestamp[MAXINDITSTAMP];
+    /** handy place to hang helper info */
+    void *aux;				
+} ISwitchVectorProperty;
+
+/** \struct ILight
+    \brief One light descriptor.
+*/
+typedef struct {			
+    char name[MAXINDINAME];		/** index name */
+    char label[MAXINDILABEL];		/** this lights's label */
+    IPState s;				/** this lights's state */
+    struct _ILightVectorProperty *lvp;	/** pointer to parent */
+    void *aux;				/** handy place to hang helper info */
+} ILight;
+
+/** \struct _ILightVectorProperty
+    \brief Light vector property descriptor.
+*/
+typedef struct _ILightVectorProperty {	
+    /** device name */
+    char device[MAXINDIDEVICE];		
+    /** property name */
+    char name[MAXINDINAME];		
+    /** short description */
+    char label[MAXINDILABEL];		
+    /** GUI grouping hint */
+    char group[MAXINDIGROUP];		
+    /** current property state */
+    IPState s;				
+    /** lights comprising this vector */
+    ILight *lp;				
+    /** dimension of lp[] */
+    int nlp;
+    /** ISO 8601 timestamp of this event */			
+    char timestamp[MAXINDITSTAMP];	
+    /** handy place to hang helper info */
+    void *aux;				
+} ILightVectorProperty;
+
+/** \struct IBLOB
+    \brief One Blob (Binary Large Object) descriptor.
+ */
+typedef struct {			/* one BLOB descriptor */
+  /** index name */
+  char name[MAXINDINAME];		
+  /** this BLOB's label */
+  char label[MAXINDILABEL];	
+  /** format attr */	
+  char format[MAXINDIBLOBFMT];	
+  /** malloced binary large object bytes */
+  void *blob;			
+  /** bytes in blob */	
+  int bloblen;			
+  /** n uncompressed bytes */
+  int size;				
+  /** pointer to parent */
+  struct _IBLOBVectorProperty *bvp;	
+  /** handy place to hang helper info */
+  void *aux0, *aux1, *aux2;		
+} IBLOB;
+
+/** \struct _IBLOBVectorProperty
+    \brief BLOB (Binary Large Object) vector property descriptor.
+ */
+
+typedef struct _IBLOBVectorProperty {	/* BLOB vector property descriptor */
+  /** device name */
+  char device[MAXINDIDEVICE];		
+  /** property name */
+  char name[MAXINDINAME];		
+  /** short description */
+  char label[MAXINDILABEL];		
+  /** GUI grouping hint */
+  char group[MAXINDIGROUP];		
+  /** client accessibility hint */
+  IPerm p;				
+  /** current max time to change, secs */
+  double timeout;			
+  /** current property state */
+  IPState s;				
+  /** BLOBs comprising this vector */
+  IBLOB *bp;				
+  /** dimension of bp[] */
+  int nbp;				
+  /** ISO 8601 timestamp of this event */
+  char timestamp[MAXINDITSTAMP];	
+  /** handy place to hang helper info */
+  void *aux;				
+} IBLOBVectorProperty;
+
+
+/** \brief Handy macro to find the number of elements in array a[]. Must be used with actual array, not pointer.
+*/
+#define NARRAY(a)       (sizeof(a)/sizeof(a[0]))
+
+#endif
Index: /BAORadio/libindi/v1/indidevapi.h
===================================================================
--- /BAORadio/libindi/v1/indidevapi.h	(revision 500)
+++ /BAORadio/libindi/v1/indidevapi.h	(revision 500)
@@ -0,0 +1,712 @@
+#if 0
+    INDI
+    Copyright (C) 2003-2006 Elwood C. Downey
+
+			Modified by Jasem Mutlaq (2003-2006)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+#ifndef INDI_DEVAPI_H
+#define INDI_DEVAPI_H
+
+/** \file indidevapi.h
+    \brief Interface to the reference INDI C API device implementation on the Device Driver side.
+    \author Elwood C. Downey
+    \author Jasem Mutlaq
+     
+     This file is divided into two main sections:\n
+     <ol><li> Functions the INDI device driver framework defines which the Driver may
+     call:</li>
+ 
+      <ul><li>IDxxx functions to send messages to an INDI client.</li>
+      <li>IExxx functions to implement the event driven model.</li>
+      <li>IUxxx functions to perform handy utility functions.</li></ul>
+ 
+     <li>Functions the INDI device driver framework calls which the Driver must
+    define:</li>
+ 
+     <ul><li>ISxxx to respond to messages from a Client.</li></ul></ol>
+
+<p>These functions are the interface to the INDI C-language Device Driver
+reference implementation library. Any driver that uses this interface is
+expected to #include "indidevapi.h" and to link with indidrivermain.o and
+eventloop.o. Indidevapi.h further includes indiapi.h. The former contains
+the prototypes for the functions documented here, although many functions
+take arguments defined in the latter.</p>
+
+<p>These functions make it much easier to write a compliant INDI driver than
+starting from scratch, and also serve as a concrete
+example of the interactions an INDI driver, in any language, is expected to
+accommodate.</p>
+
+<p>The reference driver framework and the optimizations made within the reference
+indiserver both assume and require that one driver program implements exactly
+one logical INDI device.</p>
+
+<p>The functions in this framework fall into two broad categories. Some are
+functions that a driver must define because they are called by the reference
+framework; these functions begin with IS. The remaining functions are library
+utilities a driver may use to do important operations.</p>
+
+<p>A major point to realize is that an INDI driver built with this framework
+does not contain the C main() function. As soon as a driver begins executing,
+it listens on stdin for INDI messages. Only when a valid and appropriate
+message is received will it then call the driver via one of the IS functions.
+The driver is then expected to respond promptly by calling one of the ID
+library functions. It may also use any of the IU utility functions as desired
+to make processing a message easier.</p>
+
+<p>Rather separate from these IS, ID and IU functions are a collection of
+functions that utilize the notion of a callback. In a callback design,
+the driver registers a function with the framework to be called under
+certain circumstances. When said circumstances occur, the framework will
+call the callback function. The driver never calls these callbacks directly.
+These callback functions begin with IE. They can arrange for a callback
+function to be called under three kinds of circumstances: when a given file
+descriptor may be read without blocking (because either data is available
+or EOF has been encountered), when a given time interval has elapsed, or
+when the framework has nothing urgent to do. The callback functions for each
+circumstance must be written according to a well defined prototype since,
+after all, the framework must know how to call the callback correctlty.</p>
+
+*/
+ 
+
+/*******************************************************************************
+ * get the data structures
+ */
+
+#include "indiapi.h"
+#include "lilxml.h"
+
+/*******************************************************************************
+ *******************************************************************************
+ *
+ *  Functions the INDI device driver framework defines which the Driver may call
+ *
+ *******************************************************************************
+ *******************************************************************************
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \defgroup d2cFunctions IDDef Functions: Functions drivers call to define their properties to clients.
+
+<p>Each of the following functions creates the appropriate XML formatted
+INDI message from its arguments and writes it to stdout. From there, is it
+typically read by indiserver which then sends it to the clients that have
+expressed interest in messages from the Device indicated in the message.</p>
+
+<p>In addition to type-specific arguments, all end with a printf-style format
+string, and appropriate subsequent arguments, that form the \param msg
+attribute within the INDI message. If the format argument is NULL, no message
+attribute is included with the message. Note that a \e timestamp 
+attribute is also always added automatically based on the clock on the 
+computer on which this driver is running.</p>
+
+*/
+
+
+/*@{*/
+
+/** \brief Tell client to create a text vector property.
+    \param t pointer to the vector text property to be defined.
+    \param msg message in printf style to send to the client. May be NULL.
+*/
+extern void IDDefText (const ITextVectorProperty *t, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Tell client to create a number number property.
+    \param n pointer to the vector number property to be defined.
+    \param msg message in printf style to send to the client. May be NULL.
+*/
+extern void IDDefNumber (const INumberVectorProperty *n, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Tell client to create a switch vector property.
+    \param s pointer to the vector switch property to be defined.
+    \param msg message in printf style to send to the client. May be NULL.
+*/
+extern void IDDefSwitch (const ISwitchVectorProperty *s, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Tell client to create a light vector property.
+    \param l pointer to the vector light property to be defined.
+    \param msg message in printf style to send to the client. May be NULL.
+*/
+extern void IDDefLight (const ILightVectorProperty *l, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Tell client to create a BLOB vector property.
+    \param b pointer to the vector BLOB property to be defined.
+    \param msg message in printf style to send to the client. May be NULL.
+ */
+extern void IDDefBLOB (const IBLOBVectorProperty *b, const char *msg, ...)
+#ifdef __GNUC__
+    __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+
+/*@}*/
+
+/**
+ * \defgroup d2cuFunctions IDSet Functions: Functions drivers call to tell clients of new values for existing properties.
+ */
+/*@{*/
+
+/** \brief Tell client to update an existing text vector property.
+    \param t pointer to the vector text property.
+    \param msg message in printf style to send to the client. May be NULL.
+*/
+extern void IDSetText (const ITextVectorProperty *t, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Tell client to update an existing number vector property.
+    \param n pointer to the vector number property.
+    \param msg message in printf style to send to the client. May be NULL.
+*/
+extern void IDSetNumber (const INumberVectorProperty *n, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Tell client to update an existing switch vector property.
+    \param s pointer to the vector switch property.
+    \param msg message in printf style to send to the client. May be NULL.
+*/
+extern void IDSetSwitch (const ISwitchVectorProperty *s, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Tell client to update an existing light vector property.
+    \param l pointer to the vector light property.
+    \param msg message in printf style to send to the client. May be NULL.
+*/
+extern void IDSetLight (const ILightVectorProperty *l, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Tell client to update an existing BLOB vector property.
+    \param b pointer to the vector BLOB property.
+    \param msg message in printf style to send to the client. May be NULL.
+ */
+extern void IDSetBLOB (const IBLOBVectorProperty *b, const char *msg, ...)
+#ifdef __GNUC__
+    __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/*@}*/
+
+/**
+ * \defgroup d2duFunctions ID Functions: Functions to delete properties, and log messages locally or remotely.
+ */
+/*@{*/
+
+
+/** \brief Function Drivers call to send log messages to Clients.
+ 
+    If dev is specified the Client shall associate the message with that device; if dev is NULL the Client shall treat the message as generic from no specific Device.
+    
+    \param dev device name
+    \param msg message in printf style to send to the client.
+*/
+extern void IDMessage (const char *dev, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 2, 3 ) ) )
+#endif
+;
+
+/** \brief Function Drivers call to inform Clients a Property is no longer available, or the entire device is gone if name is NULL.
+
+    \param dev device name. If device name is NULL, the entire device will be deleted.
+    \param name property name to be deleted.
+    \param msg message in printf style to send to the client.
+*/
+extern void IDDelete (const char *dev, const char *name, const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 3, 4 ) ) )
+#endif
+;
+
+/** \brief Function Drivers call to log a message locally.
+ 
+    The message is not sent to any Clients.
+    
+    \param msg message in printf style to send to the client.
+*/
+extern void IDLog (const char *msg, ...)
+#ifdef __GNUC__
+        __attribute__ ( ( format( printf, 1, 2 ) ) )
+#endif
+;
+
+/*@}*/
+
+/**
+ * \defgroup snoopFunctions ISnoop Functions: Functions drivers call to snoop on other drivers.
+ 
+ */
+/*@{*/
+
+
+/** \typedef BLOBHandling
+    \brief How drivers handle BLOBs incoming from snooping drivers */
+typedef enum 
+{
+  B_NEVER=0,	/*!< Never receive BLOBs */
+  B_ALSO,	/*!< Receive BLOBs along with normal messages */
+  B_ONLY	/*!< ONLY receive BLOBs from drivers, ignore all other traffic */
+} BLOBHandling;
+
+/** \brief Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevice.
+    \param snooped_device name of the device to snoop.
+    \param snooped_property name of the snooped property in the device.
+*/
+extern void IDSnoopDevice (const char *snooped_device, char *snooped_property);
+
+/** \brief Function a Driver calls to control whether they will receive BLOBs from snooped devices.
+    \param snooped_device_name name of the device to snoop.
+    \param bh How drivers handle BLOBs incoming from snooping drivers.
+*/
+extern void IDSnoopBLOBs (const char *snooped_device, BLOBHandling bh);
+
+/*@}*/
+
+/**
+ * \defgroup deventFunctions IE Functions: Functions drivers call to register with the INDI event utilities.
+ 
+     Callbacks are called when a read on a file descriptor will not block. Timers are called once after a specified interval. Workprocs are called when there is nothing else to do. The "Add" functions return a unique id for use with their corresponding "Rm" removal function. An arbitrary pointer may be specified when a function is registered which will be stored and forwarded unchanged when the function is later invoked.
+ */
+/*@{*/
+     
+ /* signature of a callback, timout caller and work procedure function */
+
+/** \typedef IE_CBF
+    \brief Signature of a callback. */
+typedef void (IE_CBF) (int readfiledes, void *userpointer);
+
+/** \typedef IE_TCF
+    \brief Signature of a timeout caller. */
+typedef void (IE_TCF) (void *userpointer);
+
+/** \typedef IE_WPF
+    \brief Signature of a work procedure function. */
+typedef void (IE_WPF) (void *userpointer);
+
+/* functions to add and remove callbacks, timers and work procedures */
+
+/** \brief Register a new callback, \e fp, to be called with \e userpointer as argument when \e readfiledes is ready.
+*
+* \param readfiledes file descriptor.
+* \param fp a pointer to the callback function.
+* \param userpointer a pointer to be passed to the callback function when called.
+* \return a unique callback id for use with IERmCallback().
+*/
+extern int  IEAddCallback (int readfiledes, IE_CBF *fp, void *userpointer);
+
+/** \brief Remove a callback function.
+*
+* \param callbackid the callback ID returned from IEAddCallback()
+*/
+extern void IERmCallback (int callbackid);
+
+/** \brief Register a new timer function, \e fp, to be called with \e ud as argument after \e ms.
+ 
+ Add to list in order of decreasing time from epoch, ie, last entry runs soonest. The timer will only invoke the callback function \b once. You need to call addTimer again if you want to repeat the process.
+*
+* \param millisecs timer period in milliseconds.
+* \param fp a pointer to the callback function.
+* \param userpointer a pointer to be passed to the callback function when called.
+* \return a unique id for use with IERmTimer().
+*/
+extern int  IEAddTimer (int millisecs, IE_TCF *fp, void *userpointer);
+
+/** \brief Remove the timer with the given \e timerid, as returned from IEAddTimer.
+*
+* \param timerid the timer callback ID returned from IEAddTimer().
+*/
+extern void IERmTimer (int timerid);
+
+/** \brief Add a new work procedure, fp, to be called with ud when nothing else to do.
+*
+* \param fp a pointer to the work procedure callback function.
+* \param userpointer a pointer to be passed to the callback function when called.
+* \return a unique id for use with IERmWorkProc().
+*/
+extern int  IEAddWorkProc (IE_WPF *fp, void *userpointer);
+
+/** \brief Remove a work procedure.
+*
+* \param workprocid The unique ID for the work procedure to be removed.
+*/
+extern void IERmWorkProc (int workprocid);
+
+/* wait in-line for a flag to set, presumably by another event function */
+
+extern int IEDeferLoop (int maxms, int *flagp);
+extern int IEDeferLoop0 (int maxms, int *flagp);
+
+/*@}*/
+
+/**
+ * \defgroup dutilFunctions IU Functions: Functions drivers call to perform handy utility routines.
+
+<p>This section describes handy utility functions that are provided by the
+framework for tasks commonly required in the processing of client
+messages. It is not strictly necessary to use these functions, but it
+both prudent and efficient to do so.</P>
+
+<p>These do not communicate with the Client in any way.</p>
+ */
+/*@{*/
+
+
+/** \brief Find an IText member in a vector text property.
+*
+* \param tp a pointer to a text vector property.
+* \param name the name of the member to search for.
+* \return a pointer to an IText member on match, or NULL if nothing is found.
+*/
+extern IText   *IUFindText  (const ITextVectorProperty *tp, const char *name);
+
+/** \brief Find an INumber member in a number text property.
+*
+* \param tp a pointer to a number vector property.
+* \param name the name of the member to search for.
+* \return a pointer to an INumber member on match, or NULL if nothing is found.
+*/
+extern INumber *IUFindNumber(const INumberVectorProperty *tp, const char *name);
+
+/** \brief Find an ISwitch member in a vector switch property.
+*
+* \param tp a pointer to a switch vector property.
+* \param name the name of the member to search for.
+* \return a pointer to an ISwitch member on match, or NULL if nothing is found.
+*/
+extern ISwitch *IUFindSwitch(const ISwitchVectorProperty *tp, const char *name);
+
+/** \brief Returns the first ON switch it finds in the vector switch property.
+
+*   \note This is only valid for ISR_1OFMANY mode. That is, when only one switch out of many is allowed to be ON. Do not use this function if you can have multiple ON switches in the same vector property.
+*        
+* \param tp a pointer to a switch vector property.
+* \return a pointer to the \e first ON ISwitch member if found. If all switches are off, NULL is returned. 
+*/
+extern ISwitch *IUFindOnSwitch (const ISwitchVectorProperty *tp);
+
+/** \brief Reset all switches in a switch vector property to OFF.
+*
+* \param svp a pointer to a switch vector property.
+*/
+extern void IUResetSwitch(ISwitchVectorProperty *svp);
+
+/** \brief Update all switches in a switch vector property.
+*
+* \param svp a pointer to a switch vector property.
+* \param states the states of the new ISwitch members.
+* \param names the names of the ISwtich members to update.
+* \param n the number of ISwitch members to update.
+* \return 0 if update successful, -1 otherwise.
+*/
+extern int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n);
+
+/** \brief Update all numbers in a number vector property.
+*
+* \param nvp a pointer to a number vector property.
+* \param values the states of the new INumber members.
+* \param names the names of the INumber members to update.
+* \param n the number of INumber members to update.
+* \return 0 if update successful, -1 otherwise. Update will fail if values are out of scope, or in case of property name mismatch.
+*/
+extern int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n);
+
+/** \brief Update all text members in a text vector property.
+*
+* \param tvp a pointer to a text vector property.
+* \param texts a pointer to the text members
+* \param names the names of the IText members to update.
+* \param n the number of IText members to update.
+* \return 0 if update successful, -1 otherwise. Update will fail in case of property name mismatch.
+*/
+extern int IUUpdateText(ITextVectorProperty *tvp, char * texts[], char *names[], int n);
+
+/** \brief Function to update the min and max elements of a number in the client
+    \param nvp pointer to an INumberVectorProperty.
+ */
+extern void IUUpdateMinMax(const INumberVectorProperty *nvp);
+
+/** \brief Function to reliably save new text in a IText.
+    \param tp pointer to an IText member.
+    \param newtext the new text to be saved     
+*/
+extern void IUSaveText (IText *tp, const char *newtext);
+
+/** \brief Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
+    \param sp pointer a switch property to fill
+    \param name the switch name
+    \param label the switch label
+    \param s the switch state (ISS_ON or ISS_OFF)
+*/
+extern void IUFillSwitch(ISwitch *sp, const char *name, const char * label, ISState s);
+
+/** \brief Assign attributes for a light property. The light's auxiliary elements will be set to NULL.
+    \param lp pointer a light property to fill
+    \param name the light name
+    \param label the light label
+    \param s the light state (IDLE, WARNING, OK, ALERT)
+*/
+extern void IUFillLight(ILight *lp, const char *name, const char * label, IPState s);
+
+/** \brief Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
+    \param np pointer a number property to fill
+    \param name the number name
+    \param label the number label
+    \param format the number format in printf style (e.g. "%02d")
+    \param min  the minimum possible value
+    \param max the maximum possible value
+    \param step the step used to climb from minimum value to maximum value
+    \param value the number's current value
+*/
+extern void IUFillNumber(INumber *np, const char *name, const char * label, const char *format, double min, double max, double step, double value);
+
+/** \brief Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
+    \param tp pointer a text property to fill
+    \param name the text name
+    \param label the text label
+    \param initialText the initial text
+*/
+extern void IUFillText(IText *tp, const char *name, const char * label, const char *initialText);
+
+
+/** \brief Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
+    \param svp pointer a switch vector property to fill
+    \param sp pointer to an array of switches
+    \param nsp the dimension of sp
+    \param dev the device name this vector property belongs to
+    \param name the vector property name
+    \param label the vector property label
+    \param group the vector property group
+    \param p the vector property permission
+    \param r the switches behavior
+    \param timeout vector property timeout in seconds 
+    \param s the vector property initial state.
+*/
+extern void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char * dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s);
+
+/** \brief Assign attributes for a light vector property. The vector's auxiliary elements will be set to NULL.
+    \param lvp pointer a light vector property to fill
+    \param lp pointer to an array of lights
+    \param nlp the dimension of lp
+    \param dev the device name this vector property belongs to
+    \param name the vector property name
+    \param label the vector property label
+    \param group the vector property group
+    \param s the vector property initial state.
+*/
+extern void IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char * dev, const char *name, const char *label, const char *group, IPState s);
+
+/** \brief Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
+    \param nvp pointer a number vector property to fill
+    \param np pointer to an array of numbers
+    \param nnp the dimension of np
+    \param dev the device name this vector property belongs to
+    \param name the vector property name
+    \param label the vector property label
+    \param group the vector property group
+    \param p the vector property permission
+    \param timeout vector property timeout in seconds 
+    \param s the vector property initial state.
+*/
+extern void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s);
+
+/** \brief Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
+    \param tvp pointer a text vector property to fill
+    \param tp pointer to an array of texts
+    \param ntp the dimension of tp
+    \param dev the device name this vector property belongs to
+    \param name the vector property name
+    \param label the vector property label
+    \param group the vector property group
+    \param p the vector property permission
+    \param timeout vector property timeout in seconds 
+    \param s the vector property initial state.
+*/
+extern void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s);
+
+/** \brief Update a snooped number vector property from the given XML root element.
+    \param root XML root elememnt containing the snopped property content
+    \param nvp a pointer to the number vector property to be updated.
+    \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble.
+*/
+extern int IUSnoopNumber (XMLEle *root, INumberVectorProperty *nvp);
+
+/** \brief Update a snooped text vector property from the given XML root element.
+    \param root XML root elememnt containing the snopped property content
+    \param tvp a pointer to the text vector property to be updated.
+    \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble.
+*/
+extern int IUSnoopText (XMLEle *root, ITextVectorProperty *tvp);
+
+/** \brief Update a snooped light vector property from the given XML root element.
+    \param root XML root elememnt containing the snopped property content
+    \param lvp a pointer to the light vector property to be updated.
+    \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble.
+*/
+extern int IUSnoopLight (XMLEle *root, ILightVectorProperty *lvp);
+
+/** \brief Update a snooped switch vector property from the given XML root element.
+    \param root XML root elememnt containing the snopped property content
+    \param svp a pointer to the switch vector property to be updated.
+    \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble.
+*/
+extern int IUSnoopSwitch (XMLEle *root, ISwitchVectorProperty *svp);
+
+/** \brief Update a snooped BLOB vector property from the given XML root element.
+    \param root XML root elememnt containing the snopped property content
+    \param bvp a pointer to the BLOB vector property to be updated.
+    \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble.
+*/
+extern int IUSnoopBLOB (XMLEle *root, IBLOBVectorProperty *bvp);
+
+/*@}*/
+
+/*******************************************************************************
+ *******************************************************************************
+ *
+ *   Functions the INDI Device Driver framework calls which the Driver must
+ *   define.
+ *
+ *******************************************************************************
+ *******************************************************************************
+ */
+
+
+
+/**
+ * \defgroup dcuFunctions IS Functions: Functions all drivers must define.
+ 
+This section defines functions that must be defined in each driver. These
+functions are never called by the driver, but are called by the driver
+framework. These must always be defined even if they do nothing.
+*/
+/*@{*/
+
+/** \brief Get Device Properties
+    \param dev the name of the device.
+
+This function is called by the framework whenever the driver has received a
+getProperties message from an INDI client. The argument \param dev is either a
+string containing the name of the device specified within the message, or NULL
+if no device was specified. If the driver does not recognize the device, it
+should ignore the message and do nothing. If dev matches the device the driver
+is implementing, or dev is NULL, the driver must respond by sending one defXXX
+message to describe each property defined by this device, including its
+current (or initial) value. The recommended way to send these messages is to
+call the appropriate IDDef functions.
+*/  
+extern void ISGetProperties (const char *dev);
+
+
+/** \brief Update the value of an existing text vector property.
+    \param dev the name of the device.
+    \param name the name of the text vector property to update.
+    \param texts an array of text values.
+    \param names parallel names to the array of text values.
+    \param n the dimension of texts[].
+    \note You do not need to call this function, it is called by INDI when new text values arrive from the client.
+*/
+extern void ISNewText (const char *dev, const char *name, char *texts[],
+    char *names[], int n); 
+
+/** \brief Update the value of an existing number vector property.
+    \param dev the name of the device.
+    \param name the name of the number vector property to update.
+    \param doubles an array of number values.
+    \param names parallel names to the array of number values.
+    \param n the dimension of doubles[].
+    \note You do not need to call this function, it is called by INDI when new number values arrive from the client.
+*/
+extern void ISNewNumber (const char *dev, const char *name, double *doubles,
+    char *names[], int n); 
+
+/** \brief Update the value of an existing switch vector property.
+    \param dev the name of the device.
+    \param name the name of the switch vector property to update.
+    \param states an array of switch states.
+    \param names parallel names to the array of switch states.
+    \param n the dimension of states[].
+    \note You do not need to call this function, it is called by INDI when new switch values arrive from the client.
+*/
+extern void ISNewSwitch (const char *dev, const char *name, ISState *states,
+    char *names[], int n); 
+
+/** \brief Update data of an existing blob vector property.
+    \param dev the name of the device.
+    \param name the name of the blob vector property to update.
+    \param sizes an array of base64 blob sizes in bytes \e before decoding.
+    \param blobsizes an array of the sizes of blobs \e after decoding from base64.
+    \param blobs an array of decoded data. Each blob size is found in \e blobsizes array.
+    \param formats Blob data format (e.g. fits.z).
+    \param names names of blob members to update. 
+    \param n the number of blobs to update.
+    \note You do not need to call this function, it is called by INDI when new blob values arrive from the client.
+          e.g. BLOB element with name names[0] has data located in blobs[0] with size sizes[0] and format formats[0].
+*/
+
+extern void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n); 
+
+/** \brief Function defined by Drivers that is called when another Driver it is snooping (by having previously called IDSnoopDevice()) sent any INDI message.
+    \param root The argument contains the full message exactly as it was sent by the driver.
+    \e Hint: use the IUSnoopXXX utility functions to help crack the message if it was one of setXXX or defXXX.
+*/
+extern void ISSnoopDevice (XMLEle *root);
+
+/*@}*/
+
+/* Handy readability macro to avoid unused variables warnings */
+#define INDI_UNUSED(x) (void) x
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /BAORadio/libindi/v1/indidrivermain.c
===================================================================
--- /BAORadio/libindi/v1/indidrivermain.c	(revision 500)
+++ /BAORadio/libindi/v1/indidrivermain.c	(revision 500)
@@ -0,0 +1,1690 @@
+#if 0
+    INDI
+    Copyright (C) 2003-2006 Elwood C. Downey
+
+			Modified by Jasem Mutlaq (2003-2006)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+/* main() for one INDI driver process.
+ * Drivers define IS*() functions we call to deliver INDI XML arriving on stdin.
+ * Drivers call ID*() functions to send INDI XML commands to stdout.
+ * Drivers call IE*() functions to build an event-driver program.
+ * Drivers call IU*() functions to perform various common utility tasks.
+ * Troubles are reported on stderr then we exit.
+ *
+ * This requires liblilxml.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "lilxml.h"
+#include "base64.h"
+#include "eventloop.h"
+#include "indidevapi.h"
+#include "indicom.h"
+
+static void usage(void);
+static void clientMsgCB(int fd, void *arg);
+static int dispatch (XMLEle *root, char msg[]);
+static int crackDN (XMLEle *root, char **dev, char **name, char msg[]);
+static int isPropDefined(const char *property_name);
+static int crackIPState (const char *str, IPState *ip);
+static int crackISState (const char *str, ISState *ip);
+static void xmlv1(void);
+const char *pstateStr(IPState s);
+const char *sstateStr(ISState s);
+const char *ruleStr(ISRule r);
+const char *permStr(IPerm p);
+
+
+static int nroCheck;			/* # of elements in roCheck */
+static int verbose;			/* chatty */
+char *me;				/* a.out name */
+static LilXML *clixml;			/* XML parser context */
+
+/* insure RO properties are never modified. RO Sanity Check */
+typedef struct
+{
+  char propName[MAXINDINAME];
+  IPerm perm;
+} ROSC;
+
+static ROSC *roCheck;
+
+int
+main (int ac, char *av[])
+{
+#ifndef _WIN32
+        setgid( getgid() );
+        setuid( getuid() );
+
+	if (geteuid() != getuid())
+            exit(255);
+#endif
+
+	/* save handy pointer to our base name */
+	for (me = av[0]; av[0][0]; av[0]++)
+	    if (av[0][0] == '/')
+		me = &av[0][1];
+
+	/* crack args */
+	while (--ac && (*++av)[0] == '-')
+	    while (*++(*av))
+		switch (*(*av)) {
+		case 'v':	/* verbose */
+		    verbose++;
+		    break;
+		default:
+		    usage();
+		}
+
+	/* ac remaining args starting at av[0] */
+	if (ac > 0)
+	    usage();
+
+	/* init */
+	clixml =  newLilXML();
+	addCallback (0, clientMsgCB, NULL);
+	
+	nroCheck = 0;
+	roCheck = NULL;
+
+	/* service client */
+	eventLoop();
+
+	/* eh?? */
+	fprintf (stderr, "%s: inf loop ended\n", me);
+	return (1);
+}
+
+/* Return 1 is property is already cached, 0 otherwise */
+static int isPropDefined(const char *property_name)
+{
+  int i=0;
+  
+  for (i=0; i < nroCheck; i++)
+    if (!strcmp(property_name, roCheck[i].propName))
+	return 1;
+
+  return 0;
+
+}
+
+/* functions we define that drivers may call */
+
+/* tell client to create a text vector property */
+void
+IDDefText (const ITextVectorProperty *tvp, const char *fmt, ...)
+{
+	int i;
+	ROSC *SC;
+
+	xmlv1();
+	printf ("<defTextVector\n");
+	printf ("  device='%s'\n", tvp->device);
+	printf ("  name='%s'\n", tvp->name);
+	printf ("  label='%s'\n", tvp->label);
+	printf ("  group='%s'\n", tvp->group);
+	printf ("  state='%s'\n", pstateStr(tvp->s));
+	printf ("  perm='%s'\n", permStr(tvp->p));
+	printf ("  timeout='%g'\n", tvp->timeout);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < tvp->ntp; i++) {
+	    IText *tp = &tvp->tp[i];
+	    printf ("  <defText\n");
+	    printf ("    name='%s'\n", tp->name);
+	    printf ("    label='%s'>\n", tp->label);
+	    printf ("      %s\n", tp->text ? tp->text : "");
+	    printf ("  </defText>\n");
+	}
+
+	printf ("</defTextVector>\n");
+
+	if (!isPropDefined(tvp->name))
+	{	
+		/* Add this property to insure proper sanity check */
+		roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
+	                  	: (ROSC *) malloc  ( sizeof(ROSC));
+		SC      = &roCheck[nroCheck++];
+	
+		strcpy(SC->propName, tvp->name);
+		SC->perm = tvp->p;
+	}
+	
+	fflush (stdout);
+}
+
+/* tell client to create a new numeric vector property */
+void
+IDDefNumber (const INumberVectorProperty *n, const char *fmt, ...)
+{
+	int i;
+	ROSC *SC;
+
+	xmlv1();
+	printf ("<defNumberVector\n");
+	printf ("  device='%s'\n", n->device);
+	printf ("  name='%s'\n", n->name);
+	printf ("  label='%s'\n", n->label);
+	printf ("  group='%s'\n", n->group);
+	printf ("  state='%s'\n", pstateStr(n->s));
+	printf ("  perm='%s'\n", permStr(n->p));
+	printf ("  timeout='%g'\n", n->timeout);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < n->nnp; i++) {
+	    INumber *np = &n->np[i];
+	    printf ("  <defNumber\n");
+	    printf ("    name='%s'\n", np->name);
+	    printf ("    label='%s'\n", np->label);
+	    printf ("    format='%s'\n", np->format);
+	    printf ("    min='%.20g'\n", np->min);
+	    printf ("    max='%.20g'\n", np->max);
+	    printf ("    step='%.20g'>\n", np->step);
+	    printf ("      %.20g\n", np->value);
+	    printf ("  </defNumber>\n");
+	}
+
+	printf ("</defNumberVector>\n");
+	
+	if (!isPropDefined(n->name))
+	{	
+		/* Add this property to insure proper sanity check */
+		roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
+	                  	: (ROSC *) malloc  ( sizeof(ROSC));
+		SC      = &roCheck[nroCheck++];
+	
+		strcpy(SC->propName, n->name);
+		SC->perm = n->p;
+
+	}
+	
+	fflush (stdout);
+}
+
+/* tell client to create a new switch vector property */
+void
+IDDefSwitch (const ISwitchVectorProperty *s, const char *fmt, ...)
+
+{
+	int i;
+	ROSC *SC;
+
+	xmlv1();
+	printf ("<defSwitchVector\n");
+	printf ("  device='%s'\n", s->device);
+	printf ("  name='%s'\n", s->name);
+	printf ("  label='%s'\n", s->label);
+	printf ("  group='%s'\n", s->group);
+	printf ("  state='%s'\n", pstateStr(s->s));
+	printf ("  perm='%s'\n", permStr(s->p));
+	printf ("  rule='%s'\n", ruleStr (s->r));
+	printf ("  timeout='%g'\n", s->timeout);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < s->nsp; i++) {
+	    ISwitch *sp = &s->sp[i];
+	    printf ("  <defSwitch\n");
+	    printf ("    name='%s'\n", sp->name);
+	    printf ("    label='%s'>\n", sp->label);
+	    printf ("      %s\n", sstateStr(sp->s));
+	    printf ("  </defSwitch>\n");
+	}
+
+	printf ("</defSwitchVector>\n");
+	
+	if (!isPropDefined(s->name))
+	{	
+		/* Add this property to insure proper sanity check */
+		roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
+	                  	: (ROSC *) malloc  ( sizeof(ROSC));
+		SC      = &roCheck[nroCheck++];
+	
+		strcpy(SC->propName, s->name);
+		SC->perm = s->p;
+	}
+	
+	fflush (stdout);
+}
+
+/* tell client to create a new lights vector property */
+void
+IDDefLight (const ILightVectorProperty *lvp, const char *fmt, ...)
+{
+	int i;
+
+	xmlv1();
+	printf ("<defLightVector\n");
+	printf ("  device='%s'\n", lvp->device);
+	printf ("  name='%s'\n", lvp->name);
+	printf ("  label='%s'\n", lvp->label);
+	printf ("  group='%s'\n", lvp->group);
+	printf ("  state='%s'\n", pstateStr(lvp->s));
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < lvp->nlp; i++) {
+	    ILight *lp = &lvp->lp[i];
+	    printf ("  <defLight\n");
+	    printf ("    name='%s'\n", lp->name);
+	    printf ("    label='%s'>\n", lp->label);
+	    printf ("      %s\n", pstateStr(lp->s));
+	    printf ("  </defLight>\n");
+	}
+
+	printf ("</defLightVector>\n");
+	fflush (stdout);
+}
+
+/* tell client to create a new BLOB vector property */
+void
+IDDefBLOB (const IBLOBVectorProperty *b, const char *fmt, ...)
+{
+  int i;
+  ROSC *SC;
+
+	xmlv1();
+	printf ("<defBLOBVector\n");
+	printf ("  device='%s'\n", b->device);
+	printf ("  name='%s'\n", b->name);
+	printf ("  label='%s'\n", b->label);
+	printf ("  group='%s'\n", b->group);
+	printf ("  state='%s'\n", pstateStr(b->s));
+	printf ("  perm='%s'\n", permStr(b->p));
+	printf ("  timeout='%g'\n", b->timeout);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+  for (i = 0; i < b->nbp; i++) {
+    IBLOB *bp = &b->bp[i];
+    printf ("  <defBLOB\n");
+    printf ("    name='%s'\n", bp->name);
+    printf ("    label='%s'\n", bp->label);
+    printf ("  />\n");
+  }
+
+	printf ("</defBLOBVector>\n");
+
+	if (!isPropDefined(b->name))
+	{	
+		/* Add this property to insure proper sanity check */
+		roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1))
+	                  	: (ROSC *) malloc  ( sizeof(ROSC));
+		SC      = &roCheck[nroCheck++];
+	
+		strcpy(SC->propName, b->name);
+		SC->perm = b->p;
+	}
+
+	fflush (stdout);
+}
+
+/* tell client to update an existing text vector property */
+void
+IDSetText (const ITextVectorProperty *tvp, const char *fmt, ...)
+{
+	int i;
+
+	xmlv1();
+	printf ("<setTextVector\n");
+	printf ("  device='%s'\n", tvp->device);
+	printf ("  name='%s'\n", tvp->name);
+	printf ("  state='%s'\n", pstateStr(tvp->s));
+	printf ("  timeout='%g'\n", tvp->timeout);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < tvp->ntp; i++) {
+	    IText *tp = &tvp->tp[i];
+	    printf ("  <oneText name='%s'>\n", tp->name);
+	    printf ("      %s\n", tp->text ? tp->text : "");
+	    printf ("  </oneText>\n");
+	}
+
+	printf ("</setTextVector>\n");
+	fflush (stdout);
+}
+
+/* tell client to update an existing numeric vector property */
+void
+IDSetNumber (const INumberVectorProperty *nvp, const char *fmt, ...)
+{
+	int i;
+
+	xmlv1();
+	printf ("<setNumberVector\n");
+	printf ("  device='%s'\n", nvp->device);
+	printf ("  name='%s'\n", nvp->name);
+	printf ("  state='%s'\n", pstateStr(nvp->s));
+	printf ("  timeout='%g'\n", nvp->timeout);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < nvp->nnp; i++) {
+	    INumber *np = &nvp->np[i];
+	    printf ("  <oneNumber name='%s'>\n", np->name);
+	    printf ("      %.20g\n", np->value);
+	    printf ("  </oneNumber>\n");
+	}
+
+	printf ("</setNumberVector>\n");
+	fflush (stdout);
+}
+
+/* tell client to update an existing switch vector property */
+void
+IDSetSwitch (const ISwitchVectorProperty *svp, const char *fmt, ...)
+{
+	int i;
+
+	xmlv1();
+	printf ("<setSwitchVector\n");
+	printf ("  device='%s'\n", svp->device);
+	printf ("  name='%s'\n", svp->name);
+	printf ("  state='%s'\n", pstateStr(svp->s));
+	printf ("  timeout='%g'\n", svp->timeout);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < svp->nsp; i++) {
+	    ISwitch *sp = &svp->sp[i];
+	    printf ("  <oneSwitch name='%s'>\n", sp->name);
+	    printf ("      %s\n", sstateStr(sp->s));
+	    printf ("  </oneSwitch>\n");
+	}
+
+	printf ("</setSwitchVector>\n");
+	fflush (stdout);
+}
+
+/* tell client to update an existing lights vector property */
+void
+IDSetLight (const ILightVectorProperty *lvp, const char *fmt, ...)
+{
+	int i;
+
+	xmlv1();
+	printf ("<setLightVector\n");
+	printf ("  device='%s'\n", lvp->device);
+	printf ("  name='%s'\n", lvp->name);
+	printf ("  state='%s'\n", pstateStr(lvp->s));
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < lvp->nlp; i++) {
+	    ILight *lp = &lvp->lp[i];
+	    printf ("  <oneLight name='%s'>\n", lp->name);
+	    printf ("      %s\n", pstateStr(lp->s));
+	    printf ("  </oneLight>\n");
+	}
+
+	printf ("</setLightVector>\n");
+	fflush (stdout);
+}
+
+/* tell client to update an existing BLOB vector property */
+void
+IDSetBLOB (const IBLOBVectorProperty *bvp, const char *fmt, ...)
+{
+	int i;
+
+	xmlv1();
+	printf ("<setBLOBVector\n");
+	printf ("  device='%s'\n", bvp->device);
+	printf ("  name='%s'\n", bvp->name);
+	printf ("  state='%s'\n", pstateStr(bvp->s));
+	printf ("  timeout='%g'\n", bvp->timeout);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf (">\n");
+
+	for (i = 0; i < bvp->nbp; i++) {
+	    IBLOB *bp = &bvp->bp[i];
+	    unsigned char *encblob;
+	    int j, l;
+
+	    printf ("  <oneBLOB\n");
+	    printf ("    name='%s'\n", bp->name);
+	    printf ("    size='%d'\n", bp->size);
+	    printf ("    format='%s'>\n", bp->format);
+
+	    encblob = malloc (4*bp->bloblen/3+4);
+	    l = to64frombits(encblob, bp->blob, bp->bloblen);
+	    for (j = 0; j < l; j += 72)
+		printf ("%.72s\n", encblob+j);
+	    free (encblob);
+
+	    printf ("  </oneBLOB>\n");
+	}
+
+  printf ("</setBLOBVector>\n");
+  fflush (stdout);
+}
+
+/* tell client to update min/max elements of an existing number vector property */
+void IUUpdateMinMax(const INumberVectorProperty *nvp)
+{
+  int i;
+
+  xmlv1();
+  printf ("<setNumberVector\n");
+  printf ("  device='%s'\n", nvp->device);
+  printf ("  name='%s'\n", nvp->name);
+  printf ("  state='%s'\n", pstateStr(nvp->s));
+  printf ("  timeout='%g'\n", nvp->timeout);
+  printf ("  timestamp='%s'\n", timestamp());
+  printf (">\n");
+
+  for (i = 0; i < nvp->nnp; i++) {
+    INumber *np = &nvp->np[i];
+    printf ("  <oneNumber name='%s'\n", np->name);
+    printf ("    min='%g'\n", np->min);
+    printf ("    max='%g'\n", np->max);
+    printf ("    step='%g'\n", np->step);
+    printf(">\n");
+    printf ("      %g\n", np->value);
+    printf ("  </oneNumber>\n");
+  }
+
+  printf ("</setNumberVector>\n");
+  fflush (stdout);
+}
+
+/* send client a message for a specific device or at large if !dev */
+void
+IDMessage (const char *dev, const char *fmt, ...)
+{
+
+        xmlv1();
+	printf ("<message\n");
+	if (dev)
+	    printf (" device='%s'\n", dev);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf ("/>\n");
+	fflush (stdout);
+}
+
+/* tell Client to delete the property with given name on given device, or
+ * entire device if !name
+ */
+void
+IDDelete (const char *dev, const char *name, const char *fmt, ...)
+{
+	xmlv1();
+	printf ("<delProperty\n  device='%s'\n", dev);
+	if (name)
+	    printf (" name='%s'\n", name);
+	printf ("  timestamp='%s'\n", timestamp());
+	if (fmt) {
+	    va_list ap;
+	    va_start (ap, fmt);
+	    printf ("  message='");
+	    vprintf (fmt, ap);
+	    printf ("'\n");
+	    va_end (ap);
+	}
+	printf ("/>\n");
+	fflush (stdout);
+}
+
+/* tell indiserver we want to snoop on the given device/property.
+ * name ignored if NULL or empty.
+ */
+void
+IDSnoopDevice (const char *snooped_device_name, char *snooped_property_name)
+{
+	xmlv1();
+	if (snooped_property_name && snooped_property_name[0])
+	    printf ("<getProperties device='%s' name='%s'/>\n",
+				    snooped_device_name, snooped_property_name);
+	else
+	    printf ("<getProperties device='%s'/>\n", snooped_device_name);
+	fflush (stdout);
+}
+
+/* tell indiserver whether we want BLOBs from the given snooped device.
+ * silently ignored if given device is not already registered for snooping.
+ */
+void 
+IDSnoopBLOBs (const char *snooped_device, BLOBHandling bh)
+{
+	const char *how;
+
+	switch (bh) {
+	case B_NEVER: how = "Never"; break;
+	case B_ALSO:  how = "Also";  break;
+	case B_ONLY:  how = "Only";  break;
+	default: return;
+	}
+
+	xmlv1();
+	printf ("<enableBLOB device='%s'>%s</enableBLOB>\n",
+						snooped_device, how);
+	fflush (stdout);
+}
+
+/* "INDI" wrappers to the more generic eventloop facility. */
+
+int
+IEAddCallback (int readfiledes, IE_CBF *fp, void *p)
+{
+	return (addCallback (readfiledes, (CBF*)fp, p));
+}
+
+void
+IERmCallback (int callbackid)
+{
+	rmCallback (callbackid);
+}
+
+int
+IEAddTimer (int millisecs, IE_TCF *fp, void *p)
+{
+	return (addTimer (millisecs, (TCF*)fp, p));
+}
+
+void
+IERmTimer (int timerid)
+{
+	rmTimer (timerid);
+}
+
+int
+IEAddWorkProc (IE_WPF *fp, void *p)
+{
+	return (addWorkProc ((WPF*)fp, p));
+}
+
+void
+IERmWorkProc (int workprocid)
+{
+	rmWorkProc (workprocid);
+}
+
+
+int
+IEDeferLoop (int maxms, int *flagp)
+{
+	return (deferLoop (maxms, flagp));
+}
+
+int
+IEDeferLoop0 (int maxms, int *flagp)
+{
+	return (deferLoop0 (maxms, flagp));
+}
+
+/* find a member of an IText vector, else NULL */
+IText *
+IUFindText  (const ITextVectorProperty *tvp, const char *name)
+{
+	int i;
+
+	for (i = 0; i < tvp->ntp; i++)
+	    if (strcmp (tvp->tp[i].name, name) == 0)
+		return (&tvp->tp[i]);
+	fprintf (stderr, "No IText '%s' in %s.%s\n",name,tvp->device,tvp->name);
+	return (NULL);
+}
+
+/* find a member of an INumber vector, else NULL */
+INumber *
+IUFindNumber(const INumberVectorProperty *nvp, const char *name)
+{
+	int i;
+
+	for (i = 0; i < nvp->nnp; i++)
+	    if (strcmp (nvp->np[i].name, name) == 0)
+		return (&nvp->np[i]);
+	fprintf(stderr,"No INumber '%s' in %s.%s\n",name,nvp->device,nvp->name);
+	return (NULL);
+}
+
+/* find a member of an ISwitch vector, else NULL */
+ISwitch *
+IUFindSwitch(const ISwitchVectorProperty *svp, const char *name)
+{
+	int i;
+
+	for (i = 0; i < svp->nsp; i++)
+	    if (strcmp (svp->sp[i].name, name) == 0)
+		return (&svp->sp[i]);
+	fprintf(stderr,"No ISwitch '%s' in %s.%s\n",name,svp->device,svp->name);
+	return (NULL);
+}
+
+/* find an ON member of an ISwitch vector, else NULL.
+ * N.B. user must make sense of result with ISRule in mind.
+ */
+ISwitch *
+IUFindOnSwitch(const ISwitchVectorProperty *svp)
+{
+	int i;
+
+	for (i = 0; i < svp->nsp; i++)
+	    if (svp->sp[i].s == ISS_ON)
+		return (&svp->sp[i]);
+	/*fprintf(stderr, "No ISwitch On in %s.%s\n", svp->device, svp->name);*/
+	return (NULL);
+}
+
+/* Set all switches to off */
+void 
+IUResetSwitch(ISwitchVectorProperty *svp)
+{
+  int i;
+  
+  for (i = 0; i < svp->nsp; i++)
+    svp->sp[i].s = ISS_OFF;
+}
+
+/* Update property switches in accord with states and names. */
+int 
+IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
+{
+ int i=0;
+ ISwitch *sp;
+ char sn[MAXINDINAME];
+
+ /* store On switch name */
+ if (svp->r == ISR_1OFMANY)
+ {
+ 	sp = IUFindOnSwitch(svp);
+ 	if (sp) strncpy(sn, sp->name, MAXINDINAME);
+ 
+	IUResetSwitch(svp);
+ }
+ 
+ for (i = 0; i < n ; i++)
+ {
+   sp = IUFindSwitch(svp, names[i]);
+	 
+   if (!sp)
+   {
+              svp->s = IPS_IDLE;
+	      IDSetSwitch(svp, "Error: %s is not a member of %s property.", names[i], svp->name);
+	      return -1;
+   }
+	 
+   sp->s = states[i]; 
+ }
+ 
+ /* Consistency checks for ISR_1OFMANY after update. */
+ if (svp->r == ISR_1OFMANY)
+ {
+	int t_count=0;
+	for (i=0; i < svp->nsp; i++)
+	{
+		if (svp->sp[i].s == ISS_ON)
+			t_count++;
+	}
+	if (t_count != 1)
+	{
+		IUResetSwitch(svp);
+		sp = IUFindSwitch(svp, sn);
+		if (sp) sp->s = ISS_ON;
+		svp->s = IPS_IDLE;
+		IDSetSwitch(svp, "Error: invalid state switch for property %s. %s.", svp->name, t_count == 0 ? "No switch is on" : "Too many switches are on");
+		return -1;
+	}
+ }
+		
+ return 0;
+
+}
+
+/* Update property numbers in accord with values and names */
+int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
+{
+  int i=0;
+  
+  INumber *np;
+  
+  for (i = 0; i < n; i++)
+  {
+    np = IUFindNumber(nvp, names[i]);
+    if (!np)
+    {
+    	nvp->s = IPS_IDLE;
+	IDSetNumber(nvp, "Error: %s is not a member of %s property.", names[i], nvp->name);
+	return -1;
+    }
+    
+    if (values[i] < np->min || values[i] > np->max)
+    {
+       nvp->s = IPS_IDLE;
+       IDSetNumber(nvp, "Error: Invalid range. Valid range is from %g to %g", np->min, np->max);
+       return -1;
+    }
+      
+  }
+
+  /* First loop checks for error, second loop set all values atomically*/
+  for (i=0; i < n; i++)
+  {
+    np = IUFindNumber(nvp, names[i]);
+    np->value = values[i];
+  }
+
+  return 0;
+
+}
+
+/* Update property text in accord with texts and names */
+int IUUpdateText(ITextVectorProperty *tvp, char * texts[], char *names[], int n)
+{
+  int i=0;
+  
+  IText *tp;
+  
+  for (i = 0; i < n; i++)
+  {
+    tp = IUFindText(tvp, names[i]);
+    if (!tp)
+    {
+    	tvp->s = IPS_IDLE;
+	IDSetText(tvp, "Error: %s is not a member of %s property.", names[i], tvp->name);
+	return -1;
+    }
+  }
+
+  /* First loop checks for error, second loop set all values atomically*/
+  for (i=0; i < n; i++)
+  {
+    tp = IUFindText(tvp, names[i]);
+    IUSaveText(tp, texts[i]);
+  }
+
+  return 0;
+
+}
+
+/* save malloced copy of newtext in tp->text, reusing if not first time */
+void
+IUSaveText (IText *tp, const char *newtext)
+{
+	/* seed for realloc */
+	if (tp->text == NULL)
+	    tp->text = malloc (1);
+
+	/* copy in fresh string */
+	tp->text = strcpy (realloc (tp->text, strlen(newtext)+1), newtext);
+}
+
+void IUFillSwitch(ISwitch *sp, const char *name, const char * label, ISState s)
+{
+  strcpy(sp->name, name);
+  strcpy(sp->label, label);
+  sp->s = s;
+  sp->svp = NULL;
+  sp->aux = NULL;
+}
+
+void IUFillLight(ILight *lp, const char *name, const char * label, IPState s)
+{
+  strcpy(lp->name, name);
+  strcpy(lp->label, label);
+  lp->s = s;
+  lp->lvp = NULL;
+  lp->aux = NULL;
+}
+
+
+void IUFillNumber(INumber *np, const char *name, const char * label, const char *format, double min, double max, double step, double value)
+{
+
+  strcpy(np->name, name);
+  strcpy(np->label, label);
+  strcpy(np->format, format);
+  
+  np->min	= min;
+  np->max	= max;
+  np->step	= step;
+  np->value	= value;
+  np->nvp	= NULL;
+  np->aux0	= NULL;
+  np->aux1	= NULL;
+}
+
+void IUFillText(IText *tp, const char *name, const char * label, const char *initialText)
+{
+
+  strcpy(tp->name, name);
+  strcpy(tp->label, label);
+  tp->text = NULL;
+  tp->tvp  = NULL;
+  tp->aux0 = NULL;
+  tp->aux1 = NULL;
+
+  IUSaveText(tp, initialText);
+
+}
+
+void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char * dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
+{
+  strcpy(svp->device, dev);
+  strcpy(svp->name, name);
+  strcpy(svp->label, label);
+  strcpy(svp->group, group);
+  strcpy(svp->timestamp, "");
+  
+  svp->p	= p;
+  svp->r	= r;
+  svp->timeout	= timeout;
+  svp->s	= s;
+  svp->sp	= sp;
+  svp->nsp	= nsp;
+}
+
+void IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char * dev, const char *name, const char *label, const char *group, IPState s)
+{
+  strcpy(lvp->device, dev);
+  strcpy(lvp->name, name);
+  strcpy(lvp->label, label);
+  strcpy(lvp->group, group);
+  strcpy(lvp->timestamp, "");
+  
+  lvp->s	= s;
+  lvp->lp	= lp;
+  lvp->nlp	= nlp;
+}
+ 
+void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s)
+{
+  
+  strcpy(nvp->device, dev);
+  strcpy(nvp->name, name);
+  strcpy(nvp->label, label);
+  strcpy(nvp->group, group);
+  strcpy(nvp->timestamp, "");
+  
+  nvp->p	= p;
+  nvp->timeout	= timeout;
+  nvp->s	= s;
+  nvp->np	= np;
+  nvp->nnp	= nnp;
+  
+}
+
+void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s)
+{
+  strcpy(tvp->device, dev);
+  strcpy(tvp->name, name);
+  strcpy(tvp->label, label);
+  strcpy(tvp->group, group);
+  strcpy(tvp->timestamp, "");
+  
+  tvp->p	= p;
+  tvp->timeout	= timeout;
+  tvp->s	= s;
+  tvp->tp	= tp;
+  tvp->ntp	= ntp;
+
+}
+
+/*****************************************************************************
+ * convenience functions for use in your implementation of ISSnoopDevice().
+ */
+
+/* crack the snooped driver setNumberVector or defNumberVector message into
+ * the given INumberVectorProperty.
+ * return 0 if type, device and name match and all members are present, else
+ * return -1
+ */
+int
+IUSnoopNumber (XMLEle *root, INumberVectorProperty *nvp)
+{
+	char *dev, *name;
+	XMLEle *ep;
+	int i;
+
+	/* check and crack type, device, name and state */
+	if (strcmp (tagXMLEle(root)+3, "NumberVector") ||
+					crackDN (root, &dev, &name, NULL) < 0)
+	    return (-1);
+	if (strcmp (dev, nvp->device) || strcmp (name, nvp->name))
+	    return (-1);	/* not this property */
+	(void) crackIPState (findXMLAttValu (root,"state"), &nvp->s);
+
+	/* match each INumber with a oneNumber */
+	for (i = 0; i < nvp->nnp; i++) {
+	    for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		if (!strcmp (tagXMLEle(ep), "oneNumber") &&
+			!strcmp (nvp->np[i].name, findXMLAttValu(ep, "name"))) {
+		    if (f_scansexa (pcdataXMLEle(ep), &nvp->np[i].value) < 0)
+			return (-1);	/* bad number format */
+		    break;
+		}
+	    }
+	    if (!ep)
+		return (-1);	/* element not found */
+	}
+
+	/* ok */
+	return (0);
+}
+
+/* crack the snooped driver setTextVector or defTextVector message into
+ * the given ITextVectorProperty.
+ * return 0 if type, device and name match and all members are present, else
+ * return -1
+ */
+int
+IUSnoopText (XMLEle *root, ITextVectorProperty *tvp)
+{
+	char *dev, *name;
+	XMLEle *ep;
+	int i;
+
+	/* check and crack type, device, name and state */
+	if (strcmp (tagXMLEle(root)+3, "TextVector") ||
+					crackDN (root, &dev, &name, NULL) < 0)
+	    return (-1);
+	if (strcmp (dev, tvp->device) || strcmp (name, tvp->name))
+	    return (-1);	/* not this property */
+	(void) crackIPState (findXMLAttValu (root,"state"), &tvp->s);
+
+	/* match each IText with a oneText */
+	for (i = 0; i < tvp->ntp; i++) {
+	    for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		if (!strcmp (tagXMLEle(ep), "oneText") &&
+			!strcmp (tvp->tp[i].name, findXMLAttValu(ep, "name"))) {
+		    IUSaveText (&tvp->tp[i], pcdataXMLEle(ep));
+		    break;
+		}
+	    }
+	    if (!ep)
+		return (-1);	/* element not found */
+	}
+
+	/* ok */
+	return (0);
+}
+
+/* crack the snooped driver setLightVector or defLightVector message into
+ * the given ILightVectorProperty. it is not necessary that all ILight names
+ * be found.
+ * return 0 if type, device and name match, else return -1.
+ */
+int
+IUSnoopLight (XMLEle *root, ILightVectorProperty *lvp)
+{
+	char *dev, *name;
+	XMLEle *ep;
+	int i;
+
+	/* check and crack type, device, name and state */
+	if (strcmp (tagXMLEle(root)+3, "LightVector") ||
+					crackDN (root, &dev, &name, NULL) < 0)
+	    return (-1);
+	if (strcmp (dev, lvp->device) || strcmp (name, lvp->name))
+	    return (-1);	/* not this property */
+
+	(void) crackIPState (findXMLAttValu (root,"state"), &lvp->s);
+
+	/* match each oneLight with one ILight */
+	for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+	    if (!strcmp (tagXMLEle(ep), "oneLight")) {
+		const char *name = findXMLAttValu (ep, "name");
+		for (i = 0; i < lvp->nlp; i++) {
+		    if (!strcmp (lvp->lp[i].name, name)) {
+			if (crackIPState(pcdataXMLEle(ep), &lvp->lp[i].s) < 0) {
+			    return (-1);	/* unrecognized state */
+			}
+			break;
+		    }
+		}
+	    }
+	}
+
+	/* ok */
+	return (0);
+}
+
+/* crack the snooped driver setSwitchVector or defSwitchVector message into the
+ * given ISwitchVectorProperty. it is not necessary that all ISwitch names be
+ * found.
+ * return 0 if type, device and name match, else return -1.
+ */
+int
+IUSnoopSwitch (XMLEle *root, ISwitchVectorProperty *svp)
+{
+	char *dev, *name;
+	XMLEle *ep;
+	int i;
+
+	/* check and crack type, device, name and state */
+	if (strcmp (tagXMLEle(root)+3, "SwitchVector") ||
+					crackDN (root, &dev, &name, NULL) < 0)
+	    return (-1);
+	if (strcmp (dev, svp->device) || strcmp (name, svp->name))
+	    return (-1);	/* not this property */
+	(void) crackIPState (findXMLAttValu (root,"state"), &svp->s);
+
+	/* match each oneSwitch with one ISwitch */
+	for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+	    if (!strcmp (tagXMLEle(ep), "oneSwitch")) {
+		const char *name = findXMLAttValu (ep, "name");
+		for (i = 0; i < svp->nsp; i++) {
+		    if (!strcmp (svp->sp[i].name, name)) {
+			if (crackISState(pcdataXMLEle(ep), &svp->sp[i].s) < 0) {
+			    return (-1);	/* unrecognized state */
+			}
+			break;
+		    }
+		}
+	    }
+	}
+
+	/* ok */
+	return (0);
+}
+
+/* crack the snooped driver setBLOBVector message into the given
+ * IBLOBVectorProperty. it is not necessary that all IBLOB names be found.
+ * return 0 if type, device and name match, else return -1.
+ * N.B. we assume any existing blob in bvp has been malloced, which we free
+ *   and replace with a newly malloced blob if found.
+ */
+int
+IUSnoopBLOB (XMLEle *root, IBLOBVectorProperty *bvp)
+{
+	char *dev, *name;
+	XMLEle *ep;
+	int i;
+
+	/* check and crack type, device, name and state */
+	if (strcmp (tagXMLEle(root), "setBLOBVector") ||
+					crackDN (root, &dev, &name, NULL) < 0)
+	    return (-1);
+	if (strcmp (dev, bvp->device) || strcmp (name, bvp->name))
+	    return (-1);	/* not this property */
+	(void) crackIPState (findXMLAttValu (root,"state"), &bvp->s);
+
+	/* match each oneBLOB with one IBLOB */
+	for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+	    if (!strcmp (tagXMLEle(ep), "oneBLOB")) {
+		const char *name = findXMLAttValu (ep, "name");
+		for (i = 0; i < bvp->nbp; i++) {
+		    IBLOB *bp = &bvp->bp[i];
+		    if (!strcmp (bp->name, name)) {
+			strcpy (bp->format, findXMLAttValu (ep,"format"));
+			bp->size = atof (findXMLAttValu (ep,"size"));
+			bp->bloblen = pcdatalenXMLEle(ep)+1;
+			if (bp->blob)
+			    free (bp->blob);
+			bp->blob = strcpy(malloc(bp->bloblen),pcdataXMLEle(ep));
+			break;
+		    }
+		}
+	    }
+	}
+
+	/* ok */
+	return (0);
+}
+
+/* print usage message and exit (1) */
+static void
+usage(void)
+{
+	fprintf (stderr, "Usage: %s [options]\n", me);
+	fprintf (stderr, "Purpose: INDI Device driver framework.\n");
+	fprintf (stderr, "Options:\n");
+	fprintf (stderr, " -v    : more verbose to stderr\n");
+
+	exit (1);
+}
+
+/* callback when INDI client message arrives on stdin.
+ * collect and dispatch when see outter element closure.
+ * exit if OS trouble or see incompatable INDI version.
+ * arg is not used.
+ */
+static void
+clientMsgCB (int fd, void *arg)
+{
+	char buf[1024], msg[1024], *bp;
+	int nr;
+	arg=arg;
+
+	/* one read */
+	nr = read (fd, buf, sizeof(buf));
+	if (nr < 0) {
+	    fprintf (stderr, "%s: %s\n", me, strerror(errno));
+	    exit(1);
+	}
+	if (nr == 0) {
+	    fprintf (stderr, "%s: EOF\n", me);
+	    exit(1);
+	}
+
+	/* crack and dispatch when complete */
+	for (bp = buf; nr-- > 0; bp++) {
+	    XMLEle *root = readXMLEle (clixml, *bp, msg);
+	    if (root) {
+		if (dispatch (root, msg) < 0)
+		    fprintf (stderr, "%s dispatch error: %s\n", me, msg);
+		delXMLEle (root);
+	    } else if (msg[0])
+		fprintf (stderr, "%s XML error: %s\n", me, msg);
+	}
+
+}
+
+/* crack the given INDI XML element and call driver's IS* entry points as they
+ *   are recognized.
+ * return 0 if ok else -1 with reason in msg[].
+ * N.B. exit if getProperties does not proclaim a compatible version.
+ */
+static int
+dispatch (XMLEle *root, char msg[])
+{
+	char *rtag = tagXMLEle(root);
+	XMLEle *ep;
+	int n,i=0;
+
+	if (verbose)
+	    prXMLEle (stderr, root, 0);
+
+	/* check tag in surmised decreasing order of likelyhood */
+
+	if (!strcmp (rtag, "newNumberVector")) {
+	    static double *doubles;
+	    static char **names;
+	    static int maxn;
+	    char *dev, *name;
+
+	    /* pull out device and name */
+	    if (crackDN (root, &dev, &name, msg) < 0)
+		return (-1);
+
+	    /* seed for reallocs */
+	    if (!doubles) {
+		doubles = (double *) malloc (1);
+		names = (char **) malloc (1);
+	    }
+
+	    /* pull out each name/value pair */
+	    for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		if (strcmp (tagXMLEle(ep), "oneNumber") == 0) {
+		    XMLAtt *na = findXMLAtt (ep, "name");
+		    if (na) {
+			if (n >= maxn) {
+			    /* grow for this and another */
+			    int newsz = (maxn=n+1)*sizeof(double);
+			    doubles = (double *) realloc(doubles,newsz);
+			    newsz = maxn*sizeof(char *);
+			    names = (char **) realloc (names, newsz);
+			}
+			if (f_scansexa (pcdataXMLEle(ep), &doubles[n]) < 0)
+			    IDMessage (dev,"%s: Bad format %s", name,
+							    pcdataXMLEle(ep));
+			else
+			    names[n++] = valuXMLAtt(na);
+		    }
+		}
+	    }
+	    
+	    /* insure property is not RO */
+	    for (i=0; i < nroCheck; i++)
+	    {
+	      if (!strcmp(roCheck[i].propName, name))
+	      {
+	       if (roCheck[i].perm == IP_RO)
+	         return -1;
+	      }
+	    }
+
+	    /* invoke driver if something to do, but not an error if not */
+	    if (n > 0)
+		ISNewNumber (dev, name, doubles, names, n);
+	    else
+		IDMessage(dev,"%s: newNumberVector with no valid members",name);
+	    return (0);
+	}
+
+	if (!strcmp (rtag, "newSwitchVector")) {
+	    static ISState *states;
+	    static char **names;
+	    static int maxn;
+	    char *dev, *name;
+	    XMLEle *ep;
+
+	    /* pull out device and name */
+	    if (crackDN (root, &dev, &name, msg) < 0)
+		return (-1);
+
+	    /* seed for reallocs */
+	    if (!states) {
+		states = (ISState *) malloc (1);
+		names = (char **) malloc (1);
+	    }
+
+	    /* pull out each name/state pair */
+	    for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		if (strcmp (tagXMLEle(ep), "oneSwitch") == 0) {
+		    XMLAtt *na = findXMLAtt (ep, "name");
+		    if (na) {
+			if (n >= maxn) {
+			    int newsz = (maxn=n+1)*sizeof(ISState);
+			    states = (ISState *) realloc(states, newsz);
+			    newsz = maxn*sizeof(char *);
+			    names = (char **) realloc (names, newsz);
+			}
+			if (strcmp (pcdataXMLEle(ep),"On") == 0) {
+			    states[n] = ISS_ON;
+			    names[n] = valuXMLAtt(na);
+			    n++;
+			} else if (strcmp (pcdataXMLEle(ep),"Off") == 0) {
+			    states[n] = ISS_OFF;
+			    names[n] = valuXMLAtt(na);
+			    n++;
+			} else 
+			    IDMessage (dev, "%s: must be On or Off: %s", name,
+							    pcdataXMLEle(ep));
+		    }
+		}
+	    }
+
+	    /* insure property is not RO */
+	    for (i=0; i < nroCheck; i++)
+	    {
+	      if (!strcmp(roCheck[i].propName, name))
+	      {
+	       if (roCheck[i].perm == IP_RO)
+	         return -1;
+	      }
+	    }
+	    
+	    /* invoke driver if something to do, but not an error if not */
+	    if (n > 0)
+		ISNewSwitch (dev, name, states, names, n);
+	    else
+		IDMessage(dev,"%s: newSwitchVector with no valid members",name);
+	    return (0);
+	}
+
+	if (!strcmp (rtag, "newTextVector")) {
+	    static char **texts;
+	    static char **names;
+	    static int maxn;
+	    char *dev, *name;
+
+	    /* pull out device and name */
+	    if (crackDN (root, &dev, &name, msg) < 0)
+		return (-1);
+
+	    /* seed for reallocs */
+	    if (!texts) {
+		texts = (char **) malloc (1);
+		names = (char **) malloc (1);
+	    }
+
+	    /* pull out each name/text pair */
+	    for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		if (strcmp (tagXMLEle(ep), "oneText") == 0) {
+		    XMLAtt *na = findXMLAtt (ep, "name");
+		    if (na) {
+			if (n >= maxn) {
+			    int newsz = (maxn=n+1)*sizeof(char *);
+			    texts = (char **) realloc (texts, newsz);
+			    names = (char **) realloc (names, newsz);
+			}
+			texts[n] = pcdataXMLEle(ep);
+			names[n] = valuXMLAtt(na);
+			n++;
+		    }
+		}
+	    }
+	    
+	    /* insure property is not RO */
+	    for (i=0; i < nroCheck; i++)
+	    {
+	      if (!strcmp(roCheck[i].propName, name))
+	      {
+	       if (roCheck[i].perm == IP_RO)
+	         return -1;
+	      }
+	    }
+
+	    /* invoke driver if something to do, but not an error if not */
+	    if (n > 0)
+		ISNewText (dev, name, texts, names, n);
+	    else
+		IDMessage (dev, "%s: set with no valid members", name);
+	    return (0);
+	}
+
+	if (!strcmp (rtag, "newBLOBVector")) {
+	    static char **blobs;
+	    static char **names;
+	    static char **formats;
+	    static int *blobsizes;
+	    static int *sizes;
+	    static int maxn;
+	    char *dev, *name;
+	    int i;
+
+	    /* pull out device and name */
+	    if (crackDN (root, &dev, &name, msg) < 0)
+		return (-1);
+
+	    /* seed for reallocs */
+	    if (!blobs) {
+		blobs = (char **) malloc (1);
+		names = (char **) malloc (1);
+		formats = (char **) malloc (1);
+		blobsizes = (int *) malloc (1);
+		sizes = (int *) malloc (1);
+	    }
+
+	    /* pull out each name/BLOB pair, decode */
+	    for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		if (strcmp (tagXMLEle(ep), "oneBLOB") == 0) {
+		    XMLAtt *na = findXMLAtt (ep, "name");
+		    XMLAtt *fa = findXMLAtt (ep, "format");
+		    XMLAtt *sa = findXMLAtt (ep, "size");
+		    if (na && fa && sa) {
+			if (n >= maxn) {
+			    int newsz = (maxn=n+1)*sizeof(char *);
+			    blobs = (char **) realloc (blobs, newsz);
+			    names = (char **) realloc (names, newsz);
+			    formats = (char **) realloc(formats,newsz);
+			    newsz = maxn*sizeof(int);
+			    sizes = (int *) realloc(sizes,newsz);
+			    blobsizes = (int *) realloc(blobsizes,newsz);
+			}
+			blobs[n] = malloc (3*pcdatalenXMLEle(ep)/4);
+			blobsizes[n] = from64tobits(blobs[n], pcdataXMLEle(ep));
+			names[n] = valuXMLAtt(na);
+			formats[n] = valuXMLAtt(fa);
+			sizes[n] = atoi(valuXMLAtt(sa));
+			n++;
+		    }
+		}
+	    }
+
+	    /* invoke driver if something to do, but not an error if not */
+	    if (n > 0) {
+		ISNewBLOB (dev, name, sizes, blobsizes, blobs, formats,names,n);
+		for (i = 0; i < n; i++)
+		    free (blobs[i]);
+	    } else
+		IDMessage (dev, "%s: newBLOBVector with no valid members",name);
+	    return (0);
+	}
+
+	if (!strcmp (rtag, "getProperties")) {
+	    XMLAtt *ap;
+	    double v;
+
+	    /* check version */
+	    ap = findXMLAtt (root, "version");
+	    if (!ap) {
+		fprintf (stderr, "%s: getProperties missing version\n", me);
+		exit(1);
+	    }
+	    v = atof (valuXMLAtt(ap));
+	    if (v > INDIV) {
+		fprintf (stderr, "%s: client version %g > %g\n", me, v, INDIV);
+		exit(1);
+	    }
+
+	    /* ok */
+	    ap = findXMLAtt (root, "device");
+	    ISGetProperties (ap ? valuXMLAtt(ap) : NULL);
+	    return (0);
+	}
+
+	/* other commands might be from a snooped device.
+	 * we don't know here which devices are being snooped so we send
+	 * all remaining valid messages
+	 */
+	if (        !strcmp (rtag, "setNumberVector") ||
+		    !strcmp (rtag, "setTextVector") ||
+		    !strcmp (rtag, "setLightVector") ||
+		    !strcmp (rtag, "setSwitchVector") ||
+		    !strcmp (rtag, "setBLOBVector") ||
+		    !strcmp (rtag, "defNumberVector") ||
+		    !strcmp (rtag, "defTextVector") ||
+		    !strcmp (rtag, "defLightVector") ||
+		    !strcmp (rtag, "defSwitchVector") ||
+		    !strcmp (rtag, "defBLOBVector") ||
+		    !strcmp (rtag, "message") ||
+		    !strcmp (rtag, "delProperty")) {
+	    ISSnoopDevice (root);
+	    return (0);
+	}
+
+	sprintf (msg, "Unknown command: %s", rtag);
+	return(1);
+}
+
+/* pull out device and name attributes from root.
+ * return 0 if ok else -1 with reason in msg[].
+ */
+static int
+crackDN (XMLEle *root, char **dev, char **name, char msg[])
+{
+	XMLAtt *ap;
+
+	ap = findXMLAtt (root, "device");
+	if (!ap) {
+	    sprintf (msg, "%s requires 'device' attribute", tagXMLEle(root));
+	    return (-1);
+	}
+	*dev = valuXMLAtt(ap);
+
+	ap = findXMLAtt (root, "name");
+	if (!ap) {
+	    sprintf (msg, "%s requires 'name' attribute", tagXMLEle(root));
+	    return (-1);
+	}
+	*name = valuXMLAtt(ap);
+
+	return (0);
+}
+
+/* return static string corresponding to the given property or light state */
+const char *
+pstateStr (IPState s)
+{
+	switch (s) {
+	case IPS_IDLE:  return ("Idle");
+	case IPS_OK:    return ("Ok");
+	case IPS_BUSY:  return ("Busy");
+	case IPS_ALERT: return ("Alert");
+	default:
+	    fprintf (stderr, "Impossible IPState %d\n", s);
+	    exit(1);
+	}
+}
+
+/* crack string into IPState.
+ * return 0 if ok, else -1
+ */
+static int
+crackIPState (const char *str, IPState *ip)
+{
+	     if (!strcmp (str, "Idle"))  *ip = IPS_IDLE;
+	else if (!strcmp (str, "Ok"))    *ip = IPS_OK;
+	else if (!strcmp (str, "Busy"))  *ip = IPS_BUSY;
+	else if (!strcmp (str, "Alert")) *ip = IPS_ALERT;
+	else return (-1);
+	return (0);
+}
+
+/* crack string into ISState.
+ * return 0 if ok, else -1
+ */
+static int
+crackISState (const char *str, ISState *ip)
+{
+	     if (!strcmp (str, "On"))  *ip = ISS_ON;
+	else if (!strcmp (str, "Off")) *ip = ISS_OFF;
+	else return (-1);
+	return (0);
+}
+
+/* return static string corresponding to the given switch state */
+const char *
+sstateStr (ISState s)
+{
+	switch (s) {
+	case ISS_ON:  return ("On");
+	case ISS_OFF: return ("Off");
+	default:
+	    fprintf (stderr, "Impossible ISState %d\n", s);
+	    exit(1);
+	}
+}
+
+/* return static string corresponding to the given Rule */
+const char *
+ruleStr (ISRule r)
+{
+	switch (r) {
+	case ISR_1OFMANY: return ("OneOfMany");
+	case ISR_ATMOST1: return ("AtMostOne");
+	case ISR_NOFMANY: return ("AnyOfMany");
+	default:
+	    fprintf (stderr, "Impossible ISRule %d\n", r);
+	    exit(1);
+	}
+}
+
+/* return static string corresponding to the given IPerm */
+const char *
+permStr (IPerm p)
+{
+	switch (p) {
+	case IP_RO: return ("ro");
+	case IP_WO: return ("wo");
+	case IP_RW: return ("rw");
+	default:
+	    fprintf (stderr, "Impossible IPerm %d\n", p);
+	    exit(1);
+	}
+}
+
+/* print the boilerplate comment introducing xml */
+static void
+xmlv1()
+{
+	printf ("<?xml version='1.0'?>\n");
+}
Index: /BAORadio/libindi/v1/indiserver.c
===================================================================
--- /BAORadio/libindi/v1/indiserver.c	(revision 500)
+++ /BAORadio/libindi/v1/indiserver.c	(revision 500)
@@ -0,0 +1,1495 @@
+/* INDI Server for protocol version 1.7.
+ * Copyright (C) 2007 Elwood C. Downey ecdowney@clearskyinstitute.com
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+ * argv lists names of Driver programs to run or sockets to connect for Devices.
+ * Drivers are restarted if they exit or connection closes.
+ * Each local Driver's stdin/out are assumed to provide INDI traffic and are
+ *   connected here via pipes. Local Drivers' stderr are connected to our
+ *   stderr with date stamp and driver name prepended.
+ * We only support Drivers that advertise support for one Device. The problem
+ *   with multiple Devices in one Driver is without a way to know what they
+ *   _all_ are there is no way to avoid sending all messages to all Drivers.
+ * Outbound messages are limited to Devices and Properties seen inbound.
+ *   Messages to Devices on sockets always include Device so the chained
+ *   indiserver will only pass back info from that Device.
+ * All newXXX() received from one Client are echoed to all other Clients who
+ *   have shown an interest in the same Device and property.
+ *
+ * Implementation notes:
+ *
+ * We fork each driver and open a server socket listening for INDI clients.
+ * Then forever we listen for new clients and pass traffic between clients and
+ * drivers, subject to optimizations based on sniffing messages for matching
+ * Devices and Properties. Since one message might be destined to more than
+ * one client or device, they are queued and only removed after the last
+ * consumer is finished. XMLEle are converted to linear strings before being
+ * sent to optimize write system calls and avoid blocking to slow clients.
+ * Clients that get more than maxqsiz bytes behind are shut down.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include "lilxml.h"
+#include "indiapi.h"
+#include "fq.h"
+
+#define INDIPORT        7624            /* default TCP/IP port to listen */
+#define	REMOTEDVR	(-1234)		/* invalid PID to flag remote drivers */
+#define	MAXRBUF		4096		/* max read buffering here */
+#define	MAXWSIZ		4096		/* max bytes/write */
+#define	DEFMAXQSIZ	10		/* default max q behind, MB */
+
+/* associate a usage count with queuded client or device message */
+typedef struct {
+    int count;				/* number of consumers left */
+    unsigned int cl;			/* content length */
+    char *cp;				/* content: buf or malloced */
+    char buf[MAXWSIZ];		/* local buf for most messages */
+} Msg;
+
+/* BLOB handling, NEVER is the default */
+typedef enum {B_NEVER=0, B_ALSO, B_ONLY} BLOBHandling;
+
+/* device + property name */
+typedef struct {
+    char dev[MAXINDIDEVICE];
+    char name[MAXINDINAME];
+} Property;
+
+/* record of each snooped property */
+typedef struct {
+    Property prop;
+    BLOBHandling blob;			/* when to snoop BLOBs */
+} Snoopee;
+
+/* info for each connected client */
+typedef struct {
+    int active;				/* 1 when this record is in use */
+    Property *props;			/* malloced array of props we want */
+    int nprops;				/* n entries in props[] */
+    int allprops;			/* saw getProperties w/o device */
+    BLOBHandling blob;			/* when to send setBLOBs */
+    int s;				/* socket for this client */
+    LilXML *lp;				/* XML parsing context */
+    FQ *msgq;				/* Msg queue */
+    unsigned int nsent;				/* bytes of current Msg sent so far */
+} ClInfo;
+static ClInfo *clinfo;			/*  malloced pool of clients */
+static int nclinfo;			/* n total (not active) */
+
+/* info for each connected driver */
+typedef struct {
+    const char *name;				/* persistent malloced name */
+    char dev[MAXINDIDEVICE];		/* device served by this driver */
+    Snoopee *sprops;			/* malloced array of props we snoop */
+    int nsprops;			/* n entries in sprops[] */
+    int pid;				/* process id or REMOTEDVR if remote */
+    int rfd;				/* read pipe fd */
+    int wfd;				/* write pipe fd */
+    int efd;				/* stderr from driver, if local */
+    int restarts;			/* times process has been restarted */
+    LilXML *lp;				/* XML parsing context */
+    FQ *msgq;				/* Msg queue */
+    unsigned int nsent;			/* bytes of current Msg sent so far */
+} DvrInfo;
+static DvrInfo *dvrinfo;		/* malloced array of drivers */
+static int ndvrinfo;			/* n total */
+
+static char *me;			/* our name */
+static int port = INDIPORT;		/* public INDI port */
+static int verbose;			/* chattiness */
+static int lsocket;			/* listen socket */
+static char *ldir;			/* where to log driver messages */
+static int maxqsiz = (DEFMAXQSIZ*1024*1024); /* kill if these bytes behind */
+
+static void logStartup(int ac, char *av[]);
+static void usage (void);
+static void noZombies (void);
+static void noSIGPIPE (void);
+static void indiRun (void);
+static void indiListen (void);
+static void newClient (void);
+static int newClSocket (void);
+static void shutdownClient (ClInfo *cp);
+static int readFromClient (ClInfo *cp);
+static void startDvr (DvrInfo *dp);
+static void startLocalDvr (DvrInfo *dp);
+static void startRemoteDvr (DvrInfo *dp);
+static int openINDIServer (char host[], int indi_port);
+static void restartDvr (DvrInfo *dp);
+static void q2RDrivers (const char *dev, Msg *mp, XMLEle *root);
+static void q2SDrivers (int isblob, const char *dev, const char *name, Msg *mp,
+    XMLEle *root);
+static int q2Clients (ClInfo *notme, int isblob, const char *dev, const char *name,
+    Msg *mp, XMLEle *root);
+static void addSDevice (DvrInfo *dp, const char *dev, const char *name);
+static Snoopee *findSDevice (DvrInfo *dp, const char *dev, const char *name);
+static void addClDevice (ClInfo *cp, const char *dev, const char *name);
+static int findClDevice (ClInfo *cp, const char *dev, const char *name);
+static int readFromDriver (DvrInfo *dp);
+static int stderrFromDriver (DvrInfo *dp);
+static int msgQSize (FQ *q);
+static void setMsgXMLEle (Msg *mp, XMLEle *root);
+static void setMsgStr (Msg *mp, char *str);
+static void freeMsg (Msg *mp);
+static Msg *newMsg (void);
+static int sendClientMsg (ClInfo *cp);
+static int sendDriverMsg (DvrInfo *cp);
+static void crackBLOB (char *enableBLOB, BLOBHandling *bp);
+static void traceMsg (XMLEle *root);
+static char *indi_tstamp (char *s);
+static void logDMsg (XMLEle *root, const char *dev);
+static void Bye(void);
+
+int
+main (int ac, char *av[])
+{
+	/* log startup */
+	logStartup(ac, av);
+
+	/* save our name */
+	me = av[0];
+
+	/* crack args */
+	while ((--ac > 0) && ((*++av)[0] == '-')) {
+	    char *s;
+	    for (s = av[0]+1; *s != '\0'; s++)
+		switch (*s) {
+		case 'l':
+		    if (ac < 2) {
+			fprintf (stderr, "-l requires log directory\n");
+			usage();
+		    }
+		    ldir = *++av;
+		    ac--;
+		    break;
+		case 'm':
+		    if (ac < 2) {
+			fprintf (stderr, "-m requires max MB behind\n");
+			usage();
+		    }
+		    maxqsiz = 1024*1024*atoi(*++av);
+		    ac--;
+		    break;
+		case 'p':
+		    if (ac < 2) {
+			fprintf (stderr, "-p requires port value\n");
+			usage();
+		    }
+		    port = atoi(*++av);
+		    ac--;
+		    break;
+		case 'v':
+		    verbose++;
+		    break;
+		default:
+		    usage();
+		}
+	}
+
+	/* at this point there are ac args in av[] to name our drivers */
+	if (ac == 0)
+	    usage();
+
+	/* take care of some unixisms */
+	noZombies();
+	noSIGPIPE();
+
+	/* realloc seed for client pool */
+	clinfo = (ClInfo *) malloc (1);
+	nclinfo = 0;
+
+	/* create driver info array all at once since size never changes */
+	ndvrinfo = ac;
+	dvrinfo = (DvrInfo *) calloc (ndvrinfo, sizeof(DvrInfo));
+
+	/* start each driver */
+	while (ac-- > 0) {
+	    dvrinfo[ac].name = *av++;
+	    startDvr (&dvrinfo[ac]);
+	}
+
+	/* announce we are online */
+	indiListen();
+
+	/* handle new clients and all io */
+	while (1)
+	    indiRun();
+
+	/* whoa! */
+	fprintf (stderr, "unexpected return from main\n");
+	return (1);
+}
+
+/* record we have started and our args */
+static void
+logStartup(int ac, char *av[])
+{
+	int i;
+
+	fprintf (stderr, "%s: startup: ", indi_tstamp(NULL));
+	for (i = 0; i < ac; i++)
+	    fprintf (stderr, "%s ", av[i]);
+	fprintf (stderr, "\n");
+}
+
+/* print usage message and exit (2) */
+static void
+usage(void)
+{
+	fprintf (stderr, "Usage: %s [options] driver [driver ...]\n", me);
+	fprintf (stderr, "Purpose: server for local and remote INDI drivers\n");
+	fprintf (stderr, "Code %s. Protocol %g.\n", "$Revision: 726523 $", INDIV);
+	fprintf (stderr, "Options:\n");
+	fprintf (stderr, " -l d  : log driver messages to <d>/YYYY-MM-DD.islog\n");
+	fprintf (stderr, " -m m  : kill client if gets more than this many MB behind, default %d\n", DEFMAXQSIZ);
+	fprintf (stderr, " -p p  : alternate IP port, default %d\n", INDIPORT);
+	fprintf (stderr, " -v    : show key events, no traffic\n");
+	fprintf (stderr, " -vv   : -v + key message content\n");
+	fprintf (stderr, " -vvv  : -vv + complete xml\n");
+	fprintf (stderr, "driver : executable or device@host[:port]\n");
+
+	exit (2);
+}
+
+/* arrange for no zombies if drivers die */
+static void
+noZombies()
+{
+	struct sigaction sa;
+	sa.sa_handler = SIG_IGN;
+	sigemptyset(&sa.sa_mask);
+#ifdef SA_NOCLDWAIT
+	sa.sa_flags = SA_NOCLDWAIT;
+#else
+	sa.sa_flags = 0;
+#endif
+	(void)sigaction(SIGCHLD, &sa, NULL);
+}
+
+/* turn off SIGPIPE on bad write so we can handle it inline */
+static void
+noSIGPIPE()
+{
+	struct sigaction sa;
+	sa.sa_handler = SIG_IGN;
+	sigemptyset(&sa.sa_mask);
+	(void)sigaction(SIGPIPE, &sa, NULL);
+}
+
+/* start the given INDI driver process or connection.
+ * exit if trouble.
+ */
+static void
+startDvr (DvrInfo *dp)
+{
+	if (strchr (dp->name, '@'))
+	    startRemoteDvr (dp);
+	else
+	    startLocalDvr (dp);
+}
+
+/* start the given local INDI driver process.
+ * exit if trouble.
+ */
+static void
+startLocalDvr (DvrInfo *dp)
+{
+	Msg *mp;
+	char buf[1024];
+	int rp[2], wp[2], ep[2];
+	int pid;
+
+	/* build three pipes: r, w and error*/
+	if (pipe (rp) < 0) {
+	    fprintf (stderr, "%s: read pipe: %s\n", indi_tstamp(NULL),
+							    strerror(errno));
+	    Bye();
+	}
+	if (pipe (wp) < 0) {
+	    fprintf (stderr, "%s: write pipe: %s\n", indi_tstamp(NULL),
+							    strerror(errno));
+	    Bye();
+	}
+	if (pipe (ep) < 0) {
+	    fprintf (stderr, "%s: stderr pipe: %s\n", indi_tstamp(NULL),
+							    strerror(errno));
+	    Bye();
+	}
+
+	/* fork&exec new process */
+	pid = fork();
+	if (pid < 0) {
+	    fprintf (stderr, "%s: fork: %s\n", indi_tstamp(NULL), strerror(errno));
+	    Bye();
+	}
+	if (pid == 0) {
+	    /* child: exec name */
+	    int fd;
+
+	    /* rig up pipes */
+	    dup2 (wp[0], 0);	/* driver stdin reads from wp[0] */
+	    dup2 (rp[1], 1);	/* driver stdout writes to rp[1] */
+	    dup2 (ep[1], 2);	/* driver stderr writes to e[]1] */
+	    for (fd = 3; fd < 100; fd++)
+		(void) close (fd);
+
+	    /* go -- should never return */
+	    execlp (dp->name, dp->name, NULL);
+	    fprintf (stderr, "%s: Driver %s: execlp: %s\n", indi_tstamp(NULL),
+						dp->name, strerror(errno));
+	    _exit (1);	/* parent will notice EOF shortly */
+	}
+
+	/* don't need child's side of pipes */
+	close (wp[0]);
+	close (rp[1]);
+	close (ep[1]);
+
+	/* record pid, io channels, init lp and snoop list */
+	dp->pid = pid;
+	dp->rfd = rp[0];
+	dp->wfd = wp[1];
+	dp->efd = ep[0];
+	dp->lp = newLilXML();
+	dp->msgq = newFQ(1);
+	dp->sprops = (Snoopee*) malloc (1);	/* seed for realloc */
+	dp->nsprops = 0;
+	dp->nsent = 0;
+
+	/* first message primes driver to report its properties -- dev known
+	 * if restarting
+	 */
+	mp = newMsg();
+	pushFQ (dp->msgq, mp);
+	if (dp->dev[0])
+	    sprintf (buf, "<getProperties device='%s' version='%g'/>\n",
+							    dp->dev, INDIV);
+	else
+	    sprintf (buf, "<getProperties version='%g'/>\n", INDIV);
+	setMsgStr (mp, buf);
+	mp->count++;
+
+	if (verbose > 0)
+	    fprintf (stderr, "%s: Driver %s: pid=%d rfd=%d wfd=%d efd=%d\n",
+		    indi_tstamp(NULL), dp->name, dp->pid, dp->rfd, dp->wfd, dp->efd);
+}
+
+/* start the given remote INDI driver connection.
+ * exit if trouble.
+ */
+static void
+startRemoteDvr (DvrInfo *dp)
+{
+	Msg *mp;
+	char dev[1024];
+	char host[1024];
+	char buf[1024];
+	int indi_port, sockfd;
+
+	/* extract host and port */
+	indi_port = INDIPORT;
+	if (sscanf (dp->name, "%[^@]@%[^:]:%d", dev, host, &indi_port) < 2) {
+	    fprintf (stderr, "Bad remote device syntax: %s\n", dp->name);
+	    Bye();
+	}
+
+	/* connect */
+	sockfd = openINDIServer (host, indi_port);
+
+	/* record flag pid, io channels, init lp and snoop list */
+	dp->pid = REMOTEDVR;
+	dp->rfd = sockfd;
+	dp->wfd = sockfd;
+	dp->lp = newLilXML();
+	dp->msgq = newFQ(1);
+	dp->sprops = (Snoopee*) malloc (1);	/* seed for realloc */
+	dp->nsprops = 0;
+	dp->nsent = 0;
+
+	/* N.B. storing name now is key to limiting outbound traffic to this
+	 * dev.
+	 */
+	strncpy (dp->dev, dev, MAXINDIDEVICE-1);
+	dp->dev[MAXINDIDEVICE-1] = '\0';
+
+	/* Sending getProperties with device lets remote server limit its
+	 * outbound (and our inbound) traffic on this socket to this device.
+	 */
+	mp = newMsg();
+	pushFQ (dp->msgq, mp);
+	sprintf (buf, "<getProperties device='%s' version='%g'/>\n",
+							    dp->dev, INDIV);
+	setMsgStr (mp, buf);
+	mp->count++;
+
+	if (verbose > 0)
+	    fprintf (stderr, "%s: Driver %s: socket=%d\n", indi_tstamp(NULL),
+							    dp->name, sockfd);
+}
+
+/* open a connection to the given host and port or die.
+ * return socket fd.
+ */
+static int
+openINDIServer (char host[], int indi_port)
+{
+	struct sockaddr_in serv_addr;
+	struct hostent *hp;
+	int sockfd;
+
+	/* lookup host address */
+	hp = gethostbyname (host);
+	if (!hp) {
+	    fprintf (stderr, "gethostbyname(%s): %s\n", host, strerror(errno));
+	    Bye();
+	}
+
+	/* create a socket to the INDI server */
+	(void) memset ((char *)&serv_addr, 0, sizeof(serv_addr));
+	serv_addr.sin_family = AF_INET;
+	serv_addr.sin_addr.s_addr =
+			    ((struct in_addr *)(hp->h_addr_list[0]))->s_addr;
+	serv_addr.sin_port = htons(indi_port);
+	if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+	    fprintf (stderr, "socket(%s,%d): %s\n", host, indi_port,strerror(errno));
+	    Bye();
+	}
+
+	/* connect */
+	if (connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){
+	    fprintf (stderr, "connect(%s,%d): %s\n", host,indi_port,strerror(errno));
+	    Bye();
+	}
+
+	/* ok */
+	return (sockfd);
+}
+
+/* create the public INDI Driver endpoint lsocket on port.
+ * return server socket else exit.
+ */
+static void
+indiListen ()
+{
+	struct sockaddr_in serv_socket;
+	int sfd;
+	int reuse = 1;
+
+	/* make socket endpoint */
+	if ((sfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+	    fprintf (stderr, "%s: socket: %s\n", indi_tstamp(NULL), strerror(errno));
+	    Bye();
+	}
+
+	/* bind to given port for any IP address */
+	memset (&serv_socket, 0, sizeof(serv_socket));
+	serv_socket.sin_family = AF_INET;
+	#ifdef SSH_TUNNEL
+	serv_socket.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+	#else
+	serv_socket.sin_addr.s_addr = htonl (INADDR_ANY);
+	#endif
+	serv_socket.sin_port = htons ((unsigned short)port);
+	if (setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0){
+	    fprintf (stderr, "%s: setsockopt: %s\n", indi_tstamp(NULL),
+							    strerror(errno));
+	    Bye();
+	}
+	if (bind(sfd,(struct sockaddr*)&serv_socket,sizeof(serv_socket)) < 0){
+	    fprintf (stderr, "%s: bind: %s\n", indi_tstamp(NULL), strerror(errno));
+	    Bye();
+	}
+
+	/* willing to accept connections with a backlog of 5 pending */
+	if (listen (sfd, 5) < 0) {
+	    fprintf (stderr, "%s: listen: %s\n", indi_tstamp(NULL), strerror(errno));
+	    Bye();
+	}
+
+	/* ok */
+	lsocket = sfd;
+	if (verbose > 0)
+	    fprintf (stderr, "%s: listening to port %d on fd %d\n",
+	    					indi_tstamp(NULL), port, sfd);
+}
+
+/* service traffic from clients and drivers */
+static void
+indiRun(void)
+{
+	fd_set rs, ws;
+	int maxfd;
+	int i, s;
+
+	/* init with no writers or readers */
+	FD_ZERO(&ws);
+	FD_ZERO(&rs);
+
+	/* always listen for new clients */
+	FD_SET(lsocket, &rs);
+	maxfd = lsocket;
+
+	/* add all client readers and client writers with work to send */
+	for (i = 0; i < nclinfo; i++) {
+	    ClInfo *cp = &clinfo[i];
+	    if (cp->active) {
+		FD_SET(cp->s, &rs);
+		if (nFQ(cp->msgq) > 0)
+		    FD_SET(cp->s, &ws);
+		if (cp->s > maxfd)
+		    maxfd = cp->s;
+	    }
+	}
+
+	/* add all driver readers and driver writers with work to send */
+	for (i = 0; i < ndvrinfo; i++) {
+	    DvrInfo *dp = &dvrinfo[i];
+	    FD_SET(dp->rfd, &rs);
+	    if (dp->rfd > maxfd)
+		maxfd = dp->rfd;
+	    if (dp->pid != REMOTEDVR) {
+		FD_SET(dp->efd, &rs);
+		if (dp->efd > maxfd)
+		    maxfd = dp->efd;
+	    }
+	    if (nFQ(dp->msgq) > 0) {
+		FD_SET(dp->wfd, &ws);
+		if (dp->wfd > maxfd)
+		    maxfd = dp->wfd;
+	    }
+	}
+
+	/* wait for action */
+	s = select (maxfd+1, &rs, &ws, NULL, NULL);
+	if (s < 0) {
+	    fprintf (stderr, "%s: select(%d): %s\n", indi_tstamp(NULL), maxfd+1,
+							    strerror(errno));
+	    Bye();
+	}
+
+	/* new client? */
+	if (s > 0 && FD_ISSET(lsocket, &rs)) {
+	    newClient();
+	    s--;
+	}
+
+	/* message to/from client? */
+	for (i = 0; s > 0 && i < nclinfo; i++) {
+	    ClInfo *cp = &clinfo[i];
+	    if (cp->active) {
+		if (FD_ISSET(cp->s, &rs)) {
+		    if (readFromClient(cp) < 0)
+			return;	/* fds effected */
+		    s--;
+		}
+		if (s > 0 && FD_ISSET(cp->s, &ws)) {
+		    if (sendClientMsg(cp) < 0)
+			return;	/* fds effected */
+		    s--;
+		}
+	    }
+	}
+
+	/* message to/from driver? */
+	for (i = 0; s > 0 && i < ndvrinfo; i++) {
+	    DvrInfo *dp = &dvrinfo[i];
+	    if (dp->pid != REMOTEDVR && FD_ISSET(dp->efd, &rs)) {
+		if (stderrFromDriver(dp) < 0)
+		    return;	/* fds effected */
+		s--;
+	    }
+	    if (s > 0 && FD_ISSET(dp->rfd, &rs)) {
+		if (readFromDriver(dp) < 0)
+		    return;	/* fds effected */
+		s--;
+	    }
+	    if (s > 0 && FD_ISSET(dp->wfd, &ws) && nFQ(dp->msgq) > 0) {
+		if (sendDriverMsg(dp) < 0)
+		    return;	/* fds effected */
+		s--;
+	    }
+	}
+}
+
+/* prepare for new client arriving on lsocket.
+ * exit if trouble.
+ */
+static void
+newClient()
+{
+	ClInfo *cp = NULL;
+	int s, cli;
+
+	/* assign new socket */
+	s = newClSocket ();
+
+	/* try to reuse a clinfo slot, else add one */
+	for (cli = 0; cli < nclinfo; cli++)
+	    if (!(cp = &clinfo[cli])->active)
+		break;
+	if (cli == nclinfo) {
+	    /* grow clinfo */
+	    clinfo = (ClInfo *) realloc (clinfo, (nclinfo+1)*sizeof(ClInfo));
+	    if (!clinfo) {
+		fprintf (stderr, "no memory for new client\n");
+		Bye();
+	    }
+	    cp = &clinfo[nclinfo++];
+	}
+
+	/* rig up new clinfo entry */
+	memset (cp, 0, sizeof(*cp));
+	cp->active = 1;
+	cp->s = s;
+	cp->lp = newLilXML();
+	cp->msgq = newFQ(1);
+	cp->props = malloc (1);
+	cp->nsent = 0;
+
+	if (verbose > 0) {
+	    struct sockaddr_in addr;
+	    socklen_t len = sizeof(addr);
+	    getpeername(s, (struct sockaddr*)&addr, &len);
+	    fprintf(stderr,"%s: Client %d: new arrival from %s:%d - welcome!\n",
+			    indi_tstamp(NULL), cp->s, inet_ntoa(addr.sin_addr),
+							ntohs(addr.sin_port));
+	}
+}
+
+/* read more from the given client, send to each appropriate driver when see
+ * xml closure. also send all newXXX() to all other interested clients.
+ * return -1 if had to shut down anything, else 0.
+ */
+static int
+readFromClient (ClInfo *cp)
+{
+	char buf[MAXRBUF];
+	int shutany = 0;
+	int i, nr;
+
+	/* read client */
+	nr = read (cp->s, buf, sizeof(buf));
+	if (nr <= 0) {
+	    if (nr < 0)
+		fprintf (stderr, "%s: Client %d: read: %s\n", indi_tstamp(NULL),
+							cp->s, strerror(errno));
+	    else if (verbose > 0)
+		fprintf (stderr, "%s: Client %d: read EOF\n", indi_tstamp(NULL),
+									cp->s);
+	    shutdownClient (cp);
+	    return (-1);
+	}
+
+	/* process XML, sending when find closure */
+	for (i = 0; i < nr; i++) {
+	    char err[1024];
+	    XMLEle *root = readXMLEle (cp->lp, buf[i], err);
+	    if (root) {
+		char *roottag = tagXMLEle(root);
+		const char *dev = findXMLAttValu (root, "device");
+		const char *name = findXMLAttValu (root, "name");
+		int isblob = !strcmp (tagXMLEle(root), "setBLOBVector");
+		Msg *mp;
+
+		if (verbose > 2) {
+		    fprintf (stderr, "%s: Client %d: read ",indi_tstamp(NULL),cp->s);
+		    traceMsg (root);
+		} else if (verbose > 1) {
+		    fprintf (stderr, "%s: Client %d: read <%s device='%s' name='%s'>\n",
+				    indi_tstamp(NULL), cp->s, tagXMLEle(root),
+				    findXMLAttValu (root, "device"),
+				    findXMLAttValu (root, "name"));
+		}
+
+		/* snag interested properties.
+		 * N.B. don't open to alldevs if seen specific dev already, else
+		 *   remote client connections start returning too much.
+		 */
+		if (dev[0])
+		    addClDevice (cp, dev, name);
+		else if (!strcmp (roottag, "getProperties") && !cp->nprops)
+		    cp->allprops = 1;
+
+		/* snag enableBLOB -- send to remote drivers too */
+		if (!strcmp (roottag, "enableBLOB"))
+		    crackBLOB (pcdataXMLEle(root), &cp->blob);
+
+		/* build a new message -- set content iff anyone cares */
+		mp = newMsg();
+
+		/* send message to driver(s) responsible for dev */
+		q2RDrivers (dev, mp, root);
+
+		/* echo new* commands back to other clients */
+		if (!strncmp (roottag, "new", 3)) {
+		    if (q2Clients (cp, isblob, dev, name, mp, root) < 0)
+			shutany++;
+		}
+
+		/* set message content if anyone cares else forget it */
+		if (mp->count > 0)
+		    setMsgXMLEle (mp, root);
+		else
+		    freeMsg (mp);
+		delXMLEle (root);
+
+	    } else if (err[0]) {
+		char *ts = indi_tstamp(NULL);
+		fprintf (stderr, "%s: Client %d: XML error: %s\n", ts,
+								cp->s, err);
+		fprintf (stderr, "%s: Client %d: XML read: %.*s\n", ts,
+							    cp->s, nr, buf);
+		shutdownClient (cp);
+		return (-1);
+	    }
+	}
+
+	return (shutany ? -1 : 0);
+}
+
+/* read more from the given driver, send to each interested client when see
+ * xml closure. if driver dies, try restarting.
+ * return 0 if ok else -1 if had to shut down anything.
+ */
+static int
+readFromDriver (DvrInfo *dp)
+{
+	char buf[MAXRBUF];
+	int shutany = 0;
+	int i, nr;
+
+	/* read driver */
+	nr = read (dp->rfd, buf, sizeof(buf));
+	if (nr <= 0) {
+	    if (nr < 0)
+		fprintf (stderr, "%s: Driver %s: stdin %s\n", indi_tstamp(NULL),
+						    dp->name, strerror(errno));
+	    else
+		fprintf (stderr, "%s: Driver %s: stdin EOF\n",
+							indi_tstamp(NULL), dp->name);
+	    restartDvr (dp);
+	    return (-1);
+	}
+
+	/* process XML, sending when find closure */
+	for (i = 0; i < nr; i++) {
+	    char err[1024];
+	    XMLEle *root = readXMLEle (dp->lp, buf[i], err);
+	    if (root) {
+		char *roottag = tagXMLEle(root);
+		const char *dev = findXMLAttValu (root, "device");
+		const char *name = findXMLAttValu (root, "name");
+		int isblob = !strcmp (tagXMLEle(root), "setBLOBVector");
+		Msg *mp;
+
+		if (verbose > 2) {
+		    fprintf(stderr, "%s: Driver %s: read ", indi_tstamp(0),dp->name);
+		    traceMsg (root);
+		} else if (verbose > 1) {
+		    fprintf (stderr, "%s: Driver %s: read <%s device='%s' name='%s'>\n",
+				    indi_tstamp(NULL), dp->name, tagXMLEle(root),
+				    findXMLAttValu (root, "device"),
+				    findXMLAttValu (root, "name"));
+		}
+
+		/* that's all if driver is just registering a snoop */
+		if (!strcmp (roottag, "getProperties")) {
+		    addSDevice (dp, dev, name);
+		    delXMLEle (root);
+		    continue;
+		}
+
+		/* that's all if driver is just registering a BLOB mode */
+		if (!strcmp (roottag, "enableBLOB")) {
+		    Snoopee *sp = findSDevice (dp, dev, name);
+		    if (sp)
+			crackBLOB (pcdataXMLEle (root), &sp->blob);
+		    delXMLEle (root);
+		    continue;
+		}
+
+		/* snag device name if not known yet */
+		if (!dp->dev[0] && dev[0]) {
+		    strncpy (dp->dev, dev, MAXINDIDEVICE-1);
+		    dp->dev[MAXINDIDEVICE-1] = '\0';
+		}
+
+		/* log messages if any and wanted */
+		if (ldir)
+		    logDMsg (root, dev);
+
+		/* build a new message -- set content iff anyone cares */
+		mp = newMsg();
+
+		/* send to interested clients */
+		if (q2Clients (NULL, isblob, dev, name, mp, root) < 0)
+		    shutany++;
+
+		/* send to snooping drivers */
+		q2SDrivers (isblob, dev, name, mp, root);
+
+		/* set message content if anyone cares else forget it */
+		if (mp->count > 0)
+		    setMsgXMLEle (mp, root);
+		else
+		    freeMsg (mp);
+		delXMLEle (root);
+
+	    } else if (err[0]) {
+		char *ts = indi_tstamp(NULL);
+		fprintf (stderr, "%s: Driver %s: XML error: %s\n", ts,
+								dp->name, err);
+		fprintf (stderr, "%s: Driver %s: XML read: %.*s\n", ts,
+							    dp->name, nr, buf);
+		restartDvr (dp);
+		return (-1);
+	    }
+	}
+
+	return (shutany ? -1 : 0);
+}
+
+/* read more from the given driver stderr, add prefix and send to our stderr.
+ * return 0 if ok else -1 if had to restart.
+ */
+static int
+stderrFromDriver (DvrInfo *dp)
+{
+	static char exbuf[MAXRBUF];
+	static int nexbuf;
+	int i, nr;
+
+	/* read more */
+	nr = read (dp->efd, exbuf+nexbuf, sizeof(exbuf)-nexbuf);
+	if (nr <= 0) {
+	    if (nr < 0)
+		fprintf (stderr, "%s: Driver %s: stderr %s\n", indi_tstamp(NULL),
+						    dp->name, strerror(errno));
+	    else
+		fprintf (stderr, "%s: Driver %s: stderr EOF\n",
+							indi_tstamp(NULL), dp->name);
+	    restartDvr (dp);
+	    return (-1);
+	}
+	nexbuf += nr;
+
+	/* prefix each whole line to our stderr, save extra for next time */
+	for (i = 0; i < nexbuf; i++) {
+	    if (exbuf[i] == '\n') {
+		fprintf (stderr, "%s: Driver %s: %.*s\n", indi_tstamp(NULL),
+							    dp->name, i, exbuf);
+		i++;				  /* count including nl */
+		nexbuf -= i;			  /* remove from nexbuf */
+		memmove (exbuf, exbuf+i, nexbuf); /* slide remaining to front */
+		i = -1;				  /* restart for loop scan */
+	    }
+	}
+
+	return (0);
+}
+
+/* close down the given client */
+static void
+shutdownClient (ClInfo *cp)
+{
+	Msg *mp;
+
+	/* close connection */
+	shutdown (cp->s, SHUT_RDWR);
+	close (cp->s);
+
+	/* free memory */
+	delLilXML (cp->lp);
+	free (cp->props);
+
+	/* decrement and possibly free any unsent messages for this client */
+	while ((mp = (Msg*) popFQ(cp->msgq)) != NULL)
+	    if (--mp->count == 0)
+		freeMsg (mp);
+	delFQ (cp->msgq);
+
+	/* ok now to recycle */
+	cp->active = 0;
+
+	if (verbose > 0)
+	    fprintf (stderr, "%s: Client %d: shut down complete - bye!\n",
+							indi_tstamp(NULL), cp->s);
+}
+
+/* close down the given driver and restart */
+static void
+restartDvr (DvrInfo *dp)
+{
+	Msg *mp;
+
+	/* make sure it's dead, reclaim resources */
+	if (dp->pid == REMOTEDVR) {
+	    /* socket connection */
+	    shutdown (dp->wfd, SHUT_RDWR);
+	    close (dp->wfd);	/* same as rfd */
+	} else {
+	    /* local pipe connection */
+	    kill (dp->pid, SIGKILL);	/* we've insured there are no zombies */
+	    close (dp->wfd);
+	    close (dp->rfd);
+	    close (dp->efd);
+	}
+
+	/* free memory */
+	free (dp->sprops);
+	delLilXML (dp->lp);
+
+	/* decrement and possibly free any unsent messages for this client */
+	while ((mp = (Msg*) popFQ(dp->msgq)) != NULL)
+	    if (--mp->count == 0)
+		freeMsg (mp);
+	delFQ (dp->msgq);
+
+	fprintf (stderr, "%s: Driver %s: restart #%d\n", indi_tstamp(NULL),
+						    dp->name, ++dp->restarts);
+	startDvr (dp);
+}
+
+/* put Msg mp on queue of each driver responsible for dev, or all drivers
+ * if dev not specified.
+ */
+static void
+q2RDrivers (const char *dev, Msg *mp, XMLEle *root)
+{
+	int sawremote = 0;
+	DvrInfo *dp;
+
+	/* queue message to each interested driver.
+	 * N.B. don't send generic getProps to more than one remote driver,
+	 *   otherwise they all fan out and we get multiple responses back.
+	 */
+	for (dp = dvrinfo; dp < &dvrinfo[ndvrinfo]; dp++) {
+	    int isremote = (dp->pid == REMOTEDVR);
+	    if (dev[0] && dp->dev[0] && strcmp (dev, dp->dev))
+		continue;	/* driver known to not support this dev */
+	    if (!dev[0] && isremote && sawremote)
+		continue;	/* already sent generic to another remote */
+	    if (isremote)
+		sawremote = 1;
+
+	    /* ok: queue message to this driver */
+	    mp->count++;
+	    pushFQ (dp->msgq, mp);
+	    if (verbose > 1)
+		fprintf (stderr, "%s: Driver %s: queuing responsible for <%s device='%s' name='%s'>\n",
+				    indi_tstamp(NULL), dp->name, tagXMLEle(root),
+				    findXMLAttValu (root, "device"),
+				    findXMLAttValu (root, "name"));
+	}
+}
+
+/* put Msg mp on queue of each driver snooping dev/name.
+ * if BLOB always honor current mode.
+ */
+static void
+q2SDrivers (int isblob, const char *dev, const char *name, Msg *mp, XMLEle *root)
+{
+	DvrInfo *dp;
+
+	for (dp = dvrinfo; dp < &dvrinfo[ndvrinfo]; dp++) {
+	    Snoopee *sp = findSDevice (dp, dev, name);
+
+	    /* nothing for dp if not snooping for dev/name or wrong BLOB mode */
+	    if (!sp)
+		continue;
+	    if ((isblob && sp->blob==B_NEVER) || (!isblob && sp->blob==B_ONLY))
+		continue;
+
+	    /* ok: queue message to this device */
+	    mp->count++;
+	    pushFQ (dp->msgq, mp);
+	    if (verbose > 1) {
+		fprintf (stderr, "%s: Driver %s: queuing snooped <%s device='%s' name='%s'>\n",
+				    indi_tstamp(NULL), dp->name, tagXMLEle(root),
+				    findXMLAttValu (root, "device"),
+				    findXMLAttValu (root, "name"));
+	    }
+	}
+}
+
+/* add dev/name to dp's snooping list.
+ * init with blob mode set to B_NEVER.
+ */
+static void
+addSDevice (DvrInfo *dp, const char *dev, const char *name)
+{
+	Snoopee *sp;
+	char *ip;
+
+	/* no dups */
+	sp = findSDevice (dp, dev, name);
+	if (sp)
+	    return;
+
+	/* add dev to sdevs list */
+	dp->sprops = (Snoopee*) realloc (dp->sprops,
+					    (dp->nsprops+1)*sizeof(Snoopee));
+	sp = &dp->sprops[dp->nsprops++];
+
+	ip = sp->prop.dev;
+	strncpy (ip, dev, MAXINDIDEVICE-1);
+	ip[MAXINDIDEVICE-1] = '\0';
+
+	ip = sp->prop.name;
+	strncpy (ip, name, MAXINDINAME-1);
+	ip[MAXINDINAME-1] = '\0';
+
+	sp->blob = B_NEVER;
+
+	if (verbose)
+	    fprintf (stderr, "%s: Driver %s: snooping on %s.%s\n", indi_tstamp(NULL),
+							dp->name, dev, name);
+}
+
+/* return Snoopee if dp is snooping dev/name, else NULL.
+ */
+static Snoopee *
+findSDevice (DvrInfo *dp, const char *dev, const char *name)
+{
+	int i;
+
+	for (i = 0; i < dp->nsprops; i++) {
+	    Snoopee *sp = &dp->sprops[i];
+	    Property *pp = &sp->prop;
+	    if (!strcmp (pp->dev, dev) &&
+		    (!pp->name[0] || !strcmp(pp->name, name)))
+		return (sp);
+	}
+
+	return (NULL);
+}
+
+/* put Msg mp on queue of each client interested in dev/name, except notme.
+ * if BLOB always honor current mode.
+ * return -1 if had to shut down any clients, else 0.
+ */
+static int
+q2Clients (ClInfo *notme, int isblob, const char *dev, const char *name, Msg *mp, XMLEle *root)
+{
+	int shutany = 0;
+	ClInfo *cp;
+	int ql;
+
+	/* queue message to each interested client */
+	for (cp = clinfo; cp < &clinfo[nclinfo]; cp++) {
+	    /* cp in use? notme? want this dev/name? blob? */
+	    if (!cp->active || cp == notme)
+		continue;
+	    if (findClDevice (cp, dev, name) < 0)
+		continue;
+	    if ((isblob && cp->blob==B_NEVER) || (!isblob && cp->blob==B_ONLY))
+		continue;
+
+	    /* shut down this client if its q is already too large */
+	    ql = msgQSize(cp->msgq);
+	    if (ql > maxqsiz) {
+		if (verbose)
+		    fprintf (stderr, "%s: Client %d: %d bytes behind, shutting down\n",
+						    indi_tstamp(NULL), cp->s, ql);
+		shutdownClient (cp);
+		shutany++;
+		continue;
+	    }
+
+	    /* ok: queue message to this client */
+	    mp->count++;
+	    pushFQ (cp->msgq, mp);
+	    if (verbose > 1)
+		fprintf (stderr, "%s: Client %d: queuing <%s device='%s' name='%s'>\n",
+				    indi_tstamp(NULL), cp->s, tagXMLEle(root),
+				    findXMLAttValu (root, "device"),
+				    findXMLAttValu (root, "name"));
+	}
+
+	return (shutany ? -1 : 0);
+}
+
+/* return size of all Msqs on the given q */
+static int
+msgQSize (FQ *q)
+{
+	int i, l = 0;
+
+	for (i = 0; i < nFQ(q); i++) {
+	    Msg *mp = (Msg *) peekiFQ(q,i);
+	    l += mp->cl;
+	}
+
+	return (l);
+}
+
+/* print root as content in Msg mp.
+ */
+static void
+setMsgXMLEle (Msg *mp, XMLEle *root)
+{
+	/* want cl to only count content, but need room for final \0 */
+	mp->cl = sprlXMLEle (root, 0);
+	if (mp->cl < sizeof(mp->buf))
+	    mp->cp = mp->buf;
+	else
+	    mp->cp = malloc (mp->cl+1);
+	sprXMLEle (mp->cp, root, 0);
+}
+
+/* save str as content in Msg mp.
+ */
+static void
+setMsgStr (Msg *mp, char *str)
+{
+	/* want cl to only count content, but need room for final \0 */
+	mp->cl = strlen (str);
+	if (mp->cl < sizeof(mp->buf))
+	    mp->cp = mp->buf;
+	else
+	    mp->cp = malloc (mp->cl+1);
+	strcpy (mp->cp, str);
+}
+
+/* return pointer to one new nulled Msg
+ */
+static Msg *
+newMsg (void)
+{
+	return ((Msg *) calloc (1, sizeof(Msg)));
+}
+
+/* free Msg mp and everything it contains */
+static void
+freeMsg (Msg *mp)
+{
+	if (mp->cp && mp->cp != mp->buf)
+	    free (mp->cp);
+	free (mp);
+}
+
+/* write the next chunk of the current message in the queue to the given
+ * client. pop message from queue when complete and free the message if we are
+ * the last one to use it. shut down this client if trouble.
+ * N.B. we assume we will never be called with cp->msgq empty.
+ * return 0 if ok else -1 if had to shut down.
+ */
+static int
+sendClientMsg (ClInfo *cp)
+{
+	int nsend, nw;
+	Msg *mp;
+
+	/* get current message */
+	mp = (Msg *) peekFQ (cp->msgq);
+
+	/* send next chunk, never more than MAXWSIZ to reduce blocking */
+	nsend = mp->cl - cp->nsent;
+	if (nsend > MAXWSIZ)
+	    nsend = MAXWSIZ;
+	nw = write (cp->s, &mp->cp[cp->nsent], nsend);
+
+	/* shut down if trouble */
+	if (nw <= 0) {
+	    if (nw == 0)
+		fprintf (stderr, "%s: Client %d: write returned 0\n",
+						    indi_tstamp(NULL), cp->s);
+	    else
+		fprintf (stderr, "%s: Client %d: write: %s\n", indi_tstamp(NULL),
+						    cp->s, strerror(errno));
+	    shutdownClient (cp);
+	    return (-1);
+	}
+
+	/* trace */
+	if (verbose > 2) {
+	    fprintf(stderr, "%s: Client %d: sending msg copy %d nq %d:\n%.*s\n",
+				indi_tstamp(NULL), cp->s, mp->count, nFQ(cp->msgq),
+				nw, &mp->cp[cp->nsent]);
+	} else if (verbose > 1) {
+	    fprintf(stderr, "%s: Client %d: sending %.50s\n", indi_tstamp(NULL),
+						    cp->s, &mp->cp[cp->nsent]);
+	}
+
+	/* update amount sent. when complete: free message if we are the last
+	 * to use it and pop from our queue.
+	 */
+	cp->nsent += nw;
+	if (cp->nsent == mp->cl) {
+	    if (--mp->count == 0)
+		freeMsg (mp);
+	    popFQ (cp->msgq);
+	    cp->nsent = 0;
+	}
+
+	return (0);
+}
+
+/* write the next chunk of the current message in the queue to the given
+ * driver. pop message from queue when complete and free the message if we are
+ * the last one to use it. restart this driver if touble.
+ * N.B. we assume we will never be called with dp->msgq empty.
+ * return 0 if ok else -1 if had to shut down.
+ */
+static int
+sendDriverMsg (DvrInfo *dp)
+{
+	int nsend, nw;
+	Msg *mp;
+
+	/* get current message */
+	mp = (Msg *) peekFQ (dp->msgq);
+
+	/* send next chunk, never more than MAXWSIZ to reduce blocking */
+	nsend = mp->cl - dp->nsent;
+	if (nsend > MAXWSIZ)
+	    nsend = MAXWSIZ;
+	nw = write (dp->wfd, &mp->cp[dp->nsent], nsend);
+
+	/* restart if trouble */
+	if (nw <= 0) {
+	    if (nw == 0)
+		fprintf (stderr, "%s: Driver %s: write returned 0\n",
+						    indi_tstamp(NULL), dp->name);
+	    else
+		fprintf (stderr, "%s: Driver %s: write: %s\n", indi_tstamp(NULL),
+						    dp->name, strerror(errno));
+	    restartDvr (dp);
+	    return (-1);
+	}
+
+	/* trace */
+	if (verbose > 2) {
+	    fprintf(stderr, "%s: Driver %s: sending msg copy %d nq %d:\n%.*s\n",
+			    indi_tstamp(NULL), dp->name, mp->count, nFQ(dp->msgq),
+			    nw, &mp->cp[dp->nsent]);
+	} else if (verbose > 1) {
+	    fprintf(stderr, "%s: Driver %s: sending %.50s\n", indi_tstamp(NULL),
+						dp->name, &mp->cp[dp->nsent]);
+	}
+
+	/* update amount sent. when complete: free message if we are the last
+	 * to use it and pop from our queue.
+	 */
+	dp->nsent += nw;
+	if (dp->nsent == mp->cl) {
+	    if (--mp->count == 0)
+		freeMsg (mp);
+	    popFQ (dp->msgq);
+	    dp->nsent = 0;
+	}
+
+	return (0);
+}
+
+/* return 0 if cp may be interested in dev/name else -1
+ */
+static int
+findClDevice (ClInfo *cp, const char *dev, const char *name)
+{
+	int i;
+
+	if (cp->allprops || !dev[0])
+	    return (0);
+	for (i = 0; i < cp->nprops; i++) {
+	    Property *pp = &cp->props[i];
+	    if (!strcmp (pp->dev, dev) &&
+				    (!pp->name[0] || !strcmp(pp->name, name)))
+		return (0);
+	}
+	return (-1);
+}
+
+/* add the given device and property to the devs[] list of client if new.
+ */
+static void
+addClDevice (ClInfo *cp, const char *dev, const char *name)
+{
+	Property *pp;
+	char *ip;
+
+	/* no dups */
+	if (!findClDevice (cp, dev, name))
+	    return;
+
+	/* add */
+	cp->props = (Property *) realloc (cp->props,
+					    (cp->nprops+1)*sizeof(Property));
+	pp = &cp->props[cp->nprops++];
+
+	ip = pp->dev;
+	strncpy (ip, dev, MAXINDIDEVICE-1);
+	ip[MAXINDIDEVICE-1] = '\0';
+
+	ip = pp->name;
+	strncpy (ip, name, MAXINDINAME-1);
+	ip[MAXINDINAME-1] = '\0';
+}
+
+
+/* block to accept a new client arriving on lsocket.
+ * return private nonblocking socket or exit.
+ */
+static int
+newClSocket ()
+{
+	struct sockaddr_in cli_socket;
+	socklen_t cli_len;
+	int cli_fd;
+
+	/* get a private connection to new client */
+	cli_len = sizeof(cli_socket);
+	cli_fd = accept (lsocket, (struct sockaddr *)&cli_socket, &cli_len);
+	if(cli_fd < 0) {
+	    fprintf (stderr, "accept: %s\n", strerror(errno));
+	    Bye();
+	}
+
+	/* ok */
+	return (cli_fd);
+}
+
+/* convert the string value of enableBLOB to our B_ state value.
+ * no change if unrecognized
+ */
+static void
+crackBLOB (char *enableBLOB, BLOBHandling *bp)
+{
+	if (!strcmp (enableBLOB, "Also"))
+	    *bp = B_ALSO;
+	else if (!strcmp (enableBLOB, "Only"))
+	    *bp = B_ONLY;
+	else if (!strcmp (enableBLOB, "Never"))
+	    *bp = B_NEVER;
+}
+
+/* print key attributes and values of the given xml to stderr.
+ */
+static void
+traceMsg (XMLEle *root)
+{
+	static const char *prtags[] = {
+	    "defNumber", "oneNumber",
+	    "defText",   "oneText",
+	    "defSwitch", "oneSwitch",
+	    "defLight",  "oneLight",
+	};
+	XMLEle *e;
+	const char *msg, *perm, *pcd;
+	unsigned int i;
+
+	/* print tag header */
+	fprintf (stderr, "%s %s %s %s", tagXMLEle(root),
+						findXMLAttValu(root,"device"),
+						findXMLAttValu(root,"name"),
+						findXMLAttValu(root,"state"));
+	pcd = pcdataXMLEle (root);
+	if (pcd[0])
+	    fprintf (stderr, " %s", pcd);
+	perm = findXMLAttValu(root,"perm");
+	if (perm[0])
+	    fprintf (stderr, " %s", perm);
+	msg = findXMLAttValu(root,"message");
+	if (msg[0])
+	    fprintf (stderr, " '%s'", msg);
+
+	/* print each array value */
+	for (e = nextXMLEle(root,1); e; e = nextXMLEle(root,0))
+	    for (i = 0; i < sizeof(prtags)/sizeof(prtags[0]); i++)
+		if (strcmp (prtags[i], tagXMLEle(e)) == 0)
+		    fprintf (stderr, "\n %10s='%s'", findXMLAttValu(e,"name"),
+							    pcdataXMLEle (e));
+
+	fprintf (stderr, "\n");
+}
+
+/* fill s with current UT string.
+ * if no s, use a static buffer
+ * return s or buffer.
+ * N.B. if use our buffer, be sure to use before calling again
+ */
+static char *
+indi_tstamp (char *s)
+{
+	static char sbuf[64];
+	struct tm *tp;
+	time_t t;
+
+	time (&t);
+	tp = gmtime (&t);
+	if (!s)
+	    s = sbuf;
+	strftime (s, sizeof(sbuf), "%Y-%m-%dT%H:%M:%S", tp);
+	return (s);
+}
+
+/* log message in root known to be from device dev to ldir, if any.
+ */
+static void
+logDMsg (XMLEle *root, const char *dev)
+{
+	char stamp[64];
+	char logfn[1024];
+	const char *ts, *ms;
+	FILE *fp;
+
+	/* get message, if any */
+	ms = findXMLAttValu (root, "message");
+	if (!ms[0])
+	    return;
+
+	/* get timestamp now if not provided */
+	ts = findXMLAttValu (root, "timestamp");
+	if (!ts[0])
+	{
+	    indi_tstamp (stamp);
+	    ts = stamp;
+	}
+
+	/* append to log file, name is date portion of time stamp */
+	sprintf (logfn, "%s/%.10s.islog", ldir, ts);
+	fp = fopen (logfn, "a");
+	if (!fp)
+	    return;	/* oh well */
+	fprintf (fp, "%s: %s: %s\n", ts, dev, ms);
+	fclose (fp);
+}
+
+/* log when then exit */
+static void
+Bye()
+{
+	fprintf (stderr, "%s: good bye\n", indi_tstamp(NULL));
+	exit(1);
+}
+
Index: /BAORadio/libindi/v1/libindi.kdev4
===================================================================
--- /BAORadio/libindi/v1/libindi.kdev4	(revision 500)
+++ /BAORadio/libindi/v1/libindi.kdev4	(revision 500)
@@ -0,0 +1,3 @@
+[Project]
+Manager=KDevCMakeManager
+Name=libindi
Index: /BAORadio/libindi/v1/libindi.pc.cmake
===================================================================
--- /BAORadio/libindi/v1/libindi.pc.cmake	(revision 500)
+++ /BAORadio/libindi/v1/libindi.pc.cmake	(revision 500)
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@LIB_DESTINATION@
+includedir=@INCLUDE_INSTALL_DIR@
+
+Name: libindi
+Description: Instrument Neutral Distributed Interface
+URL=http://www.indilib.org/
+Version: @CMAKE_INDI_VERSION_STRING@
+Libs: -L@LIB_DESTINATION@ -lindi
+Cflags: -I@INCLUDE_INSTALL_DIR@ -@INCLUDE_INSTALL_DIR@/libindi
Index: /BAORadio/libindi/v1/libs/indicom.c
===================================================================
--- /BAORadio/libindi/v1/libs/indicom.c	(revision 500)
+++ /BAORadio/libindi/v1/libs/indicom.c	(revision 500)
@@ -0,0 +1,645 @@
+/*
+    INDI LIB
+    Common routines used by all drivers
+    Copyright (C) 2003 by Jason Harris (jharris@30doradus.org)
+                          Elwood C. Downey
+
+    This is the C version of the astronomical library in KStars
+    modified by Jasem Mutlaq (mutlaqja@ikarustech.com)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/* needed for sincos() in math.h */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifdef _WIN32
+#define CX _CX
+#define CY _CY
+#endif
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include <config.h>
+
+#ifdef HAVE_NOVA_H
+#include <libnova.h>
+#endif
+
+
+#include "indicom.h"
+#ifdef _WIN32
+#undef CX
+#undef CY
+#endif
+const char * Direction[] = { "North", "West", "East", "South", "All"};
+const char * SolarSystem[] = { "Mercury", "Venus", "Moon", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto"};
+
+/* make it compile on solaris */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338327950288419716939937510582097494459
+#endif
+
+#ifndef _WIN32
+#include <termios.h>
+#define PARITY_NONE    0
+#define PARITY_EVEN    1
+#define PARITY_ODD     2
+#endif
+
+void getSexComponents(double value, int *d, int *m, int *s);
+
+
+int extractISOTime(char *timestr, struct ln_date *iso_date)
+{
+  #ifdef HAVE_NOVA_H	
+  struct tm utm;
+
+  if (strptime(timestr, "%Y/%m/%dT%H:%M:%S", &utm))
+  {
+	ln_get_date_from_tm(&utm, iso_date);
+   	return (0);
+  }
+
+  if (strptime(timestr, "%Y-%m-%dT%H:%M:%S", &utm))
+  {
+	ln_get_date_from_tm(&utm, iso_date);
+   	return (0);
+  }
+  #endif
+  
+  return (-1);
+}
+
+
+/* sprint the variable a in sexagesimal format into out[].
+ * w is the number of spaces for the whole part.
+ * fracbase is the number of pieces a whole is to broken into; valid options:
+ *	360000:	<w>:mm:ss.ss
+ *	36000:	<w>:mm:ss.s
+ *	3600:	<w>:mm:ss
+ *	600:	<w>:mm.m
+ *	60:	<w>:mm
+ * return number of characters written to out, not counting finaif (NOVA_FOUND)
+    include_directories(${NOVA_INCLUDE_DIR})
+endif (NOVA_FOUND)l '\0'.
+ */
+int
+fs_sexa (char *out, double a, int w, int fracbase)
+{
+	char *out0 = out;
+	unsigned long n;
+	int d;
+	int f;
+	int m;
+	int s;
+	int isneg;
+
+	/* save whether it's negative but do all the rest with a positive */
+	isneg = (a < 0);
+	if (isneg)
+	    a = -a;
+
+	/* convert to an integral number of whole portions */
+	n = (unsigned long)(a * fracbase + 0.5);
+	d = n/fracbase;
+	f = n%fracbase;
+
+	/* form the whole part; "negative 0" is a special case */
+	if (isneg && d == 0)
+	    out += sprintf (out, "%*s-0", w-2, "");
+	else
+	    out += sprintf (out, "%*d", w, isneg ? -d : d);
+
+	/* do the rest */
+	switch (fracbase) {
+	case 60:	/* dd:mm */
+	    m = f/(fracbase/60);
+	    out += sprintf (out, ":%02d", m);
+	    break;
+	case 600:	/* dd:mm.m */
+	    out += sprintf (out, ":%02d.%1d", f/10, f%10);
+	    break;
+	case 3600:	/* dd:mm:ss */
+	    m = f/(fracbase/60);
+	    s = f%(fracbase/60);
+	    out += sprintf (out, ":%02d:%02d", m, s);
+	    break;
+	case 36000:	/* dd:mm:ss.s*/
+	    m = f/(fracbase/60);
+	    s = f%(fracbase/60);
+	    out += sprintf (out, ":%02d:%02d.%1d", m, s/10, s%10);
+	    break;
+	case 360000:	/* dd:mm:ss.ss */
+	    m = f/(fracbase/60);
+	    s = f%(fracbase/60);
+	    out += sprintf (out, ":%02d:%02d.%02d", m, s/100, s%100);
+	    break;
+	default:
+	    printf ("fs_sexa: unknown fracbase: %d\n", fracbase);
+	    exit(1);
+	}
+
+	return (out - out0);
+}
+
+/* convert sexagesimal string str AxBxC to double.
+ *   x can be anything non-numeric. Any missing A, B or C will be assumed 0.
+ *   optional - and + can be anywhere.
+ * return 0 if ok, -1 if can't find a thing.
+ */
+int
+f_scansexa (
+const char *str0,	/* input string */
+double *dp)		/* cracked value, if return 0 */
+{
+	double a = 0, b = 0, c = 0;
+	char str[128];
+	char *neg;
+	int r;
+
+	/* copy str0 so we can play with it */
+	strncpy (str, str0, sizeof(str)-1);
+	str[sizeof(str)-1] = '\0';
+
+	neg = strchr(str, '-');
+	if (neg)
+	    *neg = ' ';
+	r = sscanf (str, "%lf%*[^0-9]%lf%*[^0-9]%lf", &a, &b, &c);
+	if (r < 1)
+	    return (-1);
+	*dp = a + b/60 + c/3600;
+	if (neg)
+	    *dp *= -1;
+	return (0);
+}
+
+void getSexComponents(double value, int *d, int *m, int *s)
+{
+
+  *d = (int) fabs(value);
+  *m = (int) ((fabs(value) - *d) * 60.0);
+  *s = (int) rint(((fabs(value) - *d) * 60.0 - *m) *60.0);
+
+  if (value < 0)
+   *d *= -1;
+}
+
+/* fill buf with properly formatted INumber string. return length */
+int
+numberFormat (char *buf, const char *format, double value)
+{
+        int w, f, s;
+        char m;
+
+        if (sscanf (format, "%%%d.%d%c", &w, &f, &m) == 3 && m == 'm') {
+            /* INDI sexi format */
+            switch (f) {
+            case 9:  s = 360000; break;
+            case 8:  s = 36000;  break;
+            case 6:  s = 3600;   break;
+            case 5:  s = 600;    break;
+            default: s = 60;     break;
+            }
+            return (fs_sexa (buf, value, w-f, s));
+        } else {
+            /* normal printf format */
+            return (sprintf (buf, format, value));
+        }
+}
+
+/* log message locally.
+ * this has nothing to do with XML or any Clients.
+ */
+void
+IDLog (const char *fmt, ...)
+{
+	va_list ap;
+	/* JM: Since all INDI's stderr are timestampped now, we don't need to time stamp ID Log */
+	/*fprintf (stderr, "%s ", timestamp());*/
+	va_start (ap, fmt);
+	vfprintf (stderr, fmt, ap);
+	va_end (ap);
+}
+
+/* return current system time in message format */
+const char *
+timestamp()
+{
+	static char ts[32];
+	struct tm *tp;
+	time_t t;
+
+	time (&t);
+	tp = gmtime (&t);
+	strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp);
+	return (ts);
+}
+
+int tty_timeout(int fd, int timeout)
+{
+  struct timeval tv;
+  fd_set readout;
+  int retval;
+
+  FD_ZERO(&readout);
+  FD_SET(fd, &readout);
+
+  /* wait for 'timeout' seconds */
+  tv.tv_sec = timeout;
+  tv.tv_usec = 0;
+
+  /* Wait till we have a change in the fd status */
+  retval = select (fd+1, &readout, NULL, NULL, &tv);
+
+  /* Return 0 on successful fd change */
+  if (retval > 0)
+   return TTY_OK;
+  /* Return -1 due to an error */
+  else if (retval == -1)
+   return TTY_SELECT_ERROR;
+  /* Return -2 if time expires before anything interesting happens */
+  else 
+    return TTY_TIME_OUT;
+  
+}
+
+int tty_write(int fd, const char * buf, int nbytes, int *nbytes_written)
+{
+  int bytes_w = 0;   
+  *nbytes_written = 0;
+   
+  while (nbytes > 0)
+  {
+    
+    bytes_w = write(fd, buf, nbytes);
+
+    if (bytes_w < 0)
+     return TTY_WRITE_ERROR;
+
+    *nbytes_written += bytes_w;
+    buf += bytes_w;
+    nbytes -= bytes_w;
+  }
+
+  return TTY_OK;
+}
+
+int tty_write_string(int fd, const char * buf, int *nbytes_written)
+{
+  unsigned int nbytes;
+  int bytes_w = 0;
+  *nbytes_written = 0;
+   
+  nbytes = strlen(buf);
+
+  while (nbytes > 0)
+  {
+    
+    bytes_w = write(fd, buf, nbytes);
+
+    if (bytes_w < 0)
+     return TTY_WRITE_ERROR;
+
+   *nbytes_written += bytes_w;
+    buf += bytes_w;
+    nbytes -= bytes_w;
+  }
+
+  return TTY_OK;
+}
+
+int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
+{
+
+ int bytesRead = 0;
+ int err = 0;
+ *nbytes_read =0;
+
+  if (nbytes <=0)
+	return TTY_PARAM_ERROR;
+
+  while (nbytes > 0)
+  {
+     if ( (err = tty_timeout(fd, timeout)) )
+      return err;
+
+     bytesRead = read(fd, buf, ((unsigned) nbytes));
+
+     if (bytesRead < 0 )
+      return TTY_READ_ERROR;
+
+     buf += bytesRead;
+     *nbytes_read += bytesRead;
+     nbytes -= bytesRead;
+  }
+
+  return TTY_OK;
+}
+
+int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
+{
+
+ int bytesRead = 0;
+ int err = TTY_OK;
+ *nbytes_read = 0;
+
+ for (;;)
+ {
+         if ( (err = tty_timeout(fd, timeout)) )
+	   return err;
+
+         bytesRead = read(fd, buf, 1);
+
+         if (bytesRead < 0 )
+            return TTY_READ_ERROR;
+
+        if (bytesRead)
+          (*nbytes_read)++;
+
+        if (*buf == stop_char)
+	   return TTY_OK;
+
+        buf += bytesRead;
+  }
+
+  return TTY_TIME_OUT;
+}
+
+int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd)
+{
+#ifdef _WIN32
+  return TTY_PORT_FAILURE;
+
+#else
+ int t_fd=0;
+ char msg[80];
+ int bps;
+ struct termios tty_setting;
+
+ if ( (t_fd = open(device, O_RDWR | O_NOCTTY )) == -1)
+    return TTY_PORT_FAILURE;
+
+    /* Control Modes
+   Set bps rate */
+  switch (bit_rate) {
+    case 0:
+      bps = B0;
+      break;
+    case 50:
+      bps = B50;
+      break;
+    case 75:
+      bps = B75;
+      break;
+    case 110:
+      bps = B110;
+      break;
+    case 134:
+      bps = B134;
+      break;
+    case 150:
+      bps = B150;
+      break;
+    case 200:
+      bps = B200;
+      break;
+    case 300:
+      bps = B300;
+      break;
+    case 600:
+      bps = B600;
+      break;
+    case 1200:
+      bps = B1200;
+      break;
+    case 1800:
+      bps = B1800;
+      break;
+    case 2400:
+      bps = B2400;
+      break;
+    case 4800:
+      bps = B4800;
+      break;
+    case 9600:
+      bps = B9600;
+      break;
+    case 19200:
+      bps = B19200;
+      break;
+    case 38400:
+      bps = B38400;
+      break;
+    case 57600:
+      bps = B57600;
+      break;
+    case 115200:
+      bps = B115200;
+      break;
+    case 230400:
+      bps = B230400;
+      break;
+    default:
+      if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid bit rate.", bit_rate) < 0)
+        perror(NULL);
+      else
+        perror(msg);
+      return TTY_PARAM_ERROR;
+  }
+  if ((cfsetispeed(&tty_setting, bps) < 0) ||
+      (cfsetospeed(&tty_setting, bps) < 0))
+  {
+    perror("tty_connect: failed setting bit rate.");
+    return TTY_PORT_FAILURE;
+  }
+
+   /* Control Modes
+   set no flow control word size, parity and stop bits.
+   Also don't hangup automatically and ignore modem status.
+   Finally enable receiving characters. */
+  tty_setting.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | HUPCL | CRTSCTS);
+  tty_setting.c_cflag |= (CLOCAL | CREAD);
+
+  /* word size */
+  switch (word_size) {
+    case 5:
+      tty_setting.c_cflag |= CS5;
+      break;
+    case 6:
+      tty_setting.c_cflag |= CS6;
+      break;
+    case 7:
+      tty_setting.c_cflag |= CS7;
+      break;
+    case 8:
+      tty_setting.c_cflag |= CS8;
+      break;
+    default:
+
+      fprintf( stderr, "Default\n") ;
+      if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid data bit count.", word_size) < 0)
+        perror(NULL);
+      else
+        perror(msg);
+
+      return TTY_PARAM_ERROR;
+  }
+
+  /* parity */
+  switch (parity) {
+    case PARITY_NONE:
+      break;
+    case PARITY_EVEN:
+      tty_setting.c_cflag |= PARENB;
+      break;
+    case PARITY_ODD:
+      tty_setting.c_cflag |= PARENB | PARODD;
+      break;
+    default:
+
+   fprintf( stderr, "Default1\n") ;
+      if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid parity selection value.", parity) < 0)
+        perror(NULL);
+      else
+        perror(msg);
+
+      return TTY_PARAM_ERROR;
+  }
+
+  /* stop_bits */
+  switch (stop_bits) {
+    case 1:
+      break;
+    case 2:
+      tty_setting.c_cflag |= CSTOPB;
+      break;
+    default:
+   fprintf( stderr, "Default2\n") ;
+      if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid stop bit count.", stop_bits) < 0)
+        perror(NULL);
+      else
+        perror(msg);
+
+      return TTY_PARAM_ERROR;
+  }
+  /* Control Modes complete */
+
+  /* Ignore bytes with parity errors and make terminal raw and dumb.*/
+  tty_setting.c_iflag &= ~(PARMRK | ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON | IXANY);
+  tty_setting.c_iflag |= INPCK | IGNPAR | IGNBRK;
+
+  /* Raw output.*/
+  tty_setting.c_oflag &= ~(OPOST | ONLCR);
+
+   /* Local Modes
+   Don't echo characters. Don't generate signals.
+   Don't process any characters.*/
+  tty_setting.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN | NOFLSH | TOSTOP);
+  tty_setting.c_lflag |=  NOFLSH;
+
+  /* blocking read until 1 char arrives */
+  tty_setting.c_cc[VMIN]  = 1;
+  tty_setting.c_cc[VTIME] = 0;
+
+  /* now clear input and output buffers and activate the new terminal settings */
+  tcflush(t_fd, TCIOFLUSH);
+  if (tcsetattr(t_fd, TCSANOW, &tty_setting)) 
+  {
+    perror("tty_connect: failed setting attributes on serial port.");
+    tty_disconnect(t_fd);
+    return TTY_PORT_FAILURE;
+  }
+  
+  *fd = t_fd;
+  /* return success */
+  return TTY_OK;
+#endif
+}
+
+int tty_disconnect(int fd)
+{
+#ifdef _WIN32
+	return TTY_ERRNO;
+#else
+	int err;
+	tcflush(fd, TCIOFLUSH);
+	err = close(fd);
+
+	if (err != 0)
+		return TTY_ERRNO;
+
+        return TTY_OK;
+#endif
+}
+
+void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
+{
+      char error_string[512];
+
+  switch (err_code)
+ {
+	case TTY_OK:
+		strncpy(err_msg, "No Error", err_msg_len);
+		break;
+
+	case TTY_READ_ERROR:
+		snprintf(error_string, 512, "Read Error: %s", strerror(errno));
+		strncpy(err_msg, error_string, err_msg_len);
+		break;
+		
+       case TTY_WRITE_ERROR:
+		snprintf(error_string, 512, "Write Error: %s", strerror(errno));
+		strncpy(err_msg, error_string, err_msg_len);
+		break;
+
+	case TTY_SELECT_ERROR:
+		snprintf(error_string, 512, "Select Error: %s", strerror(errno));
+		strncpy(err_msg, error_string, err_msg_len);
+		break;
+
+	case TTY_TIME_OUT:
+		strncpy(err_msg, "Timeout error", err_msg_len);
+		break;
+
+	case TTY_PORT_FAILURE:
+		snprintf(error_string, 512, "Port failure Error: %s", strerror(errno));
+		strncpy(err_msg, error_string, err_msg_len);
+		break;
+
+	case TTY_PARAM_ERROR:
+		strncpy(err_msg, "Parameter error", err_msg_len);
+		break;
+
+	case TTY_ERRNO:
+		snprintf(error_string, 512, "%s", strerror(errno));
+		strncpy(err_msg, error_string, err_msg_len);
+		break;
+
+	default:
+		strncpy(err_msg, "Error: unrecognized error code", err_msg_len);
+		break;
+
+
+   }	
+}
Index: /BAORadio/libindi/v1/libs/indicom.h
===================================================================
--- /BAORadio/libindi/v1/libs/indicom.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/indicom.h	(revision 500)
@@ -0,0 +1,201 @@
+/*
+    INDI LIB
+    Common routines used by all drivers
+    Copyright (C) 2003 by Jason Harris (jharris@30doradus.org)
+    			  Elwood C. Downey
+			  Jasem Mutlaq
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/** \file indicom.h
+    \brief Implementations for common driver routines.
+
+    The INDI Common Routine Library provides formatting and serial routines employed by many INDI drivers. Currently, the library is composed of the following sections:
+
+    <ul>
+    <li>Formatting Functions</li>
+    <li>Conversion Functions</li>
+    <li>TTY Functions</li>
+
+
+    </ul>
+    
+    \author Jason Harris
+    \author Elwood C. Downey
+    \author Jasem Mutlaq
+*/
+
+#ifndef INDICOM_H
+#define INDICOM_H
+
+#include <time.h>
+
+#define J2000 2451545.0
+#define ERRMSG_SIZE 1024
+#define INDI_DEBUG
+
+
+extern const char * Direction[];
+extern const char * SolarSystem[];
+
+struct ln_date;
+
+/* TTY Error Codes */
+enum TTY_ERROR { TTY_OK=0, TTY_READ_ERROR=-1, TTY_WRITE_ERROR=-2, TTY_SELECT_ERROR=-3, TTY_TIME_OUT=-4, TTY_PORT_FAILURE=-5, TTY_PARAM_ERROR=-6, TTY_ERRNO = -7};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \defgroup ttyFunctions TTY Functions: Functions to perform common terminal access routines.
+*/
+
+/*@{*/
+
+/** \brief read buffer from terminal
+    \param fd file descriptor
+    \param buf pointer to store data. Must be initilized and big enough to hold data.
+    \param nbytes number of bytes to read.
+    \param timeout number of seconds to wait for terminal before a timeout error is issued.
+    \param nbytes_read the number of bytes read.
+    \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
+*/
+int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read);
+
+/** \brief read buffer from terminal with a delimiter
+    \param fd file descriptor
+    \param buf pointer to store data. Must be initilized and big enough to hold data.
+    \param stop_char if the function encounters \e stop_char then it stops reading and returns the buffer.
+    \param timeout number of seconds to wait for terminal before a timeout error is issued.
+    \param nbytes_read the number of bytes read.
+    \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
+*/
+
+int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read);
+
+
+/** \brief Writes a buffer to fd.
+    \param fd file descriptor
+    \param buffer a null-terminated buffer to write to fd.
+    \param nbytes number of bytes to write from \e buffer
+    \param nbytes_written the number of bytes written
+    \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
+*/
+int tty_write(int fd, const char * buffer, int nbytes, int *nbytes_written);
+
+/** \brief Writes a null terminated string to fd.
+    \param fd file descriptor
+    \param buffer the buffer to write to fd.
+    \param nbytes_written the number of bytes written
+    \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
+*/
+int tty_write_string(int fd, const char * buffer, int *nbytes_written);
+
+
+/** \brief Establishes a tty connection to a terminal device.
+    \param device the device node. e.g. /dev/ttyS0
+    \param bit_rate bit rate
+    \param word_size number of data bits, 7 or 8, USE 8 DATA BITS with modbus
+    \param parity 0=no parity, 1=parity EVEN, 2=parity ODD
+    \param stop_bits number of stop bits : 1 or 2
+    \param fd \e fd is set to the file descriptor value on success.
+    \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
+    \author Wildi Markus
+*/
+
+int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd);
+
+/** \brief Closes a tty connection and flushes the bus.
+    \param fd the file descriptor to close.
+    \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code.
+*/
+int tty_disconnect(int fd);
+
+/** \brief Retrieve the tty error message
+    \param err_code the error code return by any TTY function.
+    \param err_msg an initialized buffer to hold the error message.
+    \param err_msg_len length in bytes of \e err_msg
+*/
+void tty_error_msg(int err_code, char *err_msg, int err_msg_len);
+
+int tty_timeout(int fd, int timeout);
+/*@}*/
+
+/**
+ * \defgroup convertFunctions Formatting Functions: Functions to perform handy formatting and conversion routines.
+ */
+/*@{*/
+
+/** \brief Converts a sexagesimal number to a string.
+ 
+   sprint the variable a in sexagesimal format into out[].
+	
+  \param out a pointer to store the sexagesimal number.
+  \param a the sexagesimal number to convert.
+  \param w the number of spaces in the whole part.
+  \param fracbase is the number of pieces a whole is to broken into; valid options:\n
+          \li 360000:	\<w\>:mm:ss.ss
+	  \li 36000:	\<w\>:mm:ss.s
+ 	  \li 3600:	\<w\>:mm:ss
+ 	  \li 600:	\<w\>:mm.m
+ 	  \li 60:	\<w\>:mm
+  
+  \return number of characters written to out, not counting final null terminator.
+ */
+int fs_sexa (char *out, double a, int w, int fracbase);
+
+/** \brief convert sexagesimal string str AxBxC to double.
+
+    x can be anything non-numeric. Any missing A, B or C will be assumed 0. Optional - and + can be anywhere.
+    
+    \param str0 string containing sexagesimal number.
+    \param dp pointer to a double to store the sexagesimal number.
+    \return return 0 if ok, -1 if can't find a thing.
+ */
+int f_scansexa (const char *str0, double *dp);
+
+/** \brief Extract ISO 8601 time and store it in a tm struct.
+    \param timestr a string containing date and time in ISO 8601 format.
+    \param iso_date a pointer to a \e ln_date structure to store the extracted time and date (libnova).
+    \return 0 on success, -1 on failure.
+*/
+int extractISOTime(char *timestr, struct ln_date *iso_date);
+
+void getSexComponents(double value, int *d, int *m, int *s);
+
+/** \brief Fill buffer with properly formatted INumber string.
+    \param buf to store the formatted string.
+    \param format format in sprintf style.
+    \param value the number to format.
+    \return length of string.
+*/
+int numberFormat (char *buf, const char *format, double value);
+
+/** \brief Create an ISO 8601 formatted time stamp. The format is YYYY-MM-DDTHH:MM:SS
+    \return The formatted time stamp.
+*/
+const char *timestamp (void);
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
Index: /BAORadio/libindi/v1/libs/lilxml.c
===================================================================
--- /BAORadio/libindi/v1/libs/lilxml.c	(revision 500)
+++ /BAORadio/libindi/v1/libs/lilxml.c	(revision 500)
@@ -0,0 +1,1080 @@
+#if 0
+    liblilxml
+    Copyright (C) 2003 Elwood C. Downey
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+/* little DOM-style XML parser.
+ * only handles elements, attributes and pcdata content.
+ * <! ... > and <? ... > are silently ignored.
+ * pcdata is collected into one string, sans leading whitespace first line.
+ *
+ * #define MAIN_TST to create standalone test program
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "lilxml.h"
+
+/* used to efficiently manage growing malloced string space */
+typedef struct {
+    char *s;				/* malloced memory for string */
+    int sl;				/* string length, sans trailing \0 */
+    int sm;				/* total malloced bytes */
+} String;
+#define	MINMEM	64			/* starting string length */
+
+static int oneXMLchar (LilXML *lp, int c, char errmsg[]);
+static void initParser(LilXML *lp);
+static void pushXMLEle(LilXML *lp);
+static void popXMLEle(LilXML *lp);
+static void resetEndTag(LilXML *lp);
+static XMLAtt *growAtt(XMLEle *e);
+static XMLEle *growEle(XMLEle *pe);
+static void freeAtt (XMLAtt *a);
+static int isTokenChar (int start, int c);
+static void growString (String *sp, int c);
+static void appendString (String *sp, const char *str);
+static void freeString (String *sp);
+static void newString (String *sp);
+static void *moremem (void *old, int n);
+
+typedef enum  {
+    LOOK4START = 0,			/* looking for first element start */
+    LOOK4TAG,				/* looking for element tag */
+    INTAG,				/* reading tag */
+    LOOK4ATTRN,				/* looking for attr name, > or / */
+    INATTRN,				/* reading attr name */
+    LOOK4ATTRV,				/* looking for attr value */
+    SAWSLASH,				/* saw / in element opening */
+    INATTRV,				/* in attr value */
+    ENTINATTRV,				/* in entity in attr value */
+    LOOK4CON,				/* skipping leading content whitespc */
+    INCON,				/* reading content */
+    ENTINCON,				/* in entity in pcdata */
+    SAWLTINCON,				/* saw < in content */
+    LOOK4CLOSETAG,			/* looking for closing tag after < */
+    INCLOSETAG				/* reading closing tag */
+} State;				/* parsing states */
+
+/* maintain state while parsing */
+struct _LilXML {
+    State cs;				/* current state */
+    int ln;				/* line number for diags */
+    XMLEle *ce;				/* current element being built */
+    String endtag;			/* to check for match with opening tag*/
+    String entity;			/* collect entity seq */
+    int delim;				/* attribute value delimiter */
+    int lastc;				/* last char (just used wiht skipping)*/
+    int skipping;			/* in comment or declaration */
+};
+
+/* internal representation of a (possibly nested) XML element */
+struct _xml_ele {
+    String tag;				/* element tag */
+    XMLEle *pe;				/* parent element, or NULL if root */
+    XMLAtt **at;			/* list of attributes */
+    int nat;				/* number of attributes */
+    int ait;				/* used to iterate over at[] */
+    XMLEle **el;			/* list of child elements */
+    int nel;				/* number of child elements */
+    int eit;				/* used to iterate over el[] */
+    String pcdata;			/* character data in this element */
+    int pcdata_hasent;			/* 1 if pcdata contains an entity char*/
+};
+
+/* internal representation of an attribute */
+struct _xml_att {
+    String name;			/* name */
+    String valu;			/* value */
+    XMLEle *ce;				/* containing element */
+};
+
+/* characters that need escaping as "entities" in attr values and pcdata
+ */
+static char entities[] = "&<>'\"";
+
+/* default memory managers, override with indi_xmlMalloc() */
+static void *(*mymalloc)(size_t size) = malloc;
+static void *(*myrealloc)(void *ptr, size_t size) = realloc;
+static void (*myfree)(void *ptr) = free;
+
+/* install new version of malloc/realloc/free.
+ * N.B. don't call after first use of any other lilxml function
+ */
+void
+indi_xmlMalloc (void *(*newmalloc)(size_t size),
+	   void *(*newrealloc)(void *ptr, size_t size),
+	   void (*newfree)(void *ptr))
+{
+	mymalloc = newmalloc;
+	myrealloc = newrealloc;
+	myfree = newfree;
+}
+
+/* pass back a fresh handle for use with our other functions */
+LilXML *
+newLilXML ()
+{
+	LilXML *lp = (LilXML *) moremem (NULL, sizeof(LilXML));
+	memset (lp, 0, sizeof(LilXML));
+	initParser(lp);
+	return (lp);
+}
+
+/* discard */
+void
+delLilXML (LilXML *lp)
+{
+	delXMLEle (lp->ce);
+	freeString (&lp->endtag);
+	(*myfree) (lp);
+}
+
+/* delete ep and all its children and remove from parent's list if known */
+void
+delXMLEle (XMLEle *ep)
+{
+	int i;
+
+	/* benign if NULL */
+	if (!ep)
+	    return;
+
+	/* delete all parts of ep */
+	freeString (&ep->tag);
+	freeString (&ep->pcdata);
+	if (ep->at) {
+	    for (i = 0; i < ep->nat; i++)
+		freeAtt (ep->at[i]);
+	    (*myfree) (ep->at);
+	}
+	if (ep->el) {
+	    for (i = 0; i < ep->nel; i++) {
+		/* forget parent so deleting doesn't modify _this_ el[] */
+		ep->el[i]->pe = NULL;
+
+		delXMLEle (ep->el[i]);
+	    }
+	    (*myfree) (ep->el);
+	}
+
+	/* remove from parent's list if known */
+	if (ep->pe) {
+	    XMLEle *pe = ep->pe;
+	    for (i = 0; i < pe->nel; i++) {
+		if (pe->el[i] == ep) {
+		    memmove (&pe->el[i], &pe->el[i+1],
+					      (--pe->nel-i)*sizeof(XMLEle*));
+		    break;
+		}
+	    }
+	}
+
+	/* delete ep itself */
+	(*myfree) (ep);
+}
+
+/* process one more character of an XML file.
+ * when find closure with outter element return root of complete tree.
+ * when find error return NULL with reason in errmsg[].
+ * when need more return NULL with errmsg[0] = '\0'.
+ * N.B. it is up to the caller to delete any tree returned with delXMLEle().
+ */
+XMLEle *
+readXMLEle (LilXML *lp, int newc, char errmsg[])
+{
+	XMLEle *root;
+	int s;
+
+	/* start optimistic */
+	errmsg[0] = '\0';
+
+	/* EOF? */
+	if (newc == 0) {
+	    sprintf (errmsg, "Line %d: early XML EOF", lp->ln);
+	    initParser(lp);
+	    return (NULL);
+	}
+
+	/* new line? */
+	if (newc == '\n')
+	    lp->ln++;
+
+	/* skip comments and declarations. requires 1 char history */
+	if (!lp->skipping && lp->lastc == '<' && (newc == '?' || newc == '!')) {
+	    lp->skipping = 1;
+	    lp->lastc = newc;
+	    return (NULL);
+	}
+	if (lp->skipping) {
+	    if (newc == '>')
+		lp->skipping = 0;
+	    lp->lastc = newc;
+	    return (NULL);
+	}
+	if (newc == '<') {
+	    lp->lastc = '<';
+	    return (NULL);
+	}
+
+	/* do a pending '<' first then newc */
+	if (lp->lastc == '<') {
+	    if (oneXMLchar (lp, '<', errmsg) < 0) {
+		initParser(lp);
+		return (NULL);
+	    }
+	    /* N.B. we assume '<' will never result in closure */
+	}
+
+	/* process newc (at last!) */
+	s = oneXMLchar (lp, newc, errmsg);
+	if (s == 0) {
+	    lp->lastc = newc;
+	    return (NULL);
+	}
+	if (s < 0) {
+	    initParser(lp);
+	    return (NULL);
+	}
+
+	/* Ok! return ce and we start over.
+	 * N.B. up to caller to call delXMLEle with what we return.
+	 */
+	root = lp->ce;
+	lp->ce = NULL;
+	initParser(lp);
+	return (root);
+}
+
+/* search ep for an attribute with given name.
+ * return NULL if not found.
+ */
+XMLAtt *
+findXMLAtt (XMLEle *ep, const char *name)
+{
+	int i;
+
+	for (i = 0; i < ep->nat; i++)
+	    if (!strcmp (ep->at[i]->name.s, name))
+		return (ep->at[i]);
+	return (NULL);
+}
+
+/* search ep for an element with given tag.
+ * return NULL if not found.
+ */
+XMLEle *
+findXMLEle (XMLEle *ep, const char *tag)
+{
+	int tl = strlen (tag);
+	int i;
+
+	for (i = 0; i < ep->nel; i++) {
+	    String *sp = &ep->el[i]->tag;
+	    if (sp->sl == tl && !strcmp (sp->s, tag))
+		return (ep->el[i]);
+	}
+	return (NULL);
+}
+
+/* iterate over each child element of ep.
+ * call first time with first set to 1, then 0 from then on.
+ * returns NULL when no more or err
+ */
+XMLEle *
+nextXMLEle (XMLEle *ep, int init)
+{
+	int eit;
+	
+	if (init)
+	    ep->eit = 0;
+
+	eit = ep->eit++;
+	if (eit < 0 || eit >= ep->nel)
+	    return (NULL);
+	return (ep->el[eit]);
+}
+
+/* iterate over each attribute of ep.
+ * call first time with first set to 1, then 0 from then on.
+ * returns NULL when no more or err
+ */
+XMLAtt *
+nextXMLAtt (XMLEle *ep, int init)
+{
+	int ait;
+
+	if (init)
+	    ep->ait = 0;
+
+	ait = ep->ait++;
+	if (ait < 0 || ait >= ep->nat)
+	    return (NULL);
+	return (ep->at[ait]);
+}
+
+/* return parent of given XMLEle */
+XMLEle *
+parentXMLEle (XMLEle *ep)
+{
+	return (ep->pe);
+}
+
+/* return parent element of given XMLAtt */
+XMLEle *
+parentXMLAtt (XMLAtt *ap)
+{
+	return (ap->ce);
+}
+
+/* access functions */
+
+/* return the tag name of the given element */
+char *
+tagXMLEle (XMLEle *ep)
+{
+	return (ep->tag.s);
+}
+
+/* return the pcdata portion of the given element */
+char *
+pcdataXMLEle (XMLEle *ep)
+{
+	return (ep->pcdata.s);
+}
+
+/* return the number of characters in the pcdata portion of the given element */
+int 
+pcdatalenXMLEle (XMLEle *ep)
+{
+	return (ep->pcdata.sl);
+}
+
+/* return the name of the given attribute */
+char *
+nameXMLAtt (XMLAtt *ap)
+{
+	return (ap->name.s);
+}
+
+/* return the value of the given attribute */
+char *
+valuXMLAtt (XMLAtt *ap)
+{
+	return (ap->valu.s);
+}
+
+/* return the number of child elements of the given element */
+int
+nXMLEle (XMLEle *ep)
+{
+	return (ep->nel);
+}
+
+/* return the number of attributes in the given element */
+int
+nXMLAtt (XMLEle *ep)
+{
+	return (ep->nat);
+}
+
+
+/* search ep for an attribute with the given name and return its value.
+ * return "" if not found.
+ */
+const char *
+findXMLAttValu (XMLEle *ep, const char *name)
+{
+	XMLAtt *a = findXMLAtt (ep, name);
+	return (a ? a->valu.s : "");
+}
+
+/* handy wrapper to read one xml file.
+ * return root element else NULL with report in errmsg[]
+ */
+XMLEle *
+readXMLFile (FILE *fp, LilXML *lp, char errmsg[])
+{
+	int c;
+
+	while ((c = fgetc(fp)) != EOF) {
+	    XMLEle *root = readXMLEle (lp, c, errmsg);
+	    if (root || errmsg[0])
+		return (root);
+	}
+
+	return (NULL);
+}
+
+/* add an element with the given tag to the given element.
+ * parent can be NULL to make a new root.
+ */
+XMLEle *
+addXMLEle (XMLEle *parent, const char *tag)
+{
+	XMLEle *ep = growEle (parent);
+	appendString (&ep->tag, tag);
+	return (ep);
+}
+
+/* set the pcdata of the given element */
+void
+editXMLEle (XMLEle *ep, const char *pcdata)
+{
+	freeString (&ep->pcdata);
+	appendString (&ep->pcdata, pcdata);
+	ep->pcdata_hasent = (strpbrk (pcdata, entities) != NULL);
+}
+
+/* add an attribute to the given XML element */
+XMLAtt *
+addXMLAtt (XMLEle *ep, const char *name, const char *valu)
+{
+	XMLAtt *ap = growAtt (ep);
+	appendString (&ap->name, name);
+	appendString (&ap->valu, valu);
+	return (ap);
+}
+
+/* remove the named attribute from ep, if any */
+void
+rmXMLAtt (XMLEle *ep, const char *name)
+{
+	int i;
+
+	for (i = 0; i < ep->nat; i++) {
+	    if (strcmp (ep->at[i]->name.s, name) == 0) {
+		freeAtt (ep->at[i]);
+		memmove (&ep->at[i],&ep->at[i+1],(--ep->nat-i)*sizeof(XMLAtt*));
+		return;
+	    }
+	}
+}
+
+/* change the value of an attribute to str */
+void
+editXMLAtt (XMLAtt *ap, const char *str)
+{
+	freeString (&ap->valu);
+	appendString (&ap->valu, str);
+}
+
+/* sample print ep to fp
+ * N.B. set level = 0 on first call
+ */
+#define	PRINDENT	4		/* sample print indent each level */
+void
+prXMLEle (FILE *fp, XMLEle *ep, int level)
+{
+	int indent = level*PRINDENT;
+	int i;
+
+	fprintf (fp, "%*s<%s", indent, "", ep->tag.s);
+	for (i = 0; i < ep->nat; i++)
+	    fprintf (fp, " %s=\"%s\"", ep->at[i]->name.s,
+						entityXML(ep->at[i]->valu.s));
+	if (ep->nel > 0) {
+	    fprintf (fp, ">\n");
+	    for (i = 0; i < ep->nel; i++)
+		prXMLEle (fp, ep->el[i], level+1);
+	}
+	if (ep->pcdata.sl > 0) {
+	    if (ep->nel == 0)
+		fprintf (fp, ">\n");
+	    if (ep->pcdata_hasent)
+		fprintf (fp, "%s", entityXML(ep->pcdata.s));
+	    else
+		fprintf (fp, "%s", ep->pcdata.s);
+	    if (ep->pcdata.s[ep->pcdata.sl-1] != '\n')
+		fprintf (fp, "\n");
+	}
+	if (ep->nel > 0 || ep->pcdata.sl > 0)
+	    fprintf (fp, "%*s</%s>\n", indent, "", ep->tag.s);
+	else
+	    fprintf (fp, "/>\n");
+}
+
+/* sample print ep to string s.
+ * N.B. s must be at least as large as that reported by sprlXMLEle()+1.
+ * N.B. set level = 0 on first call
+ * return length of resulting string (sans trailing \0)
+ */
+int
+sprXMLEle (char *s, XMLEle *ep, int level)
+{
+	int indent = level*PRINDENT;
+	int sl = 0;
+	int i;
+
+	sl += sprintf (s+sl, "%*s<%s", indent, "", ep->tag.s);
+	for (i = 0; i < ep->nat; i++)
+	    sl += sprintf (s+sl, " %s=\"%s\"", ep->at[i]->name.s,
+						entityXML(ep->at[i]->valu.s));
+	if (ep->nel > 0) {
+	    sl += sprintf (s+sl, ">\n");
+	    for (i = 0; i < ep->nel; i++)
+		sl += sprXMLEle (s+sl, ep->el[i], level+1);
+	}
+	if (ep->pcdata.sl > 0) {
+	    if (ep->nel == 0)
+		sl += sprintf (s+sl, ">\n");
+	    if (ep->pcdata_hasent)
+		sl += sprintf (s+sl, "%s", entityXML(ep->pcdata.s));
+	    else {
+		strcpy (s+sl, ep->pcdata.s);
+		sl += ep->pcdata.sl;
+	    }
+	    if (ep->pcdata.s[ep->pcdata.sl-1] != '\n')
+		sl += sprintf (s+sl, "\n");
+	}
+	if (ep->nel > 0 || ep->pcdata.sl > 0)
+	    sl += sprintf (s+sl, "%*s</%s>\n", indent, "", ep->tag.s);
+	else
+	    sl += sprintf (s+sl, "/>\n");
+
+	return (sl);
+}
+
+/* return number of bytes in a string guaranteed able to hold result of
+ * sprXLMEle(ep) (sans trailing \0).
+ * N.B. set level = 0 on first call
+ */
+int
+sprlXMLEle (XMLEle *ep, int level)
+{
+	int indent = level*PRINDENT;
+	int l = 0;
+	int i;
+
+	l += indent + 1 + ep->tag.sl;
+	for (i = 0; i < ep->nat; i++)
+	    l += ep->at[i]->name.sl + 4 + strlen(entityXML(ep->at[i]->valu.s));
+
+	if (ep->nel > 0) {
+	    l += 2;
+	    for (i = 0; i < ep->nel; i++)
+		l += sprlXMLEle (ep->el[i], level+1);
+	}
+	if (ep->pcdata.sl > 0) {
+	    if (ep->nel == 0)
+		l += 2;
+	    if (ep->pcdata_hasent)
+		l += strlen (entityXML(ep->pcdata.s));
+	    else
+		l += ep->pcdata.sl;
+	    if (ep->pcdata.s[ep->pcdata.sl-1] != '\n')
+		l += 1;
+	}
+	if (ep->nel > 0 || ep->pcdata.sl > 0)
+	    l += indent + 4 + ep->tag.sl;
+	else
+	    l += 3;
+
+	return (l);
+}
+
+/* return a string with all xml-sensitive characters within the passed string s
+ * replaced with their entity sequence equivalents.
+ * N.B. caller must use the returned string before calling us again.
+ */
+char *
+entityXML (char *s)
+{
+	static char *malbuf;
+	int nmalbuf = 0;
+	char *sret;
+	char *ep;
+
+	/* scan for each entity, if any */
+	for (sret = s; (ep = strpbrk (s, entities)) != NULL; s = ep+1) {
+
+	    /* found another entity, copy preceding to malloced buffer */
+	    int nnew = ep - s;			/* all but entity itself */
+	    sret = malbuf = moremem (malbuf, nmalbuf + nnew + 10);
+	    memcpy (malbuf+nmalbuf, s, nnew);
+	    nmalbuf += nnew;
+
+	    /* replace with entity encoding */
+	    switch (*ep) {
+	    case '&':
+		nmalbuf += sprintf (malbuf+nmalbuf, "&amp;");
+		break;
+	    case '<':
+		nmalbuf += sprintf (malbuf+nmalbuf, "&lt;");
+		break;
+	    case '>':
+		nmalbuf += sprintf (malbuf+nmalbuf, "&gt;");
+		break;
+	    case '\'':
+		nmalbuf += sprintf (malbuf+nmalbuf, "&apos;");
+		break;
+	    case '"':
+		nmalbuf += sprintf (malbuf+nmalbuf, "&quot;");
+		break;
+
+	    }
+
+	}
+
+	/* return s if no entities, else malloc cleaned-up copy */
+	if (sret == s) {
+	    /* using s, so free any malloced memory from last time */
+	    if (malbuf) {
+		free (malbuf);
+		malbuf = NULL;
+	    }
+	} else {
+	    /* put remaining part of s into malbuf */
+	    int nleft = strlen (s) + 1;		/* include \0 */
+	    sret = malbuf = moremem (malbuf, nmalbuf + nleft);
+	    memcpy (malbuf+nmalbuf, s, nleft);
+	}
+
+	return (sret);
+}
+
+/* if ent is a recognized xml entity sequence, set *cp to char and return 1
+ * else return 0
+ */
+static int
+decodeEntity (char *ent, int *cp)
+{
+	static struct {
+	    const char *ent;
+	    char c;
+	} enttable[] = {
+	    {"&amp;",  '&'},
+	    {"&apos;", '\''},
+	    {"&lt;",   '<'},
+	    {"&gt;",   '>'},
+	    {"&quot;", '"'},
+	};
+	unsigned int i;
+
+	for (i = 0; i < sizeof(enttable)/sizeof(enttable[0]); i++) {
+	    if (strcmp (ent, enttable[i].ent) == 0) {
+		*cp = enttable[i].c;
+		return (1);
+	    }
+	}
+	
+	return (0);
+}
+
+/* process one more char in XML file.
+ * if find final closure, return 1 and tree is in ce.
+ * if need more, return 0.
+ * if real trouble, return -1 and put reason in errmsg.
+ */
+static int
+oneXMLchar (LilXML *lp, int c, char errmsg[])
+{
+	switch (lp->cs) {
+	case LOOK4START:		/* looking for first element start */
+	    if (c == '<') {
+		pushXMLEle(lp);
+		lp->cs = LOOK4TAG;
+	    }
+	    /* silently ignore until resync */
+	    break;
+
+	case LOOK4TAG:			/* looking for element tag */
+	    if (isTokenChar (1, c)) {
+		growString (&lp->ce->tag, c);
+		lp->cs = INTAG;
+	    } else if (!isspace(c)) {
+		sprintf (errmsg, "Line %d: Bogus tag char %c", lp->ln, c);
+		return (-1);
+	    }
+	    break;
+		
+	case INTAG:			/* reading tag */
+	    if (isTokenChar (0, c))
+		growString (&lp->ce->tag, c);
+	    else if (c == '>')
+		lp->cs = LOOK4CON;
+	    else if (c == '/')
+		lp->cs = SAWSLASH;
+	    else 
+		lp->cs = LOOK4ATTRN;
+	    break;
+
+	case LOOK4ATTRN:		/* looking for attr name, > or / */
+	    if (c == '>')
+		lp->cs = LOOK4CON;
+	    else if (c == '/')
+		lp->cs = SAWSLASH;
+	    else if (isTokenChar (1, c)) {
+		XMLAtt *ap = growAtt(lp->ce);
+		growString (&ap->name, c);
+		lp->cs = INATTRN;
+	    } else if (!isspace(c)) {
+		sprintf (errmsg, "Line %d: Bogus leading attr name char: %c",
+								    lp->ln, c);
+		return (-1);
+	    }
+	    break;
+
+	case SAWSLASH:			/* saw / in element opening */
+	    if (c == '>') {
+		if (!lp->ce->pe)
+		    return(1);		/* root has no content */
+		popXMLEle(lp);
+		lp->cs = LOOK4CON;
+	    } else {
+		sprintf (errmsg, "Line %d: Bogus char %c before >", lp->ln, c);
+		return (-1);
+	    }
+	    break;
+		
+	case INATTRN:			/* reading attr name */
+	    if (isTokenChar (0, c))
+		growString (&lp->ce->at[lp->ce->nat-1]->name, c);
+	    else if (isspace(c) || c == '=')
+		lp->cs = LOOK4ATTRV;
+	    else {
+		sprintf (errmsg, "Line %d: Bogus attr name char: %c", lp->ln,c);
+		return (-1);
+	    }
+	    break;
+
+	case LOOK4ATTRV:		/* looking for attr value */
+	    if (c == '\'' || c == '"') {
+		lp->delim = c;
+		lp->cs = INATTRV;
+	    } else if (!(isspace(c) || c == '=')) {
+		sprintf (errmsg, "Line %d: No value for attribute %s", lp->ln,
+					lp->ce->at[lp->ce->nat-1]->name.s);
+		return (-1);
+	    }
+	    break;
+
+	case INATTRV:			/* in attr value */
+	    if (c == '&') {
+		newString (&lp->entity);
+		growString (&lp->entity, c);
+		lp->cs = ENTINATTRV;
+	    } else if (c == lp->delim)
+		lp->cs = LOOK4ATTRN;
+	    else if (!iscntrl(c))
+		growString (&lp->ce->at[lp->ce->nat-1]->valu, c);
+	    break;
+
+	case ENTINATTRV:		/* working on entity in attr valu */
+	    if (c == ';') {
+		/* if find a recongized esp seq, add equiv char else raw seq */
+		growString (&lp->entity, c);
+		if (decodeEntity (lp->entity.s, &c))
+		    growString (&lp->ce->at[lp->ce->nat-1]->valu, c);
+		else
+		    appendString(&lp->ce->at[lp->ce->nat-1]->valu,lp->entity.s);
+		freeString (&lp->entity);
+		lp->cs = INATTRV;
+	    } else
+		growString (&lp->entity, c);
+	    break;
+
+	case LOOK4CON:			/* skipping leading content whitespace*/
+	    if (c == '<')
+		lp->cs = SAWLTINCON;
+	    else if (!isspace(c)) {
+		growString (&lp->ce->pcdata, c);
+		lp->cs = INCON;
+	    }
+	    break;
+
+	case INCON:			/* reading content */
+	    if (c == '&') {
+		newString (&lp->entity);
+		growString (&lp->entity, c);
+		lp->cs = ENTINCON;
+	    } else if (c == '<') {
+		/* chomp trailing whitespace */
+		while (lp->ce->pcdata.sl > 0 &&
+			    isspace(lp->ce->pcdata.s[lp->ce->pcdata.sl-1]))
+		    lp->ce->pcdata.s[--(lp->ce->pcdata.sl)] = '\0';
+		lp->cs = SAWLTINCON;
+	    } else {
+		growString (&lp->ce->pcdata, c);
+	    }
+	    break;
+
+	case ENTINCON:			/* working on entity in content */
+	    if (c == ';') {
+		/* if find a recognized esc seq, add equiv char else raw seq */
+		growString (&lp->entity, c);
+		if (decodeEntity (lp->entity.s, &c))
+		    growString (&lp->ce->pcdata, c);
+		else {
+		    appendString(&lp->ce->pcdata, lp->entity.s);
+		    lp->ce->pcdata_hasent = 1;
+		}
+		freeString (&lp->entity);
+		lp->cs = INCON;
+	    } else
+		growString (&lp->entity, c);
+	    break;
+
+	case SAWLTINCON:		/* saw < in content */
+	    if (c == '/') {
+		resetEndTag(lp);
+		lp->cs = LOOK4CLOSETAG;
+	    } else {
+		pushXMLEle(lp);
+		if (isTokenChar(1,c)) {
+		    growString (&lp->ce->tag, c);
+		    lp->cs = INTAG;
+		} else
+		    lp->cs = LOOK4TAG;
+	    }
+	    break;
+
+	case LOOK4CLOSETAG:		/* looking for closing tag after < */
+	    if (isTokenChar (1, c)) {
+		growString (&lp->endtag, c);
+		lp->cs = INCLOSETAG;
+	    } else if (!isspace(c)) {
+		sprintf (errmsg, "Line %d: Bogus preend tag char %c", lp->ln,c);
+		return (-1);
+	    }
+	    break;
+
+	case INCLOSETAG:		/* reading closing tag */
+	    if (isTokenChar(0, c))
+		growString (&lp->endtag, c);
+	    else if (c == '>') {
+		if (strcmp (lp->ce->tag.s, lp->endtag.s)) {
+		    sprintf (errmsg,"Line %d: closing tag %s does not match %s",
+				    lp->ln, lp->endtag.s, lp->ce->tag.s);
+		    return (-1);
+		} else if (lp->ce->pe) {
+		    popXMLEle(lp);
+		    lp->cs = LOOK4CON;	/* back to content after nested elem */
+		} else
+		    return (1);		/* yes! */
+	    } else if (!isspace(c)) {
+		sprintf (errmsg, "Line %d: Bogus end tag char %c", lp->ln, c);
+		return (-1);
+	    }
+	    break;
+	}
+
+	return (0);
+}
+
+/* set up for a fresh start again */
+static void
+initParser(LilXML *lp)
+{
+	delXMLEle (lp->ce);
+	freeString (&lp->endtag);
+	memset (lp, 0, sizeof(*lp));
+	newString (&lp->endtag);
+	lp->cs = LOOK4START;
+	lp->ln = 1;
+}
+
+/* start a new XMLEle.
+ * point ce to a new XMLEle.
+ * if ce already set up, add to its list of child elements too.
+ * endtag no longer valid.
+ */
+static void
+pushXMLEle(LilXML *lp)
+{
+	lp->ce = growEle (lp->ce);
+	resetEndTag(lp);
+}
+
+/* point ce to parent of current ce.
+ * endtag no longer valid.
+ */
+static void
+popXMLEle(LilXML *lp)
+{
+	lp->ce = lp->ce->pe;
+	resetEndTag(lp);
+}
+
+/* return one new XMLEle, added to the given element if given */
+static XMLEle *
+growEle (XMLEle *pe)
+{
+	XMLEle *newe = (XMLEle *) moremem (NULL, sizeof(XMLEle));
+
+	memset (newe, 0, sizeof(XMLEle));
+	newString (&newe->tag);
+	newString (&newe->pcdata);
+	newe->pe = pe;
+
+	if (pe) {
+	    pe->el = (XMLEle **) moremem (pe->el, (pe->nel+1)*sizeof(XMLEle *));
+	    pe->el[pe->nel++] = newe;
+	}
+
+	return (newe);
+}
+
+/* add room for and return one new XMLAtt to the given element */
+static XMLAtt *
+growAtt(XMLEle *ep)
+{
+	XMLAtt *newa = (XMLAtt *) moremem (NULL, sizeof(XMLAtt));
+
+	memset (newa, 0, sizeof(*newa));
+	newString(&newa->name);
+	newString(&newa->valu);
+	newa->ce = ep;
+
+	ep->at = (XMLAtt **) moremem (ep->at, (ep->nat+1)*sizeof(XMLAtt *));
+	ep->at[ep->nat++] = newa;
+
+	return (newa);
+}
+
+/* free a and all it holds */
+static void
+freeAtt (XMLAtt *a)
+{
+	if (!a)
+	    return;
+	freeString (&a->name);
+	freeString (&a->valu);
+	(*myfree)(a);
+}
+
+/* reset endtag */
+static void
+resetEndTag(LilXML *lp)
+{
+	freeString (&lp->endtag);
+	newString (&lp->endtag);
+}
+
+/* 1 if c is a valid token character, else 0.
+ * it can be alpha or '_' or numeric unless start.
+ */
+static int
+isTokenChar (int start, int c)
+{
+	return (isalpha(c) || c == '_' || (!start && isdigit(c)));
+}
+
+/* grow the String storage at *sp to append c */
+static void
+growString (String *sp, int c)
+{
+	int l = sp->sl + 2;		/* need room for '\0' plus c */
+
+	if (l > sp->sm) {
+	    if (!sp->s)
+		newString (sp);
+	    else
+		sp->s = (char *) moremem (sp->s, sp->sm *= 2);
+	}
+	sp->s[--l] = '\0';
+	sp->s[--l] = (char)c;
+	sp->sl++;
+}
+
+/* append str to the String storage at *sp */
+static void
+appendString (String *sp, const char *str)
+{
+	int strl = strlen (str);
+	int l = sp->sl + strl + 1;	/* need room for '\0' */
+
+	if (l > sp->sm) {
+	    if (!sp->s)
+		newString (sp);
+	    if (l > sp->sm)
+		sp->s = (char *) moremem (sp->s, (sp->sm = l));
+	}
+	strcpy (&sp->s[sp->sl], str);
+	sp->sl += strl;		
+}
+
+/* init a String with a malloced string containing just \0 */
+static void
+newString(String *sp)
+{
+	sp->s = (char *)moremem(NULL, MINMEM);
+	sp->sm = MINMEM;
+	*sp->s = '\0';
+	sp->sl = 0;
+}
+
+/* free memory used by the given String */
+static void
+freeString (String *sp)
+{
+	if (sp->s)
+	    (*myfree) (sp->s);
+	sp->s = NULL;
+	sp->sl = 0;
+	sp->sm = 0;
+}
+
+/* like malloc but knows to use realloc if already started */
+static void *
+moremem (void *old, int n)
+{
+	return (old ? (*myrealloc)(old, n) : (*mymalloc)(n));
+}
+
+#if defined(MAIN_TST)
+int
+main (int ac, char *av[])
+{
+	LilXML *lp = newLilXML();
+	char errmsg[1024];
+	XMLEle *root;
+
+	root = readXMLFile (stdin, lp, errmsg);
+	if (root) {
+	    char *str;
+	    int l;
+
+	    if (ac > 1) {
+		XMLEle *theend = addXMLEle (root, "theend");
+		editXMLEle (theend, "Added to test editing");
+		addXMLAtt (theend, "hello", "world");
+	    }
+
+	    fprintf (stderr, "::::::::::::: %s\n", tagXMLEle(root));
+	    prXMLEle (stdout, root, 0);
+
+	    l = sprlXMLEle (root, 0);
+	    str = malloc (l+1);
+	    fprintf (stderr, "::::::::::::: %s : %d : %d",
+				tagXMLEle(root), l, sprXMLEle (str, root, 0));
+	    fprintf (stderr, ": %d\n", printf ("%s", str));
+
+	    delXMLEle (root);
+	} else if (errmsg[0]) {
+	    fprintf (stderr, "Error: %s\n", errmsg);
+	}
+
+	delLilXML (lp);
+
+	return (0);
+}
+#endif
+
Index: /BAORadio/libindi/v1/libs/lilxml.h
===================================================================
--- /BAORadio/libindi/v1/libs/lilxml.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/lilxml.h	(revision 500)
@@ -0,0 +1,302 @@
+#if 0
+    liblilxml
+    Copyright (C) 2003 Elwood C. Downey
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+#endif
+
+/** \file lilxml.h
+    \brief A little DOM-style library to handle parsing and processing an XML file.
+    
+    It only handles elements, attributes and pcdata content. <! ... > and <? ... > are silently ignored. pcdata is collected into one string, sans leading whitespace first line. \n
+    
+    The following is an example of a cannonical usage for the lilxml library. Initialize a lil xml context and read an XML file in a root element.
+    
+    \code
+    
+    #include <lilxml.h>
+    
+    LilXML *lp = newLilXML();
+	char errmsg[1024];
+	XMLEle *root, *ep;
+	int c;
+
+	while ((c = fgetc(stdin)) != EOF) {
+	    root = readXMLEle (lp, c, errmsg);
+	    if (root)
+		break;
+	    if (errmsg[0])
+		error ("Error: %s\n", errmsg);
+	}
+ 
+        // print the tag and pcdata content of each child element within the root 
+
+        for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0))
+	    printf ("%s: %s\n", tagXMLEle(ep), pcdataXMLEle(ep));
+
+
+	// finished with root element and with lil xml context
+
+	delXMLEle (root);
+	delLilXML (lp);
+	
+     \endcode
+    
+ */
+
+#ifndef LILXML_H
+#define LILXML_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* opaque handle types */
+typedef struct _xml_att XMLAtt;
+typedef struct _xml_ele XMLEle;
+typedef struct _LilXML LilXML;
+
+/**
+ * \defgroup lilxmlFunctions XML Functions: Functions to parse, process, and search XML.
+ */
+/*@{*/
+
+/* creation and destruction functions */
+
+/** \brief Create a new lilxml parser.
+    \return a pointer to the lilxml parser on success. NULL on failure.
+*/
+extern LilXML *newLilXML(void);
+
+/** \brief Delete a lilxml parser.
+    \param lp a pointer to a lilxml parser to be deleted.
+*/
+extern void delLilXML (LilXML *lp);
+
+/** \brief Delete an XML element.
+    \return a pointer to the XML Element to be deleted.
+*/
+extern void delXMLEle (XMLEle *e);
+
+/** \brief Process an XML one char at a time.
+    \param lp a pointer to a lilxml parser.
+    \param c one character to process.
+    \param errmsg a buffer to store error messages if an error in parsing is encounterd.
+    \return When the function parses a complete valid XML element, it will return a pointer to the XML element. A NULL is returned when parsing the element is still in progress, or if a parsing error occurs. Check errmsg for errors if NULL is returned. 
+ */
+extern XMLEle *readXMLEle (LilXML *lp, int c, char errmsg[]);
+
+/* search functions */
+/** \brief Find an XML attribute within an XML element.
+    \param e a pointer to the XML element to search.
+    \param name the attribute name to search for.
+    \return A pointer to the XML attribute if found or NULL on failure.
+*/
+extern XMLAtt *findXMLAtt (XMLEle *e, const char *name);
+
+/** \brief Find an XML element within an XML element.
+    \param e a pointer to the XML element to search.
+    \param tag the element tag to search for.
+    \return A pointer to the XML element if found or NULL on failure.
+*/
+extern XMLEle *findXMLEle (XMLEle *e, const char *tag);
+
+/* iteration functions */
+/** \brief Iterate an XML element for a list of nesetd XML elements.
+    \param ep a pointer to the XML element to iterate.
+    \param first the index of the starting XML element. Pass 1 to start iteration from the beginning of the XML element. Pass 0 to get the next element thereater. 
+    \return On success, a pointer to the next XML element is returned. NULL when there are no more elements.
+*/
+extern XMLEle *nextXMLEle (XMLEle *ep, int first);
+
+/** \brief Iterate an XML element for a list of XML attributes.
+    \param ep a pointer to the XML element to iterate.
+    \param first the index of the starting XML attribute. Pass 1 to start iteration from the beginning of the XML element. Pass 0 to get the next attribute thereater. 
+    \return On success, a pointer to the next XML attribute is returned. NULL when there are no more attributes.
+*/
+extern XMLAtt *nextXMLAtt (XMLEle *ep, int first);
+
+/* tree functions */
+/** \brief Return the parent of an XML element.
+    \return a pointer to the XML element parent.
+*/
+extern XMLEle *parentXMLEle (XMLEle *ep);
+
+/** \brief Return the parent of an XML attribute.
+    \return a pointer to the XML element parent.
+*/
+extern XMLEle *parentXMLAtt (XMLAtt *ap);
+
+/* access functions */
+/** \brief Return the tag of an XML element.
+    \param ep a pointer to an XML element.
+    \return the tag string.
+*/
+extern char *tagXMLEle (XMLEle *ep);
+
+/** \brief Return the pcdata of an XML element.
+    \param ep a pointer to an XML element.
+    \return the pcdata string on success.
+*/
+extern char *pcdataXMLEle (XMLEle *ep);
+
+/** \brief Return the name of an XML attribute.
+    \param ap a pointer to an XML attribute.
+    \return the name string of the attribute.
+*/
+extern char *nameXMLAtt (XMLAtt *ap);
+
+/** \brief Return the value of an XML attribute.
+    \param ap a pointer to an XML attribute.
+    \return the value string of the attribute.
+*/
+extern char *valuXMLAtt (XMLAtt *ap);
+
+/** \brief Return the number of characters in pcdata in an XML element.
+    \param ep a pointer to an XML element.
+    \return the length of the pcdata string.
+*/
+extern int pcdatalenXMLEle (XMLEle *ep);
+
+/** \brief Return the number of nested XML elements in a parent XML element.
+    \param ep a pointer to an XML element.
+    \return the number of nested XML elements.
+*/
+extern int nXMLEle (XMLEle *ep);
+
+/** \brief Return the number of XML attributes in a parent XML element.
+    \param ep a pointer to an XML element.
+    \return the number of XML attributes within the XML element.
+*/
+extern int nXMLAtt (XMLEle *ep);
+
+/* editing functions */
+/** \brief add an element with the given tag to the given element. parent can be NULL to make a new root.
+    \return if parent is NULL, a new root is returned, otherwise, parent is returned.
+*/
+extern XMLEle *addXMLEle (XMLEle *parent, const char *tag);
+
+/** \brief set the pcdata of the given element
+    \param ep pointer to an XML element.
+    \param pcdata pcdata to set.
+*/
+extern void editXMLEle (XMLEle *ep, const char *pcdata);
+
+/** \brief Add an XML attribute to an existing XML element.
+    \param ep pointer to an XML element
+    \param name the name of the XML attribute to add.
+    \param value the value of the XML attribute to add.
+*/
+extern XMLAtt* addXMLAtt (XMLEle *ep, const char *name, const char *value);
+
+/** \brief Remove an XML attribute from an XML element.
+    \param ep pointer to an XML element.
+    \param name the name of the XML attribute to remove
+*/
+extern void rmXMLAtt (XMLEle *ep, const char *name);
+
+/** \brief change the value of an attribute to str.
+*   \param ap pointer to XML attribute
+*   \param str new attribute value
+*/
+extern void editXMLAtt (XMLAtt *ap, const char *str);
+
+/** \brief return a string with all xml-sensitive characters within the passed string replaced with their entity sequence equivalents.
+*   N.B. caller must use the returned string before calling us again.
+*/
+extern char *entityXML (char *str);
+
+/* convenience functions */
+/** \brief Find an XML element's attribute value.
+    \param ep a pointer to an XML element.
+    \param name the name of the XML attribute to retrieve its value.
+    \return the value string of an XML element on success. NULL on failure.
+*/
+extern const char *findXMLAttValu (XMLEle *ep, const char *name);
+
+/** \brief Handy wrapper to read one xml file.
+    \param fp pointer to FILE to read.
+    \param lp pointer to lilxml parser.
+    \param errmsg a buffer to store error messages on failure.
+    \return root element else NULL with report in errmsg[].
+*/
+extern XMLEle *readXMLFile (FILE *fp, LilXML *lp, char errmsg[]);
+
+/** \brief Print an XML element.
+    \param fp a pointer to FILE where the print output is directed.
+    \param e the XML element to print.
+    \param level the printing level, set to 0 to print the whole element.
+*/
+extern void prXMLEle (FILE *fp, XMLEle *e, int level);
+
+/** \brief sample print ep to string s.
+*   N.B. s must be at least as large as that reported by sprlXMLEle()+1.
+*   N.B. set level = 0 on first call.
+*   \return return length of resulting string (sans trailing \0)
+*/
+extern int sprXMLEle (char *s, XMLEle *ep, int level);
+
+/** \brief return number of bytes in a string guaranteed able to hold result of sprXLMEle(ep) (sans trailing \0).
+*   N.B. set level = 0 on first call.
+*/
+extern int sprlXMLEle (XMLEle *ep, int level);
+
+/* install alternatives to malloc/realloc/free */
+extern void indi_xmlMalloc (void *(*newmalloc)(size_t size),
+    void *(*newrealloc)(void *ptr, size_t size), void (*newfree)(void *ptr));
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+/* examples.
+
+        initialize a lil xml context and read an XML file in a root element
+
+	LilXML *lp = newLilXML();
+	char errmsg[1024];
+	XMLEle *root, *ep;
+	int c;
+
+	while ((c = fgetc(stdin)) != EOF) {
+	    root = readXMLEle (lp, c, errmsg);
+	    if (root)
+		break;
+	    if (errmsg[0])
+		error ("Error: %s\n", errmsg);
+	}
+ 
+        print the tag and pcdata content of each child element within the root
+
+        for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0))
+	    printf ("%s: %s\n", tagXMLEle(ep), pcdataXMLEle(ep));
+
+
+	finished with root element and with lil xml context
+
+	delXMLEle (root);
+	delLilXML (lp);
+ */
+
+/* For RCS Only -- Do Not Edit
+ * @(#) $RCSfile$ $Date: 2007-09-17 16:34:48 +0300 (Mon, 17 Sep 2007) $ $Revision: 713418 $ $Name:  $
+ */
+
+#endif	/* LILXML_H */
Index: /BAORadio/libindi/v1/libs/webcam/PPort.cpp
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/PPort.cpp	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/PPort.cpp	(revision 500)
@@ -0,0 +1,111 @@
+/*
+   Copyright (C) 1996-1998 by Patrick Reynolds
+   Email: <no.email@noemail.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "PPort.h"
+#include "port.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <iostream>
+
+using namespace std;
+
+#define TEST_VALIDITY {if (this==NULL) return false;}
+
+PPort::PPort() {
+   reset();
+}
+
+PPort::PPort(int ioPort) {
+   reset();
+   setPort(ioPort);
+}
+
+PPort::~PPort()
+{
+    delete currentPort;
+}
+
+void PPort::reset() {
+   bitArray=0;
+   for (int i=0;i<8;++i) {
+      assignedBit[i]=NULL;
+   }
+   currentPort=NULL;
+}
+
+bool PPort::setPort(int ioPort) {
+   TEST_VALIDITY;
+   if (geteuid() != 0) {
+      cerr << "must be setuid root control parallel port"<<endl;
+      return false;
+   }
+   delete currentPort;
+   reset();
+   currentPort=new port_t(ioPort);
+   return commit();
+}
+
+bool PPort::commit() {
+   TEST_VALIDITY;
+   if (currentPort) {
+      currentPort->write_data(bitArray);
+      return true;
+   } else {
+      return false;
+   }
+}
+
+bool  PPort::setBit(const void * ID,int bit,bool stat) {
+   TEST_VALIDITY;
+   if (ID != assignedBit[bit]) {
+      return false;
+   }
+
+   if (stat) {
+      bitArray |= (1<<bit);
+   } else {
+      bitArray &= ~(1<<bit);
+   }
+   return true;
+}
+
+bool PPort::registerBit(const void * ID,int bit) {
+   TEST_VALIDITY;
+   if (assignedBit[bit] || currentPort==NULL) {
+      return false;
+   }
+   assignedBit[bit]=ID;
+   return true;
+}
+
+bool PPort::unregisterBit(const void * ID,int bit) {
+   TEST_VALIDITY;
+   if (assignedBit[bit] != ID) {
+      return false;
+   }
+   assignedBit[bit]=NULL;
+   return true;
+}
+
+bool PPort::isRegisterBit(const void * ID,int bit) const {
+   TEST_VALIDITY;
+   return (assignedBit[bit] == ID);
+}
Index: /BAORadio/libindi/v1/libs/webcam/PPort.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/PPort.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/PPort.h	(revision 500)
@@ -0,0 +1,76 @@
+/*
+    Copyright (C) 2004 by Jasem Mutlaq
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _PPort_hpp_
+#define _PPort_hpp_
+
+class port_t;
+
+/** To access and share the parallel port
+    between severa objects. */
+class PPort {
+public:
+   PPort();
+   PPort(int ioPort);
+   ~PPort();
+   /** set the ioport associated to the // port.
+       \return true if the binding was possible
+   */
+   bool setPort(int ioPort);
+   /** set a data bit of the // port.
+       \return false if IO port not set, or bit not registered by ID.
+       \param ID the identifier used to register the bit
+       \param stat the stat wanted for the given bit
+       \param bit the bit to set. They are numbered from 0 to 7.
+
+   */
+   bool setBit(const void * ID,int bit,bool stat);
+   /** register a bit for object ID.
+       \param ID the identifier used to register the bit it should be the 'this' pointer.
+       \param bit the bit of the // port to register
+       \return false if the bit is already register with an
+               other ID, or if the // port is not initialised.
+   */
+   bool registerBit(const void * ID,int bit);
+   /** release a bit.
+       \param ID the identifier used to register the bit
+       \param bit the bit to register.
+       \return false if the bit was not registered by ID or
+               if the if the // port is not initialised.
+   */
+   bool unregisterBit(const void * ID,int bit);
+
+   /** test if a bit is registerd.
+       \param ID the identifier used to register the bit
+       \param bit the bit to test.
+       \return false if the bit was not registered by ID or
+               if the if the // port is not initialised.
+   */
+   bool isRegisterBit(const void * ID,int bit) const;
+   
+   /** set the bits off the // port according to previous call to setBit().
+    */
+   bool commit();
+private:
+   void reset();
+   unsigned char bitArray;
+   const void * assignedBit[8];
+   port_t * currentPort;
+};
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/ccvt.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/ccvt.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/ccvt.h	(revision 500)
@@ -0,0 +1,165 @@
+/*  CCVT: ColourConVerT: simple library for converting colourspaces
+    Copyright (C) 2002 Nemosoft Unv.
+    Email:athomas@nemsoft.co.uk
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    For questions, remarks, patches, etc. for this program, the author can be
+    reached at nemosoft@smcc.demon.nl.
+*/
+
+/* 
+ $Log$
+ Revision 1.4  2005/04/29 16:51:20  mutlaqja
+ Adding initial support for Video 4 Linux 2 drivers. This mean that KStars can probably control Meade Lunar Planetary Imager (LPI). V4L2 requires a fairly recent kernel (> 2.6.9) and many drivers don't fully support it yet. It will take sometime. KStars still supports V4L1 and will continue so until V4L1 is obselete. Please test KStars video drivers if you can. Any comments welcomed.
+
+ CCMAIL: kstars-devel@kde.org
+
+ Revision 1.3  2004/06/26 23:12:03  mutlaqja
+ Hopefully this will fix compile issues on 64bit archs, and FreeBSD, among others. The assembly code is replaced with a more portable, albeit slower C implementation. I imported the videodev.h header after cleaning it for user space.
+
+ Anyone who has problems compiling this, please report the problem to kstars-devel@kde.org
+
+ I noticed one odd thing after updating my kdelibs, the LEDs don't change color when state is changed. Try that by starting any INDI device, and hit connect, if the LED turns to yellow and back to grey then it works fine, otherwise, we've got a problem.
+
+ CCMAIL: kstars-devel@kde.org
+
+ Revision 1.10  2003/10/24 16:55:18  nemosoft
+ removed erronous log messages
+
+ Revision 1.9  2002/11/03 22:46:25  nemosoft
+ Adding various RGB to RGB functions.
+ Adding proper copyright header too.
+
+ Revision 1.8  2002/04/14 01:00:27  nemosoft
+ Finishing touches: adding const, adding libs for 'show'
+*/
+
+
+#ifndef CCVT_H
+#define CCVT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Colour ConVerT: going from one colour space to another.
+   ** NOTE: the set of available functions is far from complete! **
+
+   Format descriptions:
+   420i = "4:2:0 interlaced"
+           YYYY UU YYYY UU   even lines
+           YYYY VV YYYY VV   odd lines
+           U/V data is subsampled by 2 both in horizontal 
+           and vertical directions, and intermixed with the Y values.
+   
+   420p = "4:2:0 planar"
+           YYYYYYYY      N lines
+           UUUU          N/2 lines
+           VVVV          N/2 lines
+           U/V is again subsampled, but all the Ys, Us and Vs are placed
+           together in separate buffers. The buffers may be placed in
+           one piece of contiguous memory though, with Y buffer first,
+           followed by U, followed by V.
+
+   yuyv = "4:2:2 interlaced"
+           YUYV YUYV YUYV ...   N lines
+           The U/V data is subsampled by 2 in horizontal direction only.
+
+   bgr24 = 3 bytes per pixel, in the order Blue Green Red (whoever came up
+           with that idea...)
+   rgb24 = 3 bytes per pixel, in the order Red Green Blue (which is sensible)
+   rgb32 = 4 bytes per pixel, in the order Red Green Blue Alpha, with 
+           Alpha really being a filler byte (0)
+   bgr32 = last but not least, 4 bytes per pixel, in the order Blue Green Red
+           Alpha, Alpha again a filler byte (0)
+ */
+
+/* 4:2:0 YUV planar to RGB/BGR     */
+void ccvt_420p_bgr24(int width, int height, const void *src, void *dst);
+void ccvt_420p_rgb24(int width, int height, const void *src, void *dst);
+void ccvt_420p_bgr32(int width, int height, const void *src, void *dst);
+void ccvt_420p_rgb32(int width, int height, const void *src, void *dst);
+
+/* 4:2:2 YUYV interlaced to RGB/BGR */
+void ccvt_yuyv_rgb32(int width, int height, const void *src, void *dst);
+void ccvt_yuyv_bgr32(int width, int height, const void *src, void *dst);
+
+/* 4:2:2 YUYV interlaced to 4:2:0 YUV planar */
+void ccvt_yuyv_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv);
+
+/* RGB/BGR to 4:2:0 YUV interlaced */
+
+/* RGB/BGR to 4:2:0 YUV planar     */
+void ccvt_rgb24_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv);
+void ccvt_bgr24_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv);
+
+/* RGB/BGR to RGB/BGR */
+void ccvt_bgr24_bgr32(int width, int height, const void *const src, void *const dst);
+void ccvt_bgr24_rgb32(int width, int height, const void *const src, void *const dst);
+void ccvt_bgr32_bgr24(int width, int height, const void *const src, void *const dst);
+void ccvt_bgr32_rgb24(int width, int height, const void *const src, void *const dst);
+void ccvt_rgb24_bgr32(int width, int height, const void *const src, void *const dst);
+void ccvt_rgb24_rgb32(int width, int height, const void *const src, void *const dst);
+void ccvt_rgb32_bgr24(int width, int height, const void *const src, void *const dst);
+void ccvt_rgb32_rgb24(int width, int height, const void *const src, void *const dst);
+
+int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip);
+
+/*
+ * BAYER2RGB24 ROUTINE TAKEN FROM:
+ *
+ * Sonix SN9C101 based webcam basic I/F routines
+ * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
+
+#ifdef __cplusplus
+}
+#endif
+
+enum Options {
+      ioNoBlock=(1<<0),
+      ioUseSelect=(1<<1),
+      haveBrightness=(1<<2),
+      haveContrast=(1<<3),
+      haveHue=(1<<4),
+      haveColor=(1<<5),
+      haveWhiteness=(1<<6) };
+
+
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/ccvt_c2.c
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/ccvt_c2.c	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/ccvt_c2.c	(revision 500)
@@ -0,0 +1,134 @@
+/*  CCVT_C2: Convert an image from yuv colourspace to rgb 
+    Copyright (C) 2001 Tony Hague <no.email@noemail.com>
+
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    For questions, remarks, patches, etc. for this program, the author can be
+    reached at nemosoft@smcc.demon.nl.
+*/
+
+#include "ccvt.h"
+#include "ccvt_types.h"
+
+/* by suitable definition of PIXTYPE, can do yuv to rgb or bgr, with or
+without word alignment */
+
+/* This doesn't exactly earn a prize in a programming beauty contest. */
+
+#define WHOLE_FUNC2RGB(type) 			\
+	const unsigned char *y1, *y2, *u, *v; 	\
+	PIXTYPE_##type *l1, *l2;		\
+	int r, g, b, cr, cg, cb, yp, j, i;	\
+						\
+	if ((width & 1) || (height & 1))	\
+		return;				\
+						\
+	l1 = (PIXTYPE_##type *)dst;		\
+	l2 = l1 + width;			\
+	y1 = (unsigned char *)src;		\
+	y2 = y1 + width;			\
+	u = (unsigned char *)src + width * height;		\
+	v = u + (width * height) / 4;		\
+	j = height / 2;				\
+	while (j--) {				\
+		i = width / 2;			\
+		while (i--) {			\
+			/* Since U & V are valid for 4 pixels, repeat code 4 	\
+			   times for different Y */				\
+			cb = ((*u-128) * 454)>>8;				\
+			cr = ((*v-128) * 359)>>8;				\
+			cg = ((*v-128) * 183 + (*u-128) * 88)>>8;		\
+						\
+			yp = *(y1++);		\
+			r = yp + cr; 		\
+			b = yp + cb;		\
+			g = yp - cg;            \
+			SAT(r);                 \
+			SAT(g);                 \
+			SAT(b);                 \
+			l1->b = b;		\
+			l1->g = g;              \
+			l1->r = r;              \
+			l1++;                   \
+                                                \
+			yp = *(y1++);           \
+			r = yp + cr;            \
+			b = yp + cb;            \
+			g = yp - cg;            \
+			SAT(r);                 \
+			SAT(g);                 \
+			SAT(b);                 \
+			l1->b = b;		\
+			l1->g = g;		\
+			l1->r = r;		\
+			l1++;			\
+						\
+			yp = *(y2++);		\
+			r = yp + cr; 		\
+			b = yp + cb;		\
+			g = yp - cg;		\
+			SAT(r);			\
+			SAT(g);			\
+			SAT(b);			\
+			l2->b = b;		\
+			l2->g = g;		\
+			l2->r = r;		\
+			l2++;			\
+						\
+			yp = *(y2++);		\
+			r = yp + cr; 		\
+			b = yp + cb;		\
+			g = yp - cg;		\
+			SAT(r);			\
+			SAT(g);			\
+			SAT(b);			\
+			l2->b = b;		\
+			l2->g = g;		\
+			l2->r = r;		\
+			l2++;			\
+						\
+			u++;			\
+			v++;			\
+		}				\
+		y1 = y2;			\
+		y2 += width;			\
+		l1 = l2;			\
+		l2 += width;			\
+	}
+
+
+
+
+void ccvt_420p_bgr32(int width, int height, const void *src, void *dst)
+{
+	WHOLE_FUNC2RGB(bgr32)
+}
+
+void ccvt_420p_bgr24(int width, int height, const void *src, void *dst)
+{
+	WHOLE_FUNC2RGB(bgr24)
+}
+
+void ccvt_420p_rgb32(int width, int height, const void *src, void *dst)
+{
+	WHOLE_FUNC2RGB(rgb32)
+}
+
+void ccvt_420p_rgb24(int width, int height, const void *src, void *dst)
+{
+	WHOLE_FUNC2RGB(rgb24)
+}
+
Index: /BAORadio/libindi/v1/libs/webcam/ccvt_misc.c
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/ccvt_misc.c	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/ccvt_misc.c	(revision 500)
@@ -0,0 +1,436 @@
+/*  CCVT: ColourConVerT: simple library for converting colourspaces
+    Copyright (C) 2002 Nemosoft Unv.
+    Email:athomas@nemsoft.co.uk
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    For questions, remarks, patches, etc. for this program, the author can be
+    reached at nemosoft@smcc.demon.nl.
+*/
+
+/* This file contains CCVT functions that aren't available in assembly yet
+   (or are not worth programming)
+ */
+
+/* 
+ * $Log$
+ * Revision 1.2  2005/04/29 16:51:20  mutlaqja
+ * Adding initial support for Video 4 Linux 2 drivers. This mean that KStars can probably control Meade Lunar Planetary Imager (LPI). V4L2 requires a fairly recent kernel (> 2.6.9) and many drivers don't fully support it yet. It will take sometime. KStars still supports V4L1 and will continue so until V4L1 is obselete. Please test KStars video drivers if you can. Any comments welcomed.
+ *
+ * CCMAIL: kstars-devel@kde.org
+ *
+ * Revision 1.1  2004/06/26 23:12:03  mutlaqja
+ * Hopefully this will fix compile issues on 64bit archs, and FreeBSD, among others. The assembly code is replaced with a more portable, albeit slower C implementation. I imported the videodev.h header after cleaning it for user space.
+ *
+ * Anyone who has problems compiling this, please report the problem to kstars-devel@kde.org
+ *
+ * I noticed one odd thing after updating my kdelibs, the LEDs don't change color when state is changed. Try that by starting any INDI device, and hit connect, if the LED turns to yellow and back to grey then it works fine, otherwise, we've got a problem.
+ *
+ * CCMAIL: kstars-devel@kde.org
+ *
+ * Revision 1.7  2003/01/02 04:10:19  nemosoft
+ * Adding ''upside down" conversion to rgb/bgr routines
+ *
+ * Revision 1.6  2002/12/03 23:29:11  nemosoft
+ * *** empty log message ***
+ *
+ * Revision 1.5  2002/12/03 23:27:41  nemosoft
+ * fixing log messages (gcc 3.2 complaining)
+ *
+   Revision 1.4  2002/12/03 22:29:07  nemosoft
+   Fixing up FTP stuff and some video
+
+   Revision 1.3  2002/11/03 22:46:25  nemosoft
+   Adding various RGB to RGB functions.
+   Adding proper copyright header too.
+ */
+
+
+#include "ccvt.h"
+#include "ccvt_types.h"
+#include <stdlib.h>
+
+static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
+static float RGBYUV01684[256], RGBYUV03316[256];
+static float RGBYUV04187[256], RGBYUV00813[256];
+
+void InitLookupTable(void);
+
+
+/* YUYV: two Y's and one U/V */
+void ccvt_yuyv_rgb32(int width, int height, const void *src, void *dst)
+{
+   width=width; height=height; src=src; dst=dst;
+
+}
+
+
+void ccvt_yuyv_bgr32(int width, int height, const void *src, void *dst)
+{
+   const unsigned char *s;
+   PIXTYPE_bgr32 *d;
+   int l, c;
+   int r, g, b, cr, cg, cb, y1, y2;
+   
+   l = height;
+   s = src;
+   d = dst;
+   while (l--) {
+      c = width >> 2;
+      while (c--) {
+         y1 = *s++;
+         cb = ((*s - 128) * 454) >> 8;
+         cg = (*s++ - 128) * 88;
+         y2 = *s++;
+         cr = ((*s - 128) * 359) >> 8;
+         cg = (cg + (*s++ - 128) * 183) >> 8;
+
+         r = y1 + cr;
+         b = y1 + cb;
+         g = y1 - cg;
+         SAT(r);
+         SAT(g);
+         SAT(b);               
+         d->b = b;	
+         d->g = g;           
+         d->r = r;          
+         d++;             
+         r = y2 + cr;
+         b = y2 + cb;
+         g = y2 - cg;
+         SAT(r);
+         SAT(g);
+         SAT(b);               
+         d->b = b;
+         d->g = g;           
+         d->r = r;          
+         d++;             
+      }
+   }
+   
+}
+
+void ccvt_yuyv_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv)
+{
+   int n, l, j;
+   const unsigned char *s1, *s2;
+   unsigned char *dy, *du, *dv;
+   
+   dy = (unsigned char *)dsty;
+   du = (unsigned char *)dstu;
+   dv = (unsigned char *)dstv;
+   s1 = (unsigned char *)src;
+   s2 = s1; /* keep pointer */
+   n = width * height;
+   for (; n > 0; n--) {
+      *dy = *s1;
+      dy++;
+      s1 += 2;
+   }
+   
+   /* Two options here: average U/V values, or skip every second row */
+   s1 = s2; /* restore pointer */
+   s1++; /* point to U */
+   for (l = 0; l < height; l += 2) {
+      s2 = s1 + width * 2; /* odd line */
+      for (j = 0; j < width; j += 2) {
+         *du = (*s1 + *s2) / 2;
+         du++;
+         s1 += 2;
+         s2 += 2;
+         *dv = (*s1 + *s2) / 2;
+         dv++;
+         s1 += 2;
+         s2 += 2;
+      }
+      s1 = s2;
+   }
+}
+
+void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
+{
+    long int i;
+    unsigned char *rawpt, *scanpt;
+    long int size;
+
+    rawpt = src;
+    scanpt = dst;
+    size = WIDTH*HEIGHT;
+
+    for ( i = 0; i < size; i++ ) {
+	if ( (i/WIDTH) % 2 == 0 ) {
+	    if ( (i % 2) == 0 ) {
+		/* B */
+		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
+		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
+				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
+		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
+				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
+		    *scanpt++ = *rawpt;					/* B */
+		} else {
+		    /* first line or left column */
+		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
+		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
+		    *scanpt++ = *rawpt;				/* B */
+		}
+	    } else {
+		/* (B)G */
+		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
+		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
+		    *scanpt++ = *rawpt;					/* G */
+		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
+		} else {
+		    /* first line or right column */
+		    *scanpt++ = *(rawpt+WIDTH);	/* R */
+		    *scanpt++ = *rawpt;		/* G */
+		    *scanpt++ = *(rawpt-1);	/* B */
+		}
+	    }
+	} else {
+	    if ( (i % 2) == 0 ) {
+		/* G(R) */
+		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
+		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
+		    *scanpt++ = *rawpt;					/* G */
+		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
+		} else {
+		    /* bottom line or left column */
+		    *scanpt++ = *(rawpt+1);		/* R */
+		    *scanpt++ = *rawpt;			/* G */
+		    *scanpt++ = *(rawpt-WIDTH);		/* B */
+		}
+	    } else {
+		/* R */
+		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
+		    *scanpt++ = *rawpt;					/* R */
+		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
+				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
+		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
+				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
+		} else {
+		    /* bottom line or right column */
+		    *scanpt++ = *rawpt;				/* R */
+		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
+		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
+		}
+	    }
+	}
+	rawpt++;
+    }
+
+}
+
+/************************************************************************
+ *
+ *  int RGB2YUV (int x_dim, int y_dim, void *bmp, YUV *yuv)
+ *
+ *	Purpose :	It takes a 24-bit RGB bitmap and convert it into
+ *				YUV (4:2:0) format
+ *
+ *  Input :		x_dim	the x dimension of the bitmap
+ *				y_dim	the y dimension of the bitmap
+ *				bmp		pointer to the buffer of the bitmap
+ *				yuv		pointer to the YUV structure
+ *
+ *  Output :	0		OK
+ *				1		wrong dimension
+ *				2		memory allocation error
+ *
+ *	Side Effect :
+ *				None
+ *
+ *	Date :		09/28/2000
+ *
+ *  Contacts:
+ *
+ *  Adam Li
+ *
+ *  DivX Advance Research Center <darc@projectmayo.com>
+ *
+ ************************************************************************/
+
+int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip)
+{
+	static int init_done = 0;
+
+	long i, j, size;
+	unsigned char *r, *g, *b;
+	unsigned char *y, *u, *v;
+	unsigned char *pu1, *pu2, *pv1, *pv2, *psu, *psv;
+	unsigned char *y_buffer, *u_buffer, *v_buffer;
+	unsigned char *sub_u_buf, *sub_v_buf;
+
+	if (init_done == 0)
+	{
+		InitLookupTable();
+		init_done = 1;
+	}
+
+	/* check to see if x_dim and y_dim are divisible by 2*/
+	if ((x_dim % 2) || (y_dim % 2)) return 1;
+	size = x_dim * y_dim;
+
+	/* allocate memory*/
+	y_buffer = (unsigned char *)y_out;
+	sub_u_buf = (unsigned char *)u_out;
+	sub_v_buf = (unsigned char *)v_out;
+	u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
+	v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
+	if (!(u_buffer && v_buffer))
+	{
+		if (u_buffer) free(u_buffer);
+		if (v_buffer) free(v_buffer);
+		return 2;
+	}
+
+	b = (unsigned char *)bmp;
+	y = y_buffer;
+	u = u_buffer;
+	v = v_buffer;
+
+	/* convert RGB to YUV*/
+	if (!flip) {
+		for (j = 0; j < y_dim; j ++)
+		{
+			y = y_buffer + (y_dim - j - 1) * x_dim;
+			u = u_buffer + (y_dim - j - 1) * x_dim;
+			v = v_buffer + (y_dim - j - 1) * x_dim;
+
+			for (i = 0; i < x_dim; i ++) {
+				g = b + 1;
+				r = b + 2;
+				*y = (unsigned char)(  RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
+				*u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2          + 128);
+				*v = (unsigned char)(  (*r)/2          - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
+				b += 3;
+				y ++;
+				u ++;
+				v ++;
+			}
+		}
+	} else {
+		for (i = 0; i < size; i++)
+		{
+			g = b + 1;
+			r = b + 2;
+			*y = (unsigned char)(  RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
+			*u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2          + 128);
+			*v = (unsigned char)(  (*r)/2          - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
+			b += 3;
+			y ++;
+			u ++;
+			v ++;
+		}
+	}
+
+	/* subsample UV*/
+	for (j = 0; j < y_dim/2; j ++)
+	{
+		psu = sub_u_buf + j * x_dim / 2;
+		psv = sub_v_buf + j * x_dim / 2;
+		pu1 = u_buffer + 2 * j * x_dim;
+		pu2 = u_buffer + (2 * j + 1) * x_dim;
+		pv1 = v_buffer + 2 * j * x_dim;
+		pv2 = v_buffer + (2 * j + 1) * x_dim;
+		for (i = 0; i < x_dim/2; i ++)
+		{
+			*psu = (*pu1 + *(pu1+1) + *pu2 + *(pu2+1)) / 4;
+			*psv = (*pv1 + *(pv1+1) + *pv2 + *(pv2+1)) / 4;
+			psu ++;
+			psv ++;
+			pu1 += 2;
+			pu2 += 2;
+			pv1 += 2;
+			pv2 += 2;
+		}
+	}
+
+	free(u_buffer);
+	free(v_buffer);
+
+	return 0;
+}
+
+
+void InitLookupTable()
+{
+	int i;
+
+	for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
+	for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
+	for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
+	for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
+	for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
+	for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
+	for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
+}
+
+
+/* RGB/BGR to RGB/BGR */
+
+#define RGBBGR_BODY24(TIN, TOUT) \
+void ccvt_ ## TIN ## _ ## TOUT (int width, int height, const void *const src, void *dst) \
+{ \
+   const PIXTYPE_ ## TIN *in = src; \
+   PIXTYPE_ ## TOUT *out = dst; \
+   int l, c, stride = 0; \
+   \
+   stride = width; \
+   out += ((height - 1) * width); \
+   stride *= 2; \
+   for (l = 0; l < height; l++) { \
+      for (c = 0; c < width; c++) { \
+         out->r = in->r; \
+         out->g = in->g; \
+         out->b = in->b; \
+         in++; \
+         out++; \
+      } \
+      out -= stride; \
+   } \
+}
+
+#define RGBBGR_BODY32(TIN, TOUT) \
+void ccvt_ ## TIN ## _ ## TOUT (int width, int height, const void *const src, void *dst) \
+{ \
+   const PIXTYPE_ ## TIN *in = src; \
+   PIXTYPE_ ## TOUT *out = dst; \
+   int l, c, stride = 0; \
+   \
+   stride = width;\
+   out += ((height - 1) * width); \
+   stride *= 2; \
+   for (l = 0; l < height; l++) { \
+      for (c = 0; c < width; c++) { \
+         out->r = in->r; \
+         out->g = in->g; \
+         out->b = in->b; \
+         out->z = 0; \
+         in++; \
+         out++; \
+      } \
+      out -= stride; \
+   } \
+}
+
+RGBBGR_BODY32(bgr24, bgr32)
+RGBBGR_BODY32(bgr24, rgb32)
+RGBBGR_BODY32(rgb24, bgr32)
+RGBBGR_BODY32(rgb24, rgb32)
+
+RGBBGR_BODY24(bgr32, bgr24)
+RGBBGR_BODY24(bgr32, rgb24)
+RGBBGR_BODY24(rgb32, bgr24)
+RGBBGR_BODY24(rgb32, rgb24)
Index: /BAORadio/libindi/v1/libs/webcam/ccvt_types.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/ccvt_types.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/ccvt_types.h	(revision 500)
@@ -0,0 +1,61 @@
+/*  CCVT: ColourConVerT: simple library for converting colourspaces
+    Copyright (C) 2002 Nemosoft Unv.
+    Email:athomas@nemsoft.co.uk
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    For questions, remarks, patches, etc. for this program, the author can be
+    reached at nemosoft@smcc.demon.nl.
+*/
+
+#ifndef CCVT_TYPES_H
+#define CCVT_TYPES_H
+
+typedef struct
+{
+		unsigned char b;
+		unsigned char g;
+		unsigned char r;
+		unsigned char z;
+} PIXTYPE_bgr32;
+
+typedef struct
+{
+		unsigned char b;
+		unsigned char g;
+		unsigned char r;
+} PIXTYPE_bgr24;
+
+typedef struct
+{
+		unsigned char r;
+		unsigned char g;
+		unsigned char b;
+		unsigned char z;
+} PIXTYPE_rgb32;
+
+typedef struct
+{
+		unsigned char r;
+		unsigned char g;
+		unsigned char b;
+} PIXTYPE_rgb24;
+
+#define SAT(c) \
+	if (c & (~255)) { if (c < 0) c = 0; else c = 255; }
+
+
+
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/port.cpp
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/port.cpp	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/port.cpp	(revision 500)
@@ -0,0 +1,200 @@
+/* libcqcam - shared Color Quickcam routines
+ * Copyright (C) 1996-1998 by Patrick Reynolds
+ * Email: <no.email@noemail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// I/O ports wrapper code
+// This file might need tweaking if you're trying to port my code to other
+// x86 Unix platforms.  Code is already available for Linux, FreeBSD, and    
+// QNX; see the Makefile.
+//
+// QNX code by: Anders Arpteg <aa11ac@hik.se>
+// FreeBSD code by: Patrick Reynolds <reynolds@cs.duke.edu> and Charles
+//                  Henrich <henrich@msu.edu>
+
+
+//#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef LOCKING
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif /* LOCKING */
+
+#ifdef __linux__
+  #if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__)
+  #include <fcntl.h>
+  #else
+  #include <sys/io.h>
+  #endif /* arm */
+#elif defined(QNX)
+#include <conio.h>
+#elif defined(__FreeBSD__)
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#elif defined(BSDI)
+#include <machine/inline.h>
+#elif defined(OPENBSD)
+#include <machine/pio.h>
+#elif defined(LYNX)
+#include "lynx-io.h"
+#elif defined(SOLARIS)
+#include "solaris-io.h"
+#else
+#error Please define a platform in the Makefile
+#endif /* which OS */
+
+#include "port.h"
+
+port_t::port_t(int iport) {
+  port = -1;
+
+#ifdef LOCKING
+  if (lock(iport) == -1) {
+#ifdef DEBUG
+    fprintf(stderr, "port 0x%x already locked\n", iport);
+#endif /* DEBUG */
+    return;
+  }
+#endif /* LOCKING */
+
+#ifdef LINUX
+#if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__)
+  if ((devport = open("/dev/port", O_RDWR)) < 0) {
+    perror("open /dev/port");
+    return;
+  }
+#else
+  if (ioperm(iport, 3, 1) == -1) {
+    perror("ioperm()");
+    return;
+  }
+#endif /* arm */
+#elif defined(FREEBSD)
+  if ((devio = fopen("/dev/io", "r+")) == NULL) {
+    perror("fopen /dev/io");
+    return;
+  }
+#elif defined(OPENBSD)
+  if (i386_iopl(1) == -1) {
+    perror("i386_iopl");
+    return;
+  }
+#elif defined(LYNX)
+  if (io_access() < 0) {
+    perror("io_access");
+    return;
+  }
+#elif defined(SOLARIS)
+  if (openiop()) {
+    perror("openiop");
+    return;
+  }
+#endif /* which OS */
+
+  port = iport;
+  port1 = port + 1;
+  port2 = port + 2;
+  control_reg = read_control();
+}
+
+port_t::~port_t(void) {
+#ifdef LOCKING
+  unlock(port);
+#endif /* LOCKING */
+#ifdef LINUX
+#if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__)
+  if (devport >= 0)
+    close(devport);
+#else
+  if (port > 0 && geteuid() == 0)
+    if (ioperm(port, 3, 0) != 0)  // drop port permissions -- still must
+                                  // be root
+      perror("ioperm()");
+#endif /* arm */
+#elif defined(FREEBSD)
+  if (devio != NULL)
+    fclose(devio);
+#elif defined(SOLARIS)
+  close(iopfd);
+#endif /* which OS */
+}
+
+#ifdef LOCKING
+int port_t::lock(int portnum) {
+  char lockfile[80];
+  sprintf(lockfile, "/tmp/LOCK.qcam.0x%x", portnum);
+  while ((lock_fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1) {
+    if (errno != EEXIST) {
+      perror(lockfile);
+      return -1;
+    }
+    struct stat stat_buf;
+    if (lstat(lockfile, &stat_buf) < 0) continue;
+    if (S_ISLNK(stat_buf.st_mode) || stat_buf.st_uid != 0) {
+      if (unlink(lockfile)) {
+        if (errno == ENOENT) continue;
+        if (errno != EISDIR || (rmdir(lockfile) && errno != ENOENT)) {
+            /* known problem: if lockfile exists and is a non-empty
+               directory, we give up instead of doing an rm-r of it */
+          perror(lockfile);
+          return -1;
+        }
+      }
+      continue;
+    }
+    lock_fd = open(lockfile, O_WRONLY, 0600);
+    if (lock_fd == -1) {
+      perror(lockfile);
+      return -1;
+    }
+    break;
+  }
+
+  static struct flock lock_info;
+  lock_info.l_type = F_WRLCK;
+#ifdef LOCK_FAIL
+  if (fcntl(lock_fd, F_SETLK, &lock_info) != 0) {
+#else
+  if (fcntl(lock_fd, F_SETLKW, &lock_info) != 0) {
+#endif /* LOCK_FAIL */
+    if (errno != EAGAIN)
+      perror("fcntl");
+    return -1;
+  }
+  chown(lockfile, getuid(), getgid());
+#ifdef DEBUG
+  fprintf(stderr, "Locked port 0x%x\n", portnum);
+#endif /* DEBUG */
+  return 0;
+}
+    
+void port_t::unlock(int portnum) {
+  if (portnum == -1)
+    return;
+  close(lock_fd);    // this clears the lock
+  char lockfile[80];
+  sprintf(lockfile, "/tmp/LOCK.qcam.0x%x", portnum);
+  if (unlink(lockfile)) perror(lockfile);
+#ifdef DEBUG
+  fprintf(stderr, "Unlocked port 0x%x\n", portnum);
+#endif /* DEBUG */
+}
+#endif /* LOCKING */
Index: /BAORadio/libindi/v1/libs/webcam/port.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/port.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/port.h	(revision 500)
@@ -0,0 +1,123 @@
+/* libcqcam - shared Color Quickcam routines
+ * Copyright (C) 1996-1998 by Patrick Reynolds
+* Email: <no.email@noemail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// I/O ports wrapper definitions and prototypes
+// This file might need tweaking if you're trying to port my code to other
+// x86 Unix platforms.  Code is already available for Linux, FreeBSD, and 
+// QNX; see the Makefile.
+//
+// QNX code by: Anders Arpteg <aa11ac@hik.se>
+// FreeBSD code by: Patrick Reynolds <reynolds@cs.duke.edu> and Charles 
+//                  Henrich <henrich@msu.edu>
+// Inlining implemented by: Philip Blundell <philip.blundell@pobox.com>
+
+#ifndef PORT_H
+#define PORT_H
+
+//#include "config.h"
+
+#include <unistd.h>
+
+#ifdef __linux__
+  #if !defined(arm) && !defined(__hppa__) && !defined(__sparc__) && !defined(__ppc__) && !defined(__powerpc__) && !defined(__s390__) && !defined(__s390x__) && !defined(__mips__) && !defined(__mc68000__)
+  #include <sys/io.h>
+  #endif /* !arm */
+#elif defined(QNX)
+#include <conio.h>
+#elif defined(__FreeBSD__)
+#include <machine/cpufunc.h>
+#include <stdio.h>
+#elif defined(BSDI)
+#include <machine/inline.h>
+#elif defined(OPENBSD)
+#include <machine/pio.h>
+#elif defined(LYNX)
+#include "lynx-io.h"
+#elif defined(SOLARIS)
+#include "solaris-io.h"
+#else
+#error Please define a platform in the Makefile
+#endif
+
+#if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__)
+static char ports_temp;
+
+#ifdef inb
+#undef inb
+#endif /* inb */
+#define inb(port) \
+  lseek(devport, port, SEEK_SET), \
+  read(devport, &ports_temp, 1), \
+  ports_temp
+
+#ifdef outb
+#undef outb
+#endif /* inb */
+#define outb(data, port) \
+  lseek(devport, port, SEEK_SET); \
+  ports_temp = data; \
+  write(devport, &ports_temp, 1);
+
+#endif /* arm, hppa */
+
+class port_t {
+public:
+  port_t(int iport);
+  ~port_t(void);
+
+  inline int read_data(void) { return inb(port); }
+  inline int read_status(void) { return inb(port1); }
+  inline int read_control(void) { return inb(port2); }
+
+#if defined(LINUX) || defined(LYNX)
+  inline void write_data(int data) { outb(data, port); }
+  inline void write_control(int data) { outb(control_reg = data, port2); }
+  inline void setbit_control(int data) { outb(control_reg |= data, port2); }
+  inline void clearbit_control(int data) { outb(control_reg &= ~data, port2); }
+#else // Solaris, QNX, and *BSD use (port, data) instead
+  inline void write_data(int data) { outb(port, data); }
+  inline void write_control(int data) { outb(port2, control_reg = data); }
+  inline void setbit_control(int data) { outb(port2, control_reg |= data); }
+  inline void clearbit_control(int data) { outb(port2, control_reg &= ~data); }
+#endif
+
+  inline int get_port() { return port; }
+  inline operator bool () const { return port != -1; }
+
+private:
+  int port;        // number of the base port
+  int port1;       // port+1, precalculated for speed
+  int port2;       // port+2, precalculated for speed
+  int control_reg; // current contents of the control register
+#ifdef LOCKING
+  int lock_fd;
+  int lock(int portnum);
+  void unlock(int portnum);
+#endif
+
+#ifdef FREEBSD
+  FILE *devio;
+#endif
+#if defined(__linux__) && (defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__))
+  int devport;
+#endif
+};
+
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/pwc-ioctl.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/pwc-ioctl.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/pwc-ioctl.h	(revision 500)
@@ -0,0 +1,325 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+   
+*/
+
+/* This is pwc-ioctl.h belonging to PWC 10.0.10
+   It contains structures and defines to communicate from user space
+   directly to the driver.
+ */
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added ioctl constants to access methods for
+                          changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
+   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
+               PWCX easier
+   2006/01/01  Luc Saillard Add raw format definition
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+   They contain functions not found in other webcams, and settings not
+   specified in the Video4Linux API.
+
+   The #define names are built up like follows:
+   VIDIOC		VIDeo IOCtl prefix
+         PWC		Philps WebCam
+            G           optional: Get
+            S           optional: Set
+             ... 	the function
+ */
+
+#include <linux/types.h>
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF	0x00
+#define PSZ_QSIF	0x01
+#define PSZ_QCIF	0x02
+#define PSZ_SIF		0x03
+#define PSZ_CIF		0x04
+#define PSZ_VGA		0x05
+#define PSZ_MAX		6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+   the upper 16 bits, since some flags are defined nowadays. The following
+   defines provide a mask and shift to filter out this value.
+   This value can also be passing using the private flag when using v4l2 and
+   VIDIOC_S_FMT ioctl.
+
+   In 'Snapshot' mode the camera freezes its automatic exposure and colour
+   balance controls.
+ */
+#define PWC_FPS_SHIFT		16
+#define PWC_FPS_MASK		0x00FF0000
+#define PWC_FPS_FRMASK		0x003F0000
+#define PWC_FPS_SNAPSHOT	0x00400000
+#define PWC_QLT_MASK		0x03000000
+#define PWC_QLT_SHIFT		24
+
+
+/* structure for transferring x & y coordinates */
+struct pwc_coord
+{
+	int x, y;		/* guess what */
+	int size;		/* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+	char name[32];
+	int type;
+};
+
+struct pwc_serial
+{
+	char serial[30];	/* String with serial number. Contains terminating 0 */
+};
+	
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR		0
+#define PWC_WB_OUTDOOR		1
+#define PWC_WB_FL		2
+#define PWC_WB_MANUAL		3
+#define PWC_WB_AUTO		4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). 
+   Set mode to one of the PWC_WB_* values above.
+   *red and *blue are the respective gains of these colour components inside 
+   the camera; range 0..65535
+   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; 
+   otherwise undefined.
+   'read_red' and 'read_blue' are read-only.
+*/   
+struct pwc_whitebalance
+{
+	int mode;
+	int manual_red, manual_blue;	/* R/W */
+	int read_red, read_blue;	/* R/O */
+};
+
+/* 
+   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+   and tell the camera how fast it should react to changes in lighting, and 
+   with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+	int control_speed;
+	int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+	int led_on;			/* Led on-time; range = 0..25000 */
+	int led_off;			/* Led off-time; range = 0..25000  */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+	int width;
+	int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN		0x01
+#define PWC_MPT_TILT		0x02
+#define PWC_MPT_TIMEOUT		0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the 
+   driver calculates the relative offset for you. This can only
+   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+   absolute angles.
+ */   
+struct pwc_mpt_angles
+{
+	int absolute;		/* write-only */
+	int pan;		/* degrees * 100 */
+	int tilt;		/* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+	int pan_min, pan_max;		/* degrees * 100 */
+	int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+	int status;
+	int time_pan;
+	int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+   all the necessary information to initialize and use the decompressor
+   routines in standalone applications.
+ */   
+struct pwc_video_command
+{
+	int type;		/* camera type (645, 675, 730, etc.) */
+	int release;		/* release number */
+
+        int size;		/* one of PSZ_* */
+        int alternate;
+	int command_len;	/* length of USB video command */
+	unsigned char command_buf[13];	/* Actual USB video command */
+	int bandlength;		/* >0 = compressed */
+	int frame_size;		/* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honor all flags. */
+#define PWCX_FLAG_PLANAR	0x0001
+#define PWCX_FLAG_BAYER		0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER		_IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER		_IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY	_IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+    means use uncompressed modes when available; 1 is low compression, 2 is
+    medium and 3 is high compression preferred. Of course, the higher the
+    compression, the lower the bandwidth used but more chance of artefacts
+    in the image. The driver automatically chooses a higher compression when
+    the preferred mode is not available.
+  */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL		_IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL		_IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL	_IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+    becomes difficult to include all the names in programs that want to
+    check for the enhanced Philips stuff. So in stead, try this PROBE;
+    it returns a structure with the original name, and the corresponding
+    Philips type.
+    To use, fill the structure with zeroes, call PROBE and if that succeeds,
+    compare the name with that returned from VIDIOCGCAP; they should be the
+    same. If so, you can be assured it is a Philips (OEM) cam and the type
+    is valid.
+ */
+#define VIDIOCPWCPROBE		_IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC		_IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC		_IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER	_IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED	_IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED	_IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
+
+  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR	_IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR	_IOR('v', 206, int)
+
+  /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT	_IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT	_IOR('v', 207, int)
+
+  /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER	_IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER	_IOR('v', 208, int)  
+
+  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE	_IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE	_IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE	_IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */ 
+#define VIDIOCPWCMPTRESET	_IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE	_IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE	_IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE	_IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS	_IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD	_IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+   int len;
+   char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE	_IOR('v', 216, struct pwc_table_init_buffer)
+
+/*
+ * This is private command used when communicating with v4l2.
+ * In the future all private ioctl will be remove/replace to 
+ * use interface offer by v4l2.
+ */
+
+#define V4L2_CID_PRIVATE_SAVE_USER       (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_RESTORE_USER    (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_COLOUR_MODE     (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AUTOCONTOUR     (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_CONTOUR         (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_BACKLIGHT       (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_FLICKERLESS     (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
+
+struct pwc_raw_frame {
+   unsigned short type;		/* type of the webcam */
+   unsigned short vbandlength;	/* Size of 4lines compressed (used by the decompressor) */
+   unsigned char   cmd[4];	/* the four byte of the command (in case of nala version, only the first 3 bytes is filled) */
+#ifndef __cplusplus
+   unsigned char   rawframe[0]; 	/* frame_size = H/4*vbandlength */
+#endif
+} __attribute__ ((packed));
+
+
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/v4l1_base.cpp
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/v4l1_base.cpp	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/v4l1_base.cpp	(revision 500)
@@ -0,0 +1,560 @@
+/*
+    Copyright (C) 2005 by Jasem Mutlaq
+    Email: mutlaqja@ikarustech.com 
+
+    Some code based on qastrocam
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <iostream>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <string.h>
+
+#include "ccvt.h"
+#include "v4l1_base.h"
+#include "eventloop.h"
+#include "indidevapi.h"
+
+#define ERRMSGSIZ	1024
+
+using namespace std;
+
+V4L1_Base::V4L1_Base()
+{
+   frameRate=10;
+   fd=-1;
+   //usingTimer = false;
+   
+   //frameUpdate = true;
+   //selectCallBackID = -1;
+   //timerCallBackID  = -1;
+
+   YBuf       = NULL;
+   UBuf       = NULL;
+   VBuf       = NULL;
+   colorBuffer= NULL;
+   buffer_start=NULL;
+
+}
+
+V4L1_Base::~V4L1_Base()
+{
+
+  delete (YBuf);
+  delete (UBuf);
+  delete (VBuf);
+  delete (colorBuffer);
+
+}
+
+int V4L1_Base::connectCam(const char * devpath, char *errmsg)
+{
+   options= (haveBrightness|haveContrast|haveHue|haveColor|haveWhiteness);
+
+   buffer_start=NULL;
+   frameRate=10;
+   fd=-1;
+
+   //cerr << "In connect Cam with device " << devpath << endl;
+   if (-1 == (fd=open(devpath, O_RDWR | O_NONBLOCK, 0)))
+   {
+        if (-1 == (fd=open(devpath, O_RDONLY | O_NONBLOCK, 0)))
+	{
+      		strncpy(errmsg, strerror(errno), ERRMSGSIZ);
+      		cerr << strerror(errno);
+      		return -1;
+	}
+   }
+   
+   cerr << "Device opened" << endl;
+   
+   if (fd != -1) 
+   {
+      if (-1 == ioctl(fd,VIDIOCGCAP,&capability))
+     {
+         cerr << "Error: ioctl (VIDIOCGCAP)" << endl;
+	 strncpy(errmsg, "ioctl (VIDIOCGCAP)", ERRMSGSIZ);
+	 return -1;
+      }
+      if (-1 == ioctl (fd, VIDIOCGWIN, &window))
+      {
+         cerr << "Error ioctl (VIDIOCGWIN)" << endl;
+	 strncpy(errmsg, "ioctl (VIDIOCGWIN)", ERRMSGSIZ);
+	 return -1;
+      }
+      if (-1 == ioctl (fd, VIDIOCGPICT, &picture_format))
+      {
+         cerr << "Error: ioctl (VIDIOCGPICT)" << endl;
+	 strncpy(errmsg, "ioctl (VIDIOCGPICT)", ERRMSGSIZ);
+	 return -1;
+      }
+
+      init(0);
+   }
+
+   cerr << "initial size w:" << window.width << " -- h: " << window.height << endl;
+
+   /*if (options & ioUseSelect)
+   {
+      selectCallBackID = addCallback(fd, V4L1_Base::staticUpdateFrame, this);
+      cerr << "Using select to wait new frames." << endl;
+   } else
+   {
+      usingTimer = true;
+      timerCallBackID = addTimer(1000/frameRate, V4L1_Base::staticCallFrame, this);
+      cerr << "Using timer to wait new frames.\n";
+   }
+    */
+
+   if (mmapInit() < 0)
+   {
+	 strncpy(errmsg, "mmapInit() failed", ERRMSGSIZ);
+	 return -1;
+   }
+   
+   cerr << "All successful, returning\n";
+   return fd;
+}
+
+void V4L1_Base::disconnectCam()
+{
+   
+   
+   delete YBuf;
+   delete UBuf;
+   delete VBuf;
+   YBuf = UBuf = VBuf = NULL;
+   
+   if (selectCallBackID != -1)
+     rmCallback(selectCallBackID);
+     
+   //if (usingTimer && timerCallBackID != -1)
+     //rmTimer(timerCallBackID);
+     
+   if (munmap (buffer_start, mmap_buffer.size) < 0)
+     fprintf(stderr, "munmap: %s\n", strerror(errno));
+     
+   if (close(fd) < 0)
+     fprintf(stderr, "close(fd): %s\n", strerror(errno));
+     
+   fprintf(stderr, "Disconnect cam\n");
+}
+
+void V4L1_Base::newFrame() 
+{
+      switch (picture_format.palette) 
+      {
+       case VIDEO_PALETTE_GREY:
+         memcpy(YBuf,mmapFrame(),window.width * window.height);
+         break;
+       case VIDEO_PALETTE_YUV420P:
+         memcpy(YBuf,mmapFrame(), window.width * window.height);
+         memcpy(UBuf,
+                mmapFrame()+ window.width * window.height,
+                (window.width/2) * (window.height/2));
+         memcpy(VBuf,
+                mmapFrame()+ window.width * window.height+(window.width/2) * (window.height/2),
+                (window.width/2) * (window.height/2));
+         break;
+      case VIDEO_PALETTE_YUYV:
+         ccvt_yuyv_420p(window.width,window.height,
+                           mmapFrame(),
+                           YBuf,
+                           UBuf,
+                           VBuf);
+         break;
+
+     case VIDEO_PALETTE_RGB24:
+        RGB2YUV(window.width, window.height, mmapFrame(), YBuf, UBuf, VBuf, 0);
+        break;
+
+      default: 
+         cerr << "invalid palette " <<picture_format.palette << endl;
+         exit(1);
+      }
+   
+   
+    if (callback)
+      (*callback)(uptr);
+
+}
+
+void V4L1_Base::updateFrame(int /*d*/, void * p)
+{
+
+  ( (V4L1_Base *) (p))->newFrame();
+
+}
+
+int V4L1_Base::start_capturing(char * /*errmsg*/)
+{
+   
+   mmapCapture();
+   mmapSync();
+
+   selectCallBackID = IEAddCallback(fd, updateFrame, this);
+   //newFrame();
+   return 0;
+}
+
+int V4L1_Base::stop_capturing(char * /*errmsg*/)
+{
+  
+  IERmCallback(selectCallBackID);
+  selectCallBackID = -1;
+  return 0;
+}
+ 
+int V4L1_Base::getWidth()
+{
+  return window.width;
+}
+
+int V4L1_Base::getHeight()
+{
+ return window.height;
+}
+
+void V4L1_Base::setFPS(int fps)
+{
+  frameRate = fps;
+}
+
+int V4L1_Base::getFPS()
+{
+  return frameRate;
+}
+
+char * V4L1_Base::getDeviceName()
+{
+  return capability.name;
+}
+
+void V4L1_Base::init(int preferedPalette)
+ {
+
+   if (preferedPalette)
+   {
+      picture_format.palette=preferedPalette;
+      if (0 == ioctl(fd, VIDIOCSPICT, &picture_format))
+        cerr <<  "found preferedPalette " << preferedPalette << endl;
+      else
+      {
+         preferedPalette=0;
+         cerr << "preferedPalette " << preferedPalette << " invalid, trying to find one." << endl;
+      }
+   }
+
+   if (preferedPalette == 0)
+   {
+      do {
+      /* trying VIDEO_PALETTE_YUV420P (Planar) */
+      picture_format.palette=VIDEO_PALETTE_YUV420P;
+      picture_format.depth=12;
+      if (0 == ioctl(fd, VIDIOCSPICT, &picture_format)) {
+         cerr << "found palette VIDEO_PALETTE_YUV420P" << endl;
+	 break;
+      }
+      cerr << "VIDEO_PALETTE_YUV420P not supported." << endl;
+      /* trying VIDEO_PALETTE_YUV420 (interlaced) */
+      picture_format.palette=VIDEO_PALETTE_YUV420;
+      picture_format.depth=12;
+      if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) {
+         cerr << "found palette VIDEO_PALETTE_YUV420" << endl;
+	 break;
+      }
+      cerr << "VIDEO_PALETTE_YUV420 not supported." << endl;
+      /* trying VIDEO_PALETTE_RGB24 */
+      picture_format.palette=VIDEO_PALETTE_RGB24;
+      picture_format.depth=24;
+      if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) {
+         cerr << "found palette VIDEO_PALETTE_RGB24" << endl;
+      break;
+      }
+      cerr << "VIDEO_PALETTE_RGB24 not supported." << endl;
+      /* trying VIDEO_PALETTE_GREY */
+      picture_format.palette=VIDEO_PALETTE_GREY;
+      picture_format.depth=8;
+      if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) {
+         cerr << "found palette VIDEO_PALETTE_GREY" << endl;
+      break;
+      }
+      cerr << "VIDEO_PALETTE_GREY not supported." << endl;
+      cerr << "could not find a supported palette." << endl;
+      exit(1);
+      } while (false);
+   }
+
+   allocBuffers();
+
+}
+
+void V4L1_Base::allocBuffers()
+{
+   delete YBuf;
+   delete UBuf;
+   delete VBuf;
+   delete colorBuffer;
+
+   YBuf= new unsigned char[window.width * window.height];
+   UBuf= new unsigned char[window.width * window.height];
+   VBuf= new unsigned char[window.width * window.height];
+   colorBuffer = new unsigned char[window.width * window.height * 4];
+}
+
+void V4L1_Base::checkSize(int & x, int & y)
+{
+   if (x >= capability.maxwidth && y >= capability.maxheight)
+   {
+      x=capability.maxwidth;
+      y=capability.maxheight;
+   }
+   else if (x>=352 && y >=288) {
+      x=352;y=288;
+   } else if (x>=320 && y >= 240) {
+      x=320;y=240;
+   } else if (x>=176 && y >=144) {
+      x=176;y=144;
+   } else if (x>=160 && y >=120 ) {
+      x=160;y=120;
+   } else
+   {
+      x=capability.minwidth;
+      y=capability.minheight;
+   }
+}
+
+void V4L1_Base::getMaxMinSize(int & xmax, int & ymax, int & xmin, int & ymin)
+{
+  xmax = capability.maxwidth;
+  ymax = capability.maxheight;
+  xmin = capability.minwidth;
+  ymin = capability.minheight;
+}
+
+bool V4L1_Base::setSize(int x, int y)
+{
+   int oldX, oldY;
+   checkSize(x,y);
+   
+   oldX = window.width;
+   oldY = window.height;
+   
+   window.width=x;
+   window.height=y;
+
+   cerr << "New size is x=" << window.width << " " << "y=" << window.height <<endl;
+   
+   if (ioctl (fd, VIDIOCSWIN, &window))
+   {
+       cerr << "ioctl(VIDIOCSWIN)" << endl;
+       window.width=oldX;
+       window.height=oldY;
+       return false;
+   }
+   ioctl (fd, VIDIOCGWIN, &window);
+
+   allocBuffers();
+   
+   return true;
+}
+
+void V4L1_Base::setContrast(int val)
+{
+   picture_format.contrast=val;
+   setPictureSettings();
+}
+
+int V4L1_Base::getContrast()
+{
+   return picture_format.contrast;
+}
+
+void V4L1_Base::setBrightness(int val)
+{
+   picture_format.brightness=val;
+   setPictureSettings();
+}
+
+int V4L1_Base::getBrightness()
+{
+   return picture_format.brightness;
+}
+
+void V4L1_Base::setColor(int val)
+{
+   picture_format.colour=val;
+   setPictureSettings();
+}
+
+int V4L1_Base::getColor()
+{
+   return picture_format.colour;
+}
+
+void V4L1_Base::setHue(int val)
+{
+   picture_format.hue=val;
+   setPictureSettings();
+}
+
+int V4L1_Base::getHue()
+{
+   return picture_format.hue;
+}
+
+void V4L1_Base::setWhiteness(int val)
+{
+   picture_format.whiteness=val;
+   setPictureSettings();
+}
+
+int V4L1_Base::getWhiteness() 
+{
+   return picture_format.whiteness;
+}
+
+void V4L1_Base::setPictureSettings()
+{
+   if (ioctl(fd, VIDIOCSPICT, &picture_format) ) {
+      cerr << "setPictureSettings" << endl;
+   }
+   ioctl(fd, VIDIOCGPICT, &picture_format);
+}
+
+void V4L1_Base::getPictureSettings()
+{
+   if (ioctl(fd, VIDIOCGPICT, &picture_format) )
+   {
+      cerr << "getPictureSettings" << endl;
+   }
+}
+
+int V4L1_Base::mmapInit()
+{
+   mmap_buffer.size = 0;
+   mmap_buffer.frames = 0;
+
+   mmap_sync_buffer=-1;
+   mmap_capture_buffer=-1;
+   buffer_start=NULL;
+
+   if (ioctl(fd, VIDIOCGMBUF, &mmap_buffer)) {
+      // mmap not supported
+      return -1;
+   }
+
+   buffer_start = (unsigned char *) mmap (NULL, mmap_buffer.size, PROT_READ, MAP_SHARED, fd, 0);
+
+   if (buffer_start == MAP_FAILED)
+    {
+      cerr << "mmap" << endl;
+      mmap_buffer.size = 0;
+      mmap_buffer.frames = 0;
+      buffer_start=NULL;
+      return -1;
+   }
+
+   return 0;
+}
+
+void V4L1_Base::mmapCapture() 
+{
+   
+   struct video_mmap vm;
+   mmap_capture_buffer = (mmap_capture_buffer + 1) % mmap_buffer.frames;
+
+   vm.frame = mmap_capture_buffer;
+   vm.format = picture_format.palette;
+   vm.width = window.width;
+   vm.height = window.height;
+
+   if (ioctl(fd, VIDIOCMCAPTURE, &vm) < 0)
+        cerr << "Error V4L1_Base::mmapCapture" << endl;
+}
+
+void V4L1_Base::mmapSync()
+{
+   mmap_sync_buffer= (mmap_sync_buffer + 1) % mmap_buffer.frames;
+
+   if (ioctl(fd, VIDIOCSYNC, &mmap_sync_buffer) < 0)
+      cerr << "Error V4L1_Base::mmapSync()" << endl;
+}
+
+unsigned char * V4L1_Base::mmapFrame()
+{
+   return (buffer_start + mmap_buffer.offsets[mmap_sync_buffer]);
+}
+
+unsigned char * V4L1_Base::getY()
+{
+  return YBuf;
+}
+
+unsigned char * V4L1_Base::getU()
+{
+ return UBuf;
+}
+
+unsigned char * V4L1_Base::getV()
+{
+ return VBuf;
+}
+
+unsigned char * V4L1_Base::getColorBuffer()
+{
+  //cerr << "in get color buffer " << endl;
+  
+  switch (picture_format.palette) 
+  {
+      case VIDEO_PALETTE_YUV420P:
+        ccvt_420p_bgr32(window.width, window.height,
+                      mmapFrame(), (void*)colorBuffer);
+      break;
+
+    case VIDEO_PALETTE_YUYV:
+         ccvt_yuyv_bgr32(window.width, window.height,
+                      mmapFrame(), (void*)colorBuffer);
+         break;
+	 
+    case VIDEO_PALETTE_RGB24:
+         ccvt_rgb24_bgr32(window.width, window.height,
+                      mmapFrame(), (void*)colorBuffer);
+         break;
+	 
+   default:
+    break;
+  }
+  
+
+  return colorBuffer;
+
+}
+
+void V4L1_Base::registerCallback(WPF *fp, void *ud)
+{
+  callback = fp;
+  uptr = ud;
+}
Index: /BAORadio/libindi/v1/libs/webcam/v4l1_base.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/v4l1_base.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/v4l1_base.h	(revision 500)
@@ -0,0 +1,110 @@
+/*
+    Copyright (C) 2005 by Jasem Mutlaq
+
+    Some code based on qastrocam
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef V4L1_BASE_H
+#define V4L1_BASE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "videodev.h"
+#include "eventloop.h"
+
+class V4L1_Base
+{
+  public:
+   V4L1_Base();
+   virtual ~V4L1_Base();
+
+  /* Connection */
+  virtual int connectCam(const char * devpath, char *errmsg);
+  virtual void disconnectCam();
+  char * getDeviceName();
+
+  /* Image settings */
+  int  getBrightness();
+  int  getContrast();
+  int  getColor();
+  int  getHue();
+  int  getWhiteness();
+  void setContrast(int val);
+  void setBrightness(int val);
+  void setColor(int val);
+  void setHue(int val);
+  void setWhiteness(int val);
+
+  /* Updates */
+  static void updateFrame(int d, void * p);
+  void newFrame();
+  void setPictureSettings();
+  void getPictureSettings();
+
+  /* Image Size */
+  int getWidth();
+  int getHeight();
+  void checkSize(int & x, int & y);
+  virtual bool setSize(int x, int y);
+  virtual void getMaxMinSize(int & xmax, int & ymax, int & xmin, int & ymin);
+
+  /* Frame rate */
+  void setFPS(int fps);
+  int  getFPS();
+
+  void init(int preferedPalette);
+  void allocBuffers();
+  int  mmapInit();
+  void mmapCapture();
+  void mmapSync();
+
+  unsigned char * mmapFrame();
+  unsigned char * getY();
+  unsigned char * getU();
+  unsigned char * getV();
+  unsigned char * getColorBuffer();
+
+  int start_capturing(char *errmsg);
+  int stop_capturing(char *errmsg);
+  void registerCallback(WPF *fp, void *ud);
+
+  protected:
+
+  int fd;
+  WPF *callback;
+  void *uptr;
+  unsigned long options;
+
+  struct video_capability capability;
+  struct video_window window;
+  struct video_picture picture_format;
+  struct video_mbuf mmap_buffer;
+
+  unsigned char * buffer_start;
+  
+  long mmap_sync_buffer;
+  long mmap_capture_buffer;  
+  
+  int frameRate;
+  bool streamActive;
+  int  selectCallBackID;
+  unsigned char * YBuf,*UBuf,*VBuf, *colorBuffer;
+
+};
+   
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/v4l1_pwc.cpp
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/v4l1_pwc.cpp	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/v4l1_pwc.cpp	(revision 500)
@@ -0,0 +1,563 @@
+/*
+    Phlips webcam driver for V4L 1
+    Copyright (C) 2005 by Jasem Mutlaq <mutlaqja@ikarustech.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <iostream>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <string.h>
+
+#include "ccvt.h"
+#include "pwc-ioctl.h"
+#include "v4l1_pwc.h"
+#include "../eventloop.h"
+
+#define ERRMSG_SIZ	1024
+
+extern int errno;
+using namespace std;
+
+V4L1_PWC::V4L1_PWC()
+{
+   frameRate=15;
+   fd=-1;
+   streamActive = true;
+
+   YBuf       = NULL;
+   UBuf       = NULL;
+   VBuf       = NULL;
+   colorBuffer= NULL;
+   buffer_start=NULL;
+}
+
+V4L1_PWC::~V4L1_PWC()
+{
+
+} 
+
+int V4L1_PWC::connectCam(const char * devpath, char *errmsg)
+{
+   options= (ioNoBlock|ioUseSelect|haveBrightness|haveContrast|haveColor);
+   struct pwc_probe probe;
+   bool IsPhilips = false;
+   frameRate=15;
+   fd=-1;
+   streamActive = true;
+   buffer_start=NULL;
+   
+   if (-1 == (fd=open(devpath,
+                           O_RDONLY | ((options & ioNoBlock) ? O_NONBLOCK : 0)))) {
+      
+      strncpy(errmsg, strerror(errno), 1024);
+      cerr << strerror(errno);
+      return -1;
+   } 
+  
+   cerr << "Device opened" << endl;
+   
+   if (fd != -1) {
+      if (-1 == ioctl(fd,VIDIOCGCAP,&capability)) {
+         cerr << "Error: ioctl (VIDIOCGCAP)" << endl;
+	 strncpy(errmsg, "ioctl (VIDIOCGCAP)", 1024);
+	 return -1;
+      }
+      if (-1 == ioctl (fd, VIDIOCGWIN, &window)) {
+         cerr << "Error: ioctl (VIDIOCGWIN)" << endl;
+	 strncpy(errmsg, "ioctl (VIDIOCGWIN)", 1024);
+	 return -1;
+      }
+      if (-1 == ioctl (fd, VIDIOCGPICT, &picture_format)) {
+         cerr << "Error: ioctl (VIDIOCGPICT)" << endl;
+	 strncpy(errmsg, "ioctl (VIDIOCGPICT)", 1024);
+	 return -1;
+      }
+      init(0);
+   }
+   
+  // Check to see if it's really a philips webcam       
+  if (ioctl(fd, VIDIOCPWCPROBE, &probe) == 0) 
+  {
+  	    if (!strcmp(capability.name,probe.name))
+	    {
+	       IsPhilips = true;
+	       type_=probe.type;
+            }
+ }
+	 
+  if (IsPhilips)
+      cerr << "Philips webcam type " << type_ << " detected" << endl;
+  else
+  {
+   strncpy(errmsg, "No Philips webcam detected.", 1024);
+   return -1;
+  }
+    
+   cerr << "initial size w:" << window.width << " -- h: " << window.height << endl;
+   
+   
+   mmapInit();
+   
+   setWhiteBalanceMode(PWC_WB_AUTO, errmsg);
+   multiplicateur_=1;
+   skippedFrame_=0;
+   lastGain_=getGain();
+
+   cerr << "All successful, returning\n";
+   return fd;
+}
+
+void V4L1_PWC::checkSize(int & x, int & y) 
+{
+ if (x>=capability.maxwidth && y >= capability.maxheight)
+   {
+      x=capability.maxwidth;
+      y=capability.maxheight;
+   } else if (x>=352 && y >=288 && type_<700) {
+      x=352;y=288;
+   } else if (x>=320 && y >= 240) {
+      x=320;y=240;
+   } else if (x>=176 && y >=144 && type_<700 ) {
+      x=176;y=144;
+   } else if (x>=160 && y >=120 ) {
+      x=160;y=120;
+   } else {
+      x=capability.minwidth;
+      y=capability.minheight;
+   }
+}
+
+bool V4L1_PWC::setSize(int x, int y) 
+{
+
+   int oldX, oldY;
+   char msg[ERRMSG_SIZ];
+   checkSize(x,y);
+   
+   oldX = window.width;
+   oldY = window.height;
+   
+   window.width=x;
+   window.height=y;
+   
+   if (ioctl (fd, VIDIOCSWIN, &window))
+   {
+       snprintf(msg, ERRMSG_SIZ, "ioctl(VIDIOCSWIN) %s", strerror(errno));
+       cerr << msg << endl;
+       window.width=oldX;
+       window.height=oldY;
+       return false;
+   }
+   ioctl (fd, VIDIOCGWIN, &window);
+
+   cerr << "New size is x=" << window.width << " " << "y=" << window.height <<endl;
+   
+   allocBuffers();
+   
+   return true;
+}
+
+int V4L1_PWC::saveSettings(char *errmsg)
+{
+   if (ioctl(fd, VIDIOCPWCSUSER)==-1)
+    {
+      snprintf(errmsg, ERRMSG_SIZ, "VIDIOCPWCSUSER %s", strerror(errno));
+      return -1;
+   }
+   
+   return 0;
+}
+
+void V4L1_PWC::restoreSettings()
+ {
+   ioctl(fd, VIDIOCPWCRUSER);
+   getPictureSettings();
+}
+
+void V4L1_PWC::restoreFactorySettings()
+{
+   ioctl(fd, VIDIOCPWCFACTORY);
+   getPictureSettings();
+}
+
+int V4L1_PWC::setGain(int val, char *errmsg)
+ {
+   if(-1==ioctl(fd, VIDIOCPWCSAGC, &val))
+   {
+      snprintf(errmsg, ERRMSG_SIZ, "VIDIOCPWCSAGC %s", strerror(errno));
+      return -1;
+   }
+   else lastGain_=val;
+   
+   cerr << "setGain "<<val<<endl;
+   
+   return lastGain_;
+}
+
+int V4L1_PWC::getGain()
+{
+   int gain;
+   char msg[ERRMSG_SIZ];
+   static int cpt=0;
+   if ((cpt%4)==0)
+   {
+      if (-1==ioctl(fd, VIDIOCPWCGAGC, &gain))
+      {
+         //perror("VIDIOCPWCGAGC");
+	 snprintf(msg, ERRMSG_SIZ, "VIDIOCPWCGAGC %s", strerror(errno));
+	 cerr << msg << endl;
+         gain=lastGain_;
+      } else
+      {
+         ++cpt;
+         lastGain_=gain;
+      }
+   } else
+   {
+      ++cpt;
+      gain=lastGain_; 
+   }
+   //cerr << "get gain "<<gain<<endl;
+   if (gain < 0) gain*=-1;
+   return gain;
+}
+
+int V4L1_PWC::setExposure(int val, char *errmsg)
+ {
+   //cout << "set exposure "<<val<<"\n";
+   
+   if (-1==ioctl(fd, VIDIOCPWCSSHUTTER, &val))
+   {
+     snprintf(errmsg, ERRMSG_SIZ, "VIDIOCPWCSSHUTTER %s", strerror(errno));
+     return -1;
+  }
+  
+  return 0;
+}
+
+void V4L1_PWC::setCompression(int val)
+{
+   ioctl(fd, VIDIOCPWCSCQUAL, &val); 
+}
+
+int V4L1_PWC::getCompression()
+{
+   int gain;
+   ioctl(fd, VIDIOCPWCGCQUAL , &gain);
+   if (gain < 0) gain*=-1;
+   return gain;
+}
+
+int V4L1_PWC::setNoiseRemoval(int val, char *errmsg)
+{
+   if (-1 == ioctl(fd, VIDIOCPWCSDYNNOISE, &val))
+   {
+       snprintf(errmsg, ERRMSG_SIZ, "VIDIOCPWCGDYNNOISE %s", strerror(errno));
+       return -1;
+   }
+   
+   return 0;
+}
+
+int V4L1_PWC::getNoiseRemoval()
+{
+   int gain;
+   char msg[ERRMSG_SIZ];
+   
+   if (-1 == ioctl(fd, VIDIOCPWCGDYNNOISE , &gain)) 
+   {
+   	 snprintf(msg, ERRMSG_SIZ, "VIDIOCPWCGDYNNOISE %s", strerror(errno));
+	 cerr << msg << endl;
+   }
+      
+   cout <<"get noise = "<<gain<<endl;
+   return gain;
+}
+
+int V4L1_PWC::setSharpness(int val, char *errmsg)
+ {
+   if (-1 == ioctl(fd, VIDIOCPWCSCONTOUR, &val))
+   {
+       snprintf(errmsg, ERRMSG_SIZ, "VIDIOCPWCSCONTOUR %s", strerror(errno));
+       return -1;
+  }
+  
+  return 0;
+}
+
+int V4L1_PWC::getSharpness()
+{
+   int gain;
+   char msg[ERRMSG_SIZ];
+   
+   if (-1 == ioctl(fd, VIDIOCPWCGCONTOUR, &gain)) 
+   {
+      snprintf(msg, ERRMSG_SIZ, "VIDIOCPWCGCONTOUR %s", strerror(errno));
+      cerr << msg << endl;
+  }
+   
+   cout <<"get sharpness = "<<gain<<endl;
+   return gain;
+}
+
+int V4L1_PWC::setBackLight(bool val, char *errmsg)
+{
+   static int on=1;
+   static int off=0;
+   if (-1 == ioctl(fd,VIDIOCPWCSBACKLIGHT, &  val?&on:&off))
+   {
+        snprintf(errmsg, ERRMSG_SIZ, "VIDIOCPWCSBACKLIGHT %s", strerror(errno));
+	return -1;
+   }
+   
+   return 0;
+}
+
+bool V4L1_PWC::getBackLight()
+{
+   int val;
+   char msg[ERRMSG_SIZ];
+   
+   if (-1 == ioctl(fd,VIDIOCPWCGBACKLIGHT, & val)) 
+   {
+      snprintf(msg, ERRMSG_SIZ, "VIDIOCPWCSBACKLIGHT %s", strerror(errno));
+      cerr << msg << endl;
+   }
+
+   return val !=0;
+}
+
+int V4L1_PWC::setFlicker(bool val, char *errmsg)
+{
+   static int on=1;
+   static int off=0;
+   if (-1 == ioctl(fd,VIDIOCPWCSFLICKER, val?&on:&off))
+   {
+      snprintf(errmsg, ERRMSG_SIZ, "VIDIOCPWCSFLICKER %s", strerror(errno));
+      return -1;
+   }
+   
+   return 0;
+   
+}
+
+bool V4L1_PWC::getFlicker() 
+{
+   int val;
+   char msg[ERRMSG_SIZ];
+   
+   if (-1 == ioctl(fd,VIDIOCPWCGFLICKER, & val))
+   {
+         snprintf(msg, ERRMSG_SIZ, "VIDIOCPWCGFLICKER %s", strerror(errno));
+	 cerr << msg << endl;
+   }
+   
+   return val !=0;
+}
+
+void V4L1_PWC::setGama(int val)
+{
+   picture_format.whiteness=val;
+   setPictureSettings();
+}
+
+int V4L1_PWC::getGama() 
+{
+   return picture_format.whiteness;
+}
+
+int V4L1_PWC::setFrameRate(int value, char *errmsg)
+ {
+   window.flags = (window.flags & ~PWC_FPS_MASK) | ((value << PWC_FPS_SHIFT) & PWC_FPS_MASK);
+   if (ioctl(fd, VIDIOCSWIN, &window))
+   {
+             snprintf(errmsg, ERRMSG_SIZ, "setFrameRate %s", strerror(errno));
+	     return -1;
+   }
+   
+   ioctl(fd, VIDIOCGWIN, &window);
+   frameRate = value;
+   
+   return 0;
+   //emit exposureTime(multiplicateur_/(double)getFrameRate());
+}
+
+int V4L1_PWC::getFrameRate() 
+{
+   return ((window.flags&PWC_FPS_FRMASK)>>PWC_FPS_SHIFT); 
+}
+
+int V4L1_PWC::getWhiteBalance()
+{
+   char msg[ERRMSG_SIZ];
+   struct pwc_whitebalance tmp_whitebalance;
+   tmp_whitebalance.mode = tmp_whitebalance.manual_red = tmp_whitebalance.manual_blue = tmp_whitebalance.read_red = tmp_whitebalance.read_blue = PWC_WB_AUTO;
+   
+   if (ioctl(fd, VIDIOCPWCGAWB, &tmp_whitebalance)) 
+   {
+           snprintf(msg, ERRMSG_SIZ, "getWhiteBalance %s", strerror(errno));
+	   cerr << msg << endl;
+   }
+   else
+   {
+#if 0
+      cout << "mode="<<tmp_whitebalance.mode
+           <<" mr="<<tmp_whitebalance.manual_red
+           <<" mb="<<tmp_whitebalance.manual_blue
+           <<" ar="<<tmp_whitebalance.read_red
+           <<" ab="<<tmp_whitebalance.read_blue
+           <<endl;
+#endif
+      /* manual_red and manual_blue are garbage :-( */
+      whiteBalanceMode_=tmp_whitebalance.mode;
+   }
+            
+      return whiteBalanceMode_;
+     
+      /*switch(whiteBalanceMode_) {
+      case PWC_WB_INDOOR:
+         setProperty("WhiteBalanceMode","Indor");
+         break;
+      case PWC_WB_OUTDOOR:
+         setProperty("WhiteBalanceMode","Outdoor");
+         break;
+      case PWC_WB_FL:
+         setProperty("WhiteBalanceMode","Neon");
+         break;
+      case PWC_WB_MANUAL:
+          setProperty("WhiteBalanceMode","Manual");
+          whiteBalanceRed_=tmp_whitebalance.manual_red;
+          whiteBalanceBlue_=tmp_whitebalance.manual_blue;
+
+         break;
+      case PWC_WB_AUTO:
+         setProperty("WhiteBalanceMode","Auto");
+         whiteBalanceRed_=tmp_whitebalance.read_red;
+         whiteBalanceBlue_=tmp_whitebalance.read_blue;
+         break;
+      default:
+         setProperty("WhiteBalanceMode","???");
+      }
+         
+      emit whiteBalanceModeChange(whiteBalanceMode_);
+
+      if (((whiteBalanceMode_ == PWC_WB_AUTO) && liveWhiteBalance_)
+          || whiteBalanceMode_ != PWC_WB_AUTO) {
+         setProperty("WhiteBalanceRed",whiteBalanceRed_);
+         emit whiteBalanceRedChange(whiteBalanceRed_);
+         setProperty("WhiteBalanceBlue",whiteBalanceBlue_);   
+         emit whiteBalanceBlueChange(whiteBalanceBlue_);
+         if (guiBuild()) {         
+            remoteCTRLWBred_->show();
+            remoteCTRLWBblue_->show();
+         }
+      } else {
+         if (guiBuild()) {         
+            remoteCTRLWBred_->hide();
+            remoteCTRLWBblue_->hide();
+         }
+      }
+   }*/
+}
+
+int V4L1_PWC::setWhiteBalance(char *errmsg) 
+{
+   struct pwc_whitebalance wb;
+   wb.mode=whiteBalanceMode_;
+   if (wb.mode == PWC_WB_MANUAL)
+   {
+      wb.manual_red=whiteBalanceRed_;
+      wb.manual_blue=whiteBalanceBlue_;
+   }
+   
+   if (ioctl(fd, VIDIOCPWCSAWB, &wb))
+   {
+       snprintf(errmsg, ERRMSG_SIZ, "setWhiteBalance %s", strerror(errno)); 
+       return -1;
+   }
+   
+   return 0;
+}
+
+int V4L1_PWC::setWhiteBalanceMode(int val, char *errmsg)
+ {
+   if (val == whiteBalanceMode_) 
+      return whiteBalanceMode_;
+      
+   if (val != PWC_WB_AUTO)
+   {
+      if ( val != PWC_WB_MANUAL)
+      {
+         whiteBalanceMode_=val;
+         if (setWhiteBalance(errmsg) < 0)
+	   return -1;
+      }
+      
+      //whiteBalanceMode_=PWC_WB_AUTO;
+      whiteBalanceMode_= val;
+      if (setWhiteBalance(errmsg) < 0)
+       return -1;
+      getWhiteBalance();
+   }
+
+   /*if (guiBuild()) {
+      if (val != PWC_WB_AUTO
+          || ( liveWhiteBalance_ && (val ==PWC_WB_AUTO))) {
+         remoteCTRLWBred_->show();
+         remoteCTRLWBblue_->show();
+      } else {
+         remoteCTRLWBred_->hide();
+         remoteCTRLWBblue_->hide();
+      }
+   }*/
+   
+   whiteBalanceMode_=val;
+   if (setWhiteBalance(errmsg) < 0)
+    return -1;
+   getWhiteBalance();
+   
+   return 0;
+}
+
+int V4L1_PWC::setWhiteBalanceRed(int val, char *errmsg) 
+{
+   whiteBalanceMode_ = PWC_WB_MANUAL;
+   whiteBalanceRed_=val;
+   if (setWhiteBalance(errmsg) < 0)
+    return -1;
+    
+   return 0;
+}
+
+int V4L1_PWC::setWhiteBalanceBlue(int val, char *errmsg)
+{
+   whiteBalanceMode_ = PWC_WB_MANUAL;
+   whiteBalanceBlue_=val;
+   if (setWhiteBalance(errmsg) < 0)
+     return -1;
+     
+   return 0;
+}
+
Index: /BAORadio/libindi/v1/libs/webcam/v4l1_pwc.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/v4l1_pwc.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/v4l1_pwc.h	(revision 500)
@@ -0,0 +1,89 @@
+/*
+    Phlips webcam driver for V4L 1
+    Copyright (C) 2005 by Jasem Mutlaq <mutlaqja@ikarustech.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef V4L1_PWC_H
+#define V4L1_PWC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "videodev.h"
+#include "v4l1_base.h"
+
+class V4L1_PWC : public V4L1_Base
+{
+  public:
+   V4L1_PWC();
+   ~V4L1_PWC();
+ 
+        int connectCam(const char * devpath, char *errmsg);
+
+	/* Philips related, from QAstrocam */
+	int    saveSettings(char *errmsg);
+	void   restoreSettings();
+	void   restoreFactorySettings();
+	int    setGain(int value, char *errmsg);
+	int    getGain();
+	int    setExposure(int val, char *errmsg);
+	void   setCompression(int value);
+	int    getCompression();
+	int    setNoiseRemoval(int value, char *errmsg);
+	int    getNoiseRemoval();
+	int    setSharpness(int value, char *errmsg);
+	int    getSharpness();
+	int    setBackLight(bool val, char *errmsg);
+	bool   getBackLight();
+	int    setFlicker(bool val, char *errmsg);
+	bool   getFlicker();
+	void   setGama(int value);
+	int    getGama();
+	int    setFrameRate(int value, char *errmsg);
+	int    getFrameRate();
+	int    setWhiteBalance(char *errmsg);
+	int    getWhiteBalance();
+	int    setWhiteBalanceMode(int val, char *errmsg);
+	int    setWhiteBalanceRed(int val, char *errmsg);
+	int    setWhiteBalanceBlue(int val, char *errmsg);
+	
+	/* TODO consider the SC modded cam after this
+	void setLongExposureTime(const QString& str);
+	void setFrameRateMultiplicateur(int value);*/
+
+
+	/* Updates */
+	//void updateFrame(int d, void *p);
+
+	/* Image Size */
+	void checkSize(int & x, int & y);
+	bool setSize(int x, int y);
+
+
+        private:
+	int whiteBalanceMode_;
+	int whiteBalanceRed_;
+	int whiteBalanceBlue_;
+	int lastGain_;
+	int multiplicateur_;
+	int skippedFrame_;
+	int type_;
+
+
+};
+
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/v4l2_base.cpp
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/v4l2_base.cpp	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/v4l2_base.cpp	(revision 500)
@@ -0,0 +1,1198 @@
+/*
+    Copyright (C) 2005 by Jasem Mutlaq <mutlaqja@ikarustech.com>
+
+    Based on V4L 2 Example
+    http://v4l2spec.bytesex.org/spec-single/v4l2.html#CAPTURE-EXAMPLE
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/ 
+
+#include <iostream>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <asm/types.h>          /* for videodev2.h */
+
+#include "ccvt.h"
+#include "v4l2_base.h"
+#include "eventloop.h"
+#include "indidevapi.h"
+
+#define ERRMSGSIZ	1024
+
+#define CLEAR(x) memset (&(x), 0, sizeof (x))
+
+using namespace std;
+
+V4L2_Base::V4L2_Base()
+{
+   frameRate=10;
+   selectCallBackID = -1;
+   dropFrame = false;
+  
+   xmax = xmin = 160;
+   ymax = ymin = 120;
+
+   io		= IO_METHOD_MMAP;
+   fd           = -1;
+   buffers      = NULL;
+   n_buffers    = 0;
+
+   YBuf         = NULL;
+   UBuf         = NULL;
+   VBuf         = NULL;
+   colorBuffer  = NULL;
+   rgb24_buffer = NULL;
+   callback     = NULL;
+
+}
+
+V4L2_Base::~V4L2_Base()
+{
+
+  delete (YBuf);
+  delete (UBuf);
+  delete (VBuf);
+  delete (colorBuffer);
+  delete (rgb24_buffer);
+
+}
+
+int V4L2_Base::xioctl(int fd, int request, void *arg)
+{
+        int r;
+
+        do r = ioctl (fd, request, arg);
+        while (-1 == r && EINTR == errno);
+
+        return r;
+}
+
+int V4L2_Base::errno_exit(const char *s, char *errmsg)
+{
+        fprintf (stderr, "%s error %d, %s\n",
+                 s, errno, strerror (errno));
+     
+        snprintf(errmsg, ERRMSGSIZ, "%s error %d, %s\n", s, errno, strerror (errno));
+
+        return -1;
+} 
+
+int V4L2_Base::connectCam(const char * devpath, char *errmsg , int pixelFormat , int width , int height )
+{
+   frameRate=10;
+   selectCallBackID = -1;
+   dropFrame = false;
+
+    if (open_device (devpath, errmsg) < 0)
+      return -1;
+
+    if (init_device(errmsg, pixelFormat, width, height) < 0)
+      return -1;
+
+   cerr << "V4L 2 - All successful, returning\n";
+   return fd;
+}
+
+void V4L2_Base::disconnectCam()
+{
+   char errmsg[ERRMSGSIZ];
+   delete YBuf;
+   delete UBuf;
+   delete VBuf;
+   YBuf = UBuf = VBuf = NULL;
+   
+   if (selectCallBackID != -1)
+     rmCallback(selectCallBackID);
+     
+   stop_capturing (errmsg);
+
+   uninit_device (errmsg);
+
+   close_device ();
+     
+   fprintf(stderr, "Disconnect cam\n");
+}
+
+int V4L2_Base::read_frame(char *errmsg)
+{
+        struct v4l2_buffer buf;
+	unsigned int i;
+        //cerr << "in read Frame" << endl;
+
+	switch (io) {
+	case IO_METHOD_READ:
+    		if (-1 == read (fd, buffers[0].start, buffers[0].length)) {
+            		switch (errno) {
+            		case EAGAIN:
+                    		return 0;
+
+			case EIO:
+				/* Could ignore EIO, see spec. */
+
+				/* fall through */
+
+			default:
+				return errno_exit ("read", errmsg);
+			}
+		}
+
+    		//process_image (buffers[0].start);
+
+		break;
+
+	case IO_METHOD_MMAP:
+		CLEAR (buf);
+
+            	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+            	buf.memory = V4L2_MEMORY_MMAP;
+
+    		if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
+            		switch (errno) {
+            		case EAGAIN:
+                    		return 0;
+
+			case EIO:
+				/* Could ignore EIO, see spec. */
+
+				/* fall through */
+
+			default:
+				return errno_exit ("VIDIOC_DQBUF", errmsg);
+			}
+		}
+
+                assert (buf.index < n_buffers);
+
+                switch (fmt.fmt.pix.pixelformat)
+                {
+                  case V4L2_PIX_FMT_YUV420:
+                    memcpy(YBuf,((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width * fmt.fmt.pix.height);
+                    memcpy(UBuf,((unsigned char *) buffers[buf.index].start) + fmt.fmt.pix.width * fmt.fmt.pix.height, (fmt.fmt.pix.width/2) * (fmt.fmt.pix.height/2));
+                    memcpy(VBuf,((unsigned char *) buffers[buf.index].start) + fmt.fmt.pix.width * fmt.fmt.pix.height + (fmt.fmt.pix.width/2) * (fmt.fmt.pix.height/2), (fmt.fmt.pix.width/2) * (fmt.fmt.pix.width/2));
+		    break;
+
+                  case V4L2_PIX_FMT_YUYV:
+                     ccvt_yuyv_420p( fmt.fmt.pix.width , fmt.fmt.pix.height, buffers[buf.index].start, YBuf, UBuf, VBuf);
+		     break;
+
+                 case V4L2_PIX_FMT_RGB24:
+			RGB2YUV(fmt.fmt.pix.width, fmt.fmt.pix.height, buffers[buf.index].start, YBuf, UBuf, VBuf, 0);
+                        break;
+
+                 case V4L2_PIX_FMT_SBGGR8:
+                         bayer2rgb24(rgb24_buffer, ((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width, fmt.fmt.pix.height);
+                         break;
+                }
+                  
+                /*if (dropFrame)
+                {
+                  dropFrame = false;
+                  return 0;
+                } */
+
+                /* Call provided callback function if any */
+                 if (callback)
+                	(*callback)(uptr);
+
+		if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+			return errno_exit ("VIDIOC_QBUF", errmsg);
+
+		break;
+
+	case IO_METHOD_USERPTR:
+		CLEAR (buf);
+
+    		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    		buf.memory = V4L2_MEMORY_USERPTR;
+
+		if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
+			switch (errno) {
+			case EAGAIN:
+				return 0;
+
+			case EIO:
+				/* Could ignore EIO, see spec. */
+
+				/* fall through */
+
+			default:
+				errno_exit ("VIDIOC_DQBUF", errmsg);
+			}
+		}
+
+		for (i = 0; i < n_buffers; ++i)
+			if (buf.m.userptr == (unsigned long) buffers[i].start
+			    && buf.length == buffers[i].length)
+				break;
+
+		assert (i < n_buffers);
+
+    		//process_image ((void *) buf.m.userptr);
+
+		if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+			errno_exit ("VIDIOC_QBUF", errmsg);
+
+		break;
+	}
+
+	return 0;
+}
+
+int V4L2_Base::stop_capturing(char *errmsg)
+{
+        enum v4l2_buf_type type;
+
+	switch (io) {
+	case IO_METHOD_READ:
+		/* Nothing to do. */
+		break;
+
+	case IO_METHOD_MMAP:
+	case IO_METHOD_USERPTR:
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+                IERmCallback(selectCallBackID);
+                selectCallBackID = -1;
+
+                // N.B. I used this as a hack to solve a problem with capturing a frame
+		// long time ago. I recently tried taking this hack off, and it worked fine!
+		//dropFrame = true;
+
+		if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
+			return errno_exit ("VIDIOC_STREAMOFF", errmsg);
+
+                
+
+		break;
+	}
+
+   return 0;
+}
+
+int V4L2_Base::start_capturing(char * errmsg)
+{
+        unsigned int i;
+        enum v4l2_buf_type type;
+
+	switch (io) {
+	case IO_METHOD_READ:
+		/* Nothing to do. */
+		break;
+
+	case IO_METHOD_MMAP:
+		for (i = 0; i < n_buffers; ++i) {
+            		struct v4l2_buffer buf;
+
+        		CLEAR (buf);
+
+        		buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        		buf.memory      = V4L2_MEMORY_MMAP;
+        		buf.index       = i;
+
+        		if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                    		return errno_exit ("VIDIOC_QBUF", errmsg);
+
+		}
+		
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+		if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
+			return errno_exit ("VIDIOC_STREAMON", errmsg);
+
+                
+
+                selectCallBackID = IEAddCallback(fd, newFrame, this);
+
+		break;
+
+	case IO_METHOD_USERPTR:
+		for (i = 0; i < n_buffers; ++i) {
+            		struct v4l2_buffer buf;
+
+        		CLEAR (buf);
+
+        		buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        		buf.memory      = V4L2_MEMORY_USERPTR;
+        		buf.m.userptr	= (unsigned long) buffers[i].start;
+			buf.length      = buffers[i].length;
+
+        		if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
+                    		return errno_exit ("VIDIOC_QBUF", errmsg);
+		}
+
+
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+		if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
+			return errno_exit ("VIDIOC_STREAMON", errmsg);
+
+		break;
+	}
+
+  return 0;
+
+}
+
+void V4L2_Base::newFrame(int /*fd*/, void *p)
+{
+  char errmsg[ERRMSGSIZ];
+
+  ( (V4L2_Base *) (p))->read_frame(errmsg);
+
+}
+
+int V4L2_Base::uninit_device(char *errmsg)
+{
+
+	switch (io) {
+	case IO_METHOD_READ:
+		free (buffers[0].start);
+		break;
+
+	case IO_METHOD_MMAP:
+		for (unsigned int i = 0; i < n_buffers; ++i)
+			if (-1 == munmap (buffers[i].start, buffers[i].length))
+				return errno_exit ("munmap", errmsg);
+		break;
+
+	case IO_METHOD_USERPTR:
+		for (unsigned int i = 0; i < n_buffers; ++i)
+			free (buffers[i].start);
+		break;
+	}
+
+	free (buffers);
+
+   return 0;
+}
+
+void V4L2_Base::init_read(unsigned int buffer_size)
+{
+        buffers = (buffer *) calloc (1, sizeof (*buffers));
+
+        if (!buffers) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+
+	buffers[0].length = buffer_size;
+	buffers[0].start = malloc (buffer_size);
+
+	if (!buffers[0].start) {
+    		fprintf (stderr, "Out of memory\n");
+            	exit (EXIT_FAILURE);
+	}
+}
+
+int V4L2_Base::init_mmap(char *errmsg)
+{
+	struct v4l2_requestbuffers req;
+
+        CLEAR (req);
+
+        req.count               = 4;
+        //req.count               = 1;
+        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory              = V4L2_MEMORY_MMAP;
+
+	if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s does not support "
+                                 "memory mapping\n", dev_name);
+                        snprintf(errmsg, ERRMSGSIZ, "%s does not support "
+                                 "memory mapping\n", dev_name);
+                        return -1;
+                } else {
+                        return errno_exit ("VIDIOC_REQBUFS", errmsg);
+                }
+        }
+
+        if (req.count < 2) {
+                fprintf (stderr, "Insufficient buffer memory on %s\n",
+                         dev_name);
+                snprintf(errmsg, ERRMSGSIZ, "Insufficient buffer memory on %s\n",
+                         dev_name);
+		return -1;
+        }
+
+        buffers = (buffer *) calloc (req.count, sizeof (*buffers));
+
+        if (!buffers)
+        {
+                fprintf (stderr, "buffers. Out of memory\n");
+                strncpy(errmsg, "buffers. Out of memory\n", ERRMSGSIZ);
+                return -1;
+        }
+
+        for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
+        {
+                struct v4l2_buffer buf;
+
+                CLEAR (buf);
+
+                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory      = V4L2_MEMORY_MMAP;
+                buf.index       = n_buffers;
+
+                if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
+                        return errno_exit ("VIDIOC_QUERYBUF", errmsg);
+
+                buffers[n_buffers].length = buf.length;
+                buffers[n_buffers].start =
+                        mmap (NULL /* start anywhere */,
+                              buf.length,
+                              PROT_READ | PROT_WRITE /* required */,
+                              MAP_SHARED /* recommended */,
+                              fd, buf.m.offset);
+
+                if (MAP_FAILED == buffers[n_buffers].start)
+                        return errno_exit ("mmap", errmsg);
+        }
+
+   return 0;
+}
+
+void V4L2_Base::init_userp(unsigned int buffer_size)
+{
+	struct v4l2_requestbuffers req;
+	char errmsg[ERRMSGSIZ];
+
+        CLEAR (req);
+
+        req.count               = 4;
+        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory              = V4L2_MEMORY_USERPTR;
+
+        if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s does not support "
+                                 "user pointer i/o\n", dev_name);
+                        exit (EXIT_FAILURE);
+                } else {
+                        errno_exit ("VIDIOC_REQBUFS", errmsg);
+                }
+        }
+
+        buffers = (buffer *) calloc (4, sizeof (*buffers));
+
+        if (!buffers) {
+                fprintf (stderr, "Out of memory\n");
+                exit (EXIT_FAILURE);
+        }
+
+        for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
+                buffers[n_buffers].length = buffer_size;
+                buffers[n_buffers].start = malloc (buffer_size);
+
+                if (!buffers[n_buffers].start) {
+    			fprintf (stderr, "Out of memory\n");
+            		exit (EXIT_FAILURE);
+		}
+        }
+}
+
+int V4L2_Base::init_device(char *errmsg, int pixelFormat , int width, int height)
+{
+	unsigned int min;
+
+        if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap))
+        {
+                if (EINVAL == errno) {
+                        fprintf (stderr, "%s is no V4L2 device\n",
+                                 dev_name);
+                        snprintf(errmsg, ERRMSGSIZ, "%s is no V4L2 device\n", dev_name);
+                        return -1;
+                } else {
+                        return errno_exit ("VIDIOC_QUERYCAP", errmsg);
+                }
+        }
+
+        if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+        {
+                fprintf (stderr, "%s is no video capture device\n",
+                         dev_name);
+                snprintf(errmsg, ERRMSGSIZ, "%s is no video capture device\n", dev_name);
+                return -1;
+        }
+
+	switch (io) 
+        {
+	case IO_METHOD_READ:
+		if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
+			fprintf (stderr, "%s does not support read i/o\n",
+				 dev_name);
+                        snprintf(errmsg, ERRMSGSIZ, "%s does not support read i/o\n",
+				 dev_name);
+			return -1;
+		}
+
+		break;
+
+	case IO_METHOD_MMAP:
+	case IO_METHOD_USERPTR:
+		if (!(cap.capabilities & V4L2_CAP_STREAMING))
+                {
+			fprintf (stderr, "%s does not support streaming i/o\n",
+				 dev_name);
+                        snprintf(errmsg, ERRMSGSIZ, "%s does not support streaming i/o\n",
+				 dev_name);
+			return -1;
+		}
+
+		break;
+	}
+
+        /* Select video input, video standard and tune here. */
+
+        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+        if (-1 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
+                /* Errors ignored. */
+        }
+
+        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        crop.c = cropcap.defrect; /* reset to default */
+
+        if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
+                switch (errno) {
+                case EINVAL:
+                        /* Cropping not supported. */
+                        break;
+                default:
+                        /* Errors ignored. */
+                        break;
+                }
+        }
+
+        CLEAR (fmt);
+
+       fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       if (-1 == xioctl (fd, VIDIOC_G_FMT, &fmt))
+            return errno_exit ("VIDIOC_G_FMT", errmsg);
+
+        fmt.fmt.pix.width       = (width == -1)       ? fmt.fmt.pix.width : width; 
+        fmt.fmt.pix.height      = (height == -1)      ? fmt.fmt.pix.height : height;
+        fmt.fmt.pix.pixelformat = (pixelFormat == -1) ? fmt.fmt.pix.pixelformat : pixelFormat;
+        //fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
+
+        if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
+                return errno_exit ("VIDIOC_S_FMT", errmsg);
+
+        /* Note VIDIOC_S_FMT may change width and height. */
+
+	/* Buggy driver paranoia. */
+	min = fmt.fmt.pix.width * 2;
+	if (fmt.fmt.pix.bytesperline < min)
+		fmt.fmt.pix.bytesperline = min;
+	min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
+	if (fmt.fmt.pix.sizeimage < min)
+		fmt.fmt.pix.sizeimage = min;
+
+        /* Let's get the actual size */
+        CLEAR(fmt);
+
+        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	if (-1 == xioctl (fd, VIDIOC_G_FMT, &fmt))
+                return errno_exit ("VIDIOC_G_FMT", errmsg);
+
+        cerr << "width: " << fmt.fmt.pix.width << " - height: " << fmt.fmt.pix.height << endl;
+
+       switch (pixelFormat)
+       {
+        case V4L2_PIX_FMT_YUV420:
+         cerr << "pixel format: V4L2_PIX_FMT_YUV420" << endl;
+        break;
+
+        case V4L2_PIX_FMT_YUYV:
+          cerr << "pixel format: V4L2_PIX_FMT_YUYV" << endl;
+         break;
+
+        case V4L2_PIX_FMT_RGB24:
+          cerr << "pixel format: V4L2_PIX_FMT_RGB24" << endl;
+         break;
+
+        case V4L2_PIX_FMT_SBGGR8:
+         cerr << "pixel format: V4L2_PIX_FMT_SBGGR8" << endl;
+         break;
+
+       }
+
+        findMinMax();
+
+        allocBuffers();
+
+	switch (io)
+        {
+	case IO_METHOD_READ:
+		init_read (fmt.fmt.pix.sizeimage);
+		break;
+
+	case IO_METHOD_MMAP:
+		return init_mmap(errmsg);
+		break;
+
+	case IO_METHOD_USERPTR:
+		init_userp (fmt.fmt.pix.sizeimage);
+		break;
+	}
+
+  return 0;
+}
+
+void V4L2_Base::close_device(void)
+{
+        char errmsg[ERRMSGSIZ];
+
+        if (-1 == close (fd))
+	        errno_exit ("close", errmsg);
+
+        fd = -1;
+}
+
+int V4L2_Base::open_device(const char *devpath, char *errmsg)
+{
+        struct stat st; 
+
+        strncpy(dev_name, devpath, 64);
+
+        if (-1 == stat (dev_name, &st)) {
+                fprintf (stderr, "Cannot identify '%s': %d, %s\n",
+                         dev_name, errno, strerror (errno));
+                snprintf(errmsg, ERRMSGSIZ, "Cannot identify '%s': %d, %s\n",
+                         dev_name, errno, strerror (errno));
+                return -1;
+        }
+
+        if (!S_ISCHR (st.st_mode))
+        {
+                fprintf (stderr, "%s is no device\n", dev_name);
+                snprintf(errmsg, ERRMSGSIZ, "%s is no device\n", dev_name);
+                return -1;
+        }
+
+        fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
+
+        if (-1 == fd)
+        {
+                fprintf (stderr, "Cannot open '%s': %d, %s\n",
+                         dev_name, errno, strerror (errno));
+                snprintf(errmsg, ERRMSGSIZ, "Cannot open '%s': %d, %s\n",
+                         dev_name, errno, strerror (errno));
+                return -1;
+        }
+
+  return 0;
+}
+
+
+
+int V4L2_Base::getWidth()
+{
+  return fmt.fmt.pix.width;
+}
+
+int V4L2_Base::getHeight()
+{
+ return fmt.fmt.pix.height;
+}
+
+void V4L2_Base::setFPS(int fps)
+{
+  frameRate = 15;//fps;
+}
+
+int V4L2_Base::getFPS()
+{
+  return 15;
+}
+
+char * V4L2_Base::getDeviceName()
+{
+  return ((char *) cap.card);
+}
+
+void V4L2_Base::allocBuffers()
+{
+   delete (YBuf); YBuf = NULL;
+   delete (UBuf); UBuf = NULL;
+   delete (VBuf); VBuf = NULL;
+   delete (colorBuffer); colorBuffer = NULL;
+   delete (rgb24_buffer); rgb24_buffer = NULL;
+   
+   YBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height];
+   UBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height];
+   VBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height];
+   colorBuffer = new unsigned char[fmt.fmt.pix.width * fmt.fmt.pix.height * 4];
+
+   if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
+     rgb24_buffer = new unsigned char[fmt.fmt.pix.width * fmt.fmt.pix.height * 3];
+}
+
+void V4L2_Base::getMaxMinSize(int & x_max, int & y_max, int & x_min, int & y_min)
+{
+  x_max = xmax; y_max = ymax; x_min = xmin; y_min = ymin;
+}
+
+int V4L2_Base::setSize(int x, int y)
+{
+   char errmsg[ERRMSGSIZ];
+   int oldW, oldH;
+ 
+   oldW = fmt.fmt.pix.width;
+   oldH = fmt.fmt.pix.height;
+
+   fmt.fmt.pix.width  = x;
+   fmt.fmt.pix.height = y;
+
+   if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
+   {
+        fmt.fmt.pix.width  = oldW;
+        fmt.fmt.pix.height = oldH;
+        return errno_exit ("VIDIOC_S_FMT", errmsg);
+   }
+
+   /* PWC bug? It seems that setting the "wrong" width and height will mess something in the driver.
+      Only 160x120, 320x280, and 640x480 are accepted. If I try to set it for example to 300x200, it wii
+      get set to 320x280, which is fine, but then the video information is messed up for some reason. */
+      xioctl (fd, VIDIOC_S_FMT, &fmt);
+ 
+  
+   allocBuffers();
+
+  return 0;
+}
+
+void V4L2_Base::setContrast(int val)
+{
+   /*picture_.contrast=val;
+   updatePictureSettings();*/
+}
+
+int V4L2_Base::getContrast()
+{
+   return 255;//picture_.contrast;
+}
+
+void V4L2_Base::setBrightness(int val)
+{
+   /*picture_.brightness=val;
+   updatePictureSettings();*/
+}
+
+int V4L2_Base::getBrightness()
+{
+   return 255;//picture_.brightness;
+}
+
+void V4L2_Base::setColor(int val)
+{
+   /*picture_.colour=val;
+   updatePictureSettings();*/
+}
+
+int V4L2_Base::getColor()
+{
+   return 255; //picture_.colour;
+}
+
+void V4L2_Base::setHue(int val)
+{
+   /*picture_.hue=val;
+   updatePictureSettings();*/
+}
+
+int V4L2_Base::getHue()
+{
+   return 255;//picture_.hue;
+}
+
+void V4L2_Base::setWhiteness(int val)
+{
+   /*picture_.whiteness=val;
+   updatePictureSettings();*/
+}
+
+int V4L2_Base::getWhiteness() 
+{
+   return 255;//picture_.whiteness;
+}
+
+void V4L2_Base::setPictureSettings()
+{
+   /*if (ioctl(device_, VIDIOCSPICT, &picture_) ) {
+      cerr << "updatePictureSettings" << endl;
+   }
+   ioctl(device_, VIDIOCGPICT, &picture_);*/
+}
+
+void V4L2_Base::getPictureSettings()
+{
+   /*if (ioctl(device_, VIDIOCGPICT, &picture_) )
+   {
+      cerr << "refreshPictureSettings" << endl;
+   }*/
+}
+
+unsigned char * V4L2_Base::getY()
+{
+  if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
+      RGB2YUV(fmt.fmt.pix.width, fmt.fmt.pix.height, rgb24_buffer, YBuf, UBuf, VBuf, 0);
+
+  return YBuf;
+}
+
+unsigned char * V4L2_Base::getU()
+{
+ return UBuf;
+}
+
+unsigned char * V4L2_Base::getV()
+{
+ return VBuf;
+}
+
+unsigned char * V4L2_Base::getColorBuffer()
+{
+  //cerr << "in get color buffer " << endl;
+
+  switch (fmt.fmt.pix.pixelformat) 
+  {
+      case V4L2_PIX_FMT_YUV420:
+        ccvt_420p_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height,
+                      buffers[0].start, (void*)colorBuffer);
+      break;
+
+    case V4L2_PIX_FMT_YUYV:
+         ccvt_yuyv_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height,
+                      buffers[0].start, (void*)colorBuffer);
+         break;
+
+    case V4L2_PIX_FMT_RGB24:
+         ccvt_rgb24_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height,
+                      buffers[0].start, (void*)colorBuffer);
+         break;
+
+    case V4L2_PIX_FMT_SBGGR8:
+         ccvt_rgb24_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height,
+                      rgb24_buffer, (void*)colorBuffer);
+         break;
+
+   default:
+    break;
+  }
+
+  return colorBuffer;
+}
+
+void V4L2_Base::registerCallback(WPF *fp, void *ud)
+{
+  callback = fp;
+  uptr = ud;
+}
+
+void V4L2_Base::findMinMax()
+{
+    char errmsg[ERRMSGSIZ];
+    struct v4l2_format tryfmt;
+    CLEAR(tryfmt);
+
+    xmin = xmax = fmt.fmt.pix.width;
+    ymin = ymax = fmt.fmt.pix.height;
+
+    tryfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    tryfmt.fmt.pix.width       = 10;
+    tryfmt.fmt.pix.height      = 10;
+    tryfmt.fmt.pix.pixelformat = fmt.fmt.pix.pixelformat;
+    tryfmt.fmt.pix.field       = fmt.fmt.pix.field;
+
+    if (-1 == xioctl (fd, VIDIOC_TRY_FMT, &tryfmt))
+    {
+        errno_exit ("VIDIOC_TRY_FMT 1", errmsg);
+        return;
+    }
+   
+    xmin = tryfmt.fmt.pix.width;
+    ymin = tryfmt.fmt.pix.height;
+
+    tryfmt.fmt.pix.width       = 1600;
+    tryfmt.fmt.pix.height      = 1200;
+
+    if (-1 == xioctl (fd, VIDIOC_TRY_FMT, &tryfmt))
+    {
+                errno_exit ("VIDIOC_TRY_FMT 2", errmsg);
+                return;
+    }
+
+    xmax = tryfmt.fmt.pix.width;
+    ymax = tryfmt.fmt.pix.height;
+
+    cerr << "Min X: " << xmin << " - Max X: " << xmax << " - Min Y: " << ymin << " - Max Y: " << ymax << endl;
+}
+
+void V4L2_Base::enumerate_ctrl (void)
+{
+  char errmsg[ERRMSGSIZ];
+  CLEAR(queryctrl);
+
+  for (queryctrl.id = V4L2_CID_BASE; queryctrl.id < V4L2_CID_LASTP1; queryctrl.id++)
+  {
+        if (0 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
+        {
+               cerr << "Control " << queryctrl.name << endl;
+
+                if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+                        continue;
+
+                cerr << "Control " << queryctrl.name << endl;
+
+                if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+                        enumerate_menu ();
+        } else
+        {
+                if (errno == EINVAL)
+                        continue;
+
+                errno_exit("VIDIOC_QUERYCTRL", errmsg);
+                return;
+        }
+  }
+
+  for (queryctrl.id = V4L2_CID_PRIVATE_BASE;  ;  queryctrl.id++)
+  {
+        if (0 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
+        {
+              cerr << "Private Control " << queryctrl.name << endl;
+
+                if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+                        continue;
+
+                if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+                        enumerate_menu ();
+        } else {
+                if (errno == EINVAL)
+                        break;
+
+                errno_exit ("VIDIOC_QUERYCTRL", errmsg);
+                return;
+        }
+
+  }
+
+}
+
+void V4L2_Base::enumerate_menu (void)
+{
+  char errmsg[ERRMSGSIZ];
+  cerr << "  Menu items:" << endl;
+
+        CLEAR(querymenu);
+        querymenu.id = queryctrl.id;
+
+        for (querymenu.index = queryctrl.minimum;  querymenu.index <= queryctrl.maximum; querymenu.index++)
+         {
+                if (0 == xioctl (fd, VIDIOC_QUERYMENU, &querymenu))
+                {
+                        cerr << "  " <<  querymenu.name << endl;
+                } else
+                {
+                        errno_exit("VIDIOC_QUERYMENU", errmsg);
+                        return;
+                }
+         }
+}
+
+int  V4L2_Base::query_ctrl(unsigned int ctrl_id, double & ctrl_min, double & ctrl_max, double & ctrl_step, double & ctrl_value, char *errmsg)
+{ 
+
+    struct v4l2_control control;
+
+    CLEAR(queryctrl);
+
+    queryctrl.id = ctrl_id;
+
+   if (-1 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
+   {
+        if (errno != EINVAL) 
+                return errno_exit ("VIDIOC_QUERYCTRL", errmsg);
+                
+        else 
+        {
+                cerr << "#" << ctrl_id << " is not supported" << endl;
+                snprintf(errmsg, ERRMSGSIZ, "# %d is not supported", ctrl_id);
+		return -1;
+        }
+   } else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+   {
+        cerr << "#" << ctrl_id << " is disabled" << endl;
+        snprintf(errmsg, ERRMSGSIZ, "# %d is disabled", ctrl_id);
+        return -1;
+   }
+
+   ctrl_min   = queryctrl.minimum;
+   ctrl_max   = queryctrl.maximum;
+   ctrl_step  = queryctrl.step;
+   ctrl_value = queryctrl.default_value;
+
+   /* Get current value */
+   CLEAR(control);
+   control.id = ctrl_id;
+
+   if (0 == xioctl(fd, VIDIOC_G_CTRL, &control))
+      ctrl_value = control.value;
+
+    cerr << queryctrl.name << " -- min: " << ctrl_min << " max: " << ctrl_max << " step: " << ctrl_step << " value: " << ctrl_value << endl;
+
+    return 0;
+
+}
+
+int  V4L2_Base::queryINTControls(INumberVectorProperty *nvp)
+{
+   struct v4l2_control control;
+   char errmsg[ERRMSGSIZ];
+   CLEAR(queryctrl);
+   INumber *numbers = NULL;
+   unsigned int *num_ctrls = NULL;
+   int nnum=0;
+
+  for (queryctrl.id = V4L2_CID_BASE; queryctrl.id < V4L2_CID_LASTP1; queryctrl.id++)
+  {
+        if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
+        {
+                if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+                {
+                    cerr << queryctrl.name << " is disabled." << endl;
+                    continue;
+                }
+
+                if (queryctrl.type == V4L2_CTRL_TYPE_INTEGER)
+                {
+                   numbers = (numbers == NULL) ? (INumber *) malloc (sizeof(INumber)) :
+                                                 (INumber *) realloc (numbers, (nnum+1) * sizeof (INumber));
+
+                   num_ctrls = (num_ctrls == NULL) ? (unsigned int *) malloc  (sizeof (unsigned int)) :
+                                                     (unsigned int *) realloc (num_ctrls, (nnum+1) * sizeof (unsigned int));
+
+                   strncpy(numbers[nnum].name, ((char *) queryctrl.name) , MAXINDINAME);
+                   strncpy(numbers[nnum].label, ((char *) queryctrl.name), MAXINDILABEL);
+                   strncpy(numbers[nnum].format, "%0.f", MAXINDIFORMAT);
+                   numbers[nnum].min    = queryctrl.minimum;
+                   numbers[nnum].max    = queryctrl.maximum;
+                   numbers[nnum].step   = queryctrl.step;
+                   numbers[nnum].value  = queryctrl.default_value;
+     
+                   /* Get current value if possible */
+                   CLEAR(control);
+                   control.id = queryctrl.id;
+                   if (0 == xioctl(fd, VIDIOC_G_CTRL, &control))
+                            numbers[nnum].value = control.value;
+
+                   /* Store ID info in INumber. This is the first time ever I make use of aux0!! */
+                   num_ctrls[nnum] = queryctrl.id;
+
+                   cerr << queryctrl.name << " -- min: " << queryctrl.minimum << " max: " << queryctrl.maximum << " step: " << queryctrl.step << " value: " << numbers[nnum].value << endl;
+
+                   nnum++;
+                  
+                }
+        } else if (errno != EINVAL) {
+		if(numbers) free(numbers);
+                return errno_exit ("VIDIOC_QUERYCTRL", errmsg);
+        }
+
+   }
+
+  for (queryctrl.id = V4L2_CID_PRIVATE_BASE;  ;  queryctrl.id++)
+  {
+     if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl))
+        {
+                if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+                {
+                    cerr << queryctrl.name << " is disabled." << endl;
+                    continue;
+                }
+
+                if (queryctrl.type == V4L2_CTRL_TYPE_INTEGER)
+                {
+                   numbers = (numbers == NULL) ? (INumber *) malloc (sizeof(INumber)) :
+                                                 (INumber *) realloc (numbers, (nnum+1) * sizeof (INumber));
+
+                   num_ctrls = (num_ctrls == NULL) ? (unsigned int *) malloc  (sizeof (unsigned int)) :
+                                                     (unsigned int *) realloc (num_ctrls, (nnum+1) * sizeof (unsigned int));
+
+                   strncpy(numbers[nnum].name, ((char *) queryctrl.name) , MAXINDINAME);
+                   strncpy(numbers[nnum].label, ((char *) queryctrl.name), MAXINDILABEL);
+                   strncpy(numbers[nnum].format, "%0.f", MAXINDIFORMAT);
+                   numbers[nnum].min    = queryctrl.minimum;
+                   numbers[nnum].max    = queryctrl.maximum;
+                   numbers[nnum].step   = queryctrl.step;
+                   numbers[nnum].value  = queryctrl.default_value;
+     
+                   /* Get current value if possible */
+                   CLEAR(control);
+                   control.id = queryctrl.id;
+                   if (0 == xioctl(fd, VIDIOC_G_CTRL, &control))
+                            numbers[nnum].value = control.value;
+
+                   /* Store ID info in INumber. This is the first time ever I make use of aux0!! */
+                   num_ctrls[nnum] = queryctrl.id;
+     
+                   nnum++;
+                  
+                }
+         }
+         else break;
+   } 
+
+  /* Store numbers in aux0 */
+  for (int i=0; i < nnum; i++)
+      numbers[i].aux0 = &num_ctrls[i];
+
+  nvp->np  = numbers;
+  nvp->nnp = nnum;
+
+  return nnum;
+
+}
+
+int  V4L2_Base::setINTControl(unsigned int ctrl_id, double new_value, char *errmsg)
+{
+   struct v4l2_control control;
+
+   CLEAR(control);
+
+   //cerr << "The id is " << ctrl_id << " new value is " << new_value << endl;
+
+   control.id = ctrl_id;
+   control.value = (int) new_value;
+
+   if (-1 == xioctl(fd, VIDIOC_S_CTRL, &control))
+         return errno_exit ("VIDIOC_S_CTRL", errmsg);
+
+   return 0;
+}
+
Index: /BAORadio/libindi/v1/libs/webcam/v4l2_base.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/v4l2_base.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/v4l2_base.h	(revision 500)
@@ -0,0 +1,141 @@
+/*
+    Copyright (C) 2005 by Jasem Mutlaq <mutlaqja@ikarustech.com>
+
+    Based on V4L 2 Example
+    http://v4l2spec.bytesex.org/spec-single/v4l2.html#CAPTURE-EXAMPLE
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef V4L2_BASE_H
+#define V4L2_BASE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "videodev2.h"
+#include "eventloop.h"
+#include "indidevapi.h"
+
+#define VIDEO_COMPRESSION_LEVEL		4
+
+class V4L2_Base
+{
+  public:
+   V4L2_Base();
+   virtual ~V4L2_Base();
+
+   typedef enum { IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR } io_method;
+
+   struct buffer
+   {
+        void *                  start;
+        size_t                  length;
+   };
+
+  /* Connection */
+  virtual int connectCam(const char * devpath, char *errmsg, int pixelFormat = -1 , int width = -1, int height = -1);
+  virtual void disconnectCam();
+  char * getDeviceName();
+
+  /* Image settings */
+  int  getBrightness();
+  int  getContrast();
+  int  getColor();
+  int  getHue();
+  int  getWhiteness();
+  void setContrast(int val);
+  void setBrightness(int val);
+  void setColor(int val);
+  void setHue(int val);
+  void setWhiteness(int val);
+
+  /* Updates */
+  void callFrame(void *p);
+  void setPictureSettings();
+  void getPictureSettings();
+
+  /* Image Size */
+  int getWidth();
+  int getHeight();
+  virtual int setSize(int x, int y);
+  virtual void getMaxMinSize(int & x_max, int & y_max, int & x_min, int & y_min);
+
+  /* Frame rate */
+  void setFPS(int fps);
+  int  getFPS();
+
+  void allocBuffers();
+  unsigned char * getY();
+  unsigned char * getU();
+  unsigned char * getV();
+  unsigned char * getColorBuffer();
+
+  void registerCallback(WPF *fp, void *ud);
+
+  int start_capturing(char *errmsg);
+  int stop_capturing(char *errmsg);
+  static void newFrame(int fd, void *p);
+  
+  void enumerate_ctrl (void);
+  void enumerate_menu (void);
+  int  queryINTControls(INumberVectorProperty *nvp);
+  int  setINTControl(unsigned int ctrl_id, double new_value, char *errmsg);
+
+  int  query_ctrl(unsigned int ctrl_id, double & ctrl_min, double & ctrl_max, double & ctrl_step, double & ctrl_value, char *errmsg);
+
+  protected:
+
+  int xioctl(int fd, int request, void *arg);
+  int read_frame(char *errsg);
+  int uninit_device(char *errmsg);
+  int open_device(const char *devpath, char *errmsg);
+  int init_device(char *errmsg, int pixelFormat , int width, int height); 
+  int init_mmap(char *errmsg);
+  int errno_exit(const char *s, char *errmsg);
+  
+  void close_device(void);
+  void init_userp(unsigned int buffer_size);
+  void init_read(unsigned int buffer_size);
+
+  void findMinMax();
+  
+  struct v4l2_capability cap;
+  struct v4l2_cropcap cropcap;
+  struct v4l2_crop crop;
+  struct v4l2_format fmt;
+
+  struct v4l2_queryctrl queryctrl;
+  struct v4l2_querymenu querymenu;
+
+  WPF *callback;
+  void *uptr;
+  char          dev_name[64];
+  io_method	io;
+  int           fd;
+  struct buffer *buffers;
+  unsigned int  n_buffers;
+
+  bool		dropFrame;
+
+  
+  int frameRate;
+  int  xmax, xmin, ymax, ymin;
+  int  selectCallBackID;
+  unsigned char * YBuf,*UBuf,*VBuf, *colorBuffer, *rgb24_buffer;
+
+};
+   
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/vcvt.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/vcvt.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/vcvt.h	(revision 500)
@@ -0,0 +1,73 @@
+/* 
+   (C) 2001 Nemosoft Unv.    <nemosoft@smcc.demon.nl>
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+
+/* 'Viewport' conversion routines. These functions convert from one colour
+   space to another, taking into account that the source image has a smaller
+   size than the view, and is placed inside the view:
+
+        +-------view.x------------+
+        |                         |
+        |     +---image.x---+     |
+        |     |             |     |
+        |     |             |     |
+        |     +-------------+     |
+        |                         |
+        +-------------------------+
+
+   The image should always be smaller than the view. The offset (top-left
+   corner of the image) should be precomputed, so you can place the image 
+   anywhere in the view.
+
+   The functions take these parameters:
+   - width 	image width (in pixels)
+   - height	image height (in pixels)
+   - plus	view width (in pixels)
+   *src		pointer at start of image
+   *dst		pointer at offset (!) in view
+*/
+
+
+#ifndef VCVT_H
+#define VCVT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Functions in vcvt_i386.S/vcvt_c.c */
+/* 4:2:0 YUV interlaced to RGB/BGR */
+void vcvt_420i_bgr24(int width, int height, int plus, void *src, void *dst);
+void vcvt_420i_rgb24(int width, int height, int plus, void *src, void *dst);
+void vcvt_420i_bgr32(int width, int height, int plus, void *src, void *dst);
+void vcvt_420i_rgb32(int width, int height, int plus, void *src, void *dst);
+
+
+/* Go from 420i to other yuv formats */
+void vcvt_420i_420p(int width, int height, int plus, void *src, void *dsty, void *dstu, void *dstv);
+void vcvt_420i_yuyv(int width, int height, int plus, void *src, void *dst);
+
+#if 0
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /BAORadio/libindi/v1/libs/webcam/videodev.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/videodev.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/videodev.h	(revision 500)
@@ -0,0 +1,365 @@
+/*
+ Copyright 2006  Bill Dirks <bdirks@pacbell.net>
+ 		Justin Schoeman
+ 		et al.
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef __LINUX_VIDEODEV_H
+#define __LINUX_VIDEODEV_H
+
+#define VID_TYPE_CAPTURE	1	/* Can capture */
+#define VID_TYPE_TUNER		2	/* Can tune */
+#define VID_TYPE_TELETEXT	4	/* Does teletext */
+#define VID_TYPE_OVERLAY	8	/* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY	16	/* Overlay by chromakey */
+#define VID_TYPE_CLIPPING	32	/* Can clip */
+#define VID_TYPE_FRAMERAM	64	/* Uses the frame buffer memory */
+#define VID_TYPE_SCALES		128	/* Scalable */
+#define VID_TYPE_MONOCHROME	256	/* Monochrome only */
+#define VID_TYPE_SUBCAPTURE	512	/* Can capture subareas of the image */
+#define VID_TYPE_MPEG_DECODER	1024	/* Can decode MPEG streams */
+#define VID_TYPE_MPEG_ENCODER	2048	/* Can encode MPEG streams */
+#define VID_TYPE_MJPEG_DECODER	4096	/* Can decode MJPEG streams */
+#define VID_TYPE_MJPEG_ENCODER	8192	/* Can encode MJPEG streams */
+
+struct video_capability
+{
+	char name[32];
+	int type;
+	int channels;	/* Num channels */
+	int audios;	/* Num audio devices */
+	int maxwidth;	/* Supported width */
+	int maxheight;	/* And height */
+	int minwidth;	/* Supported width */
+	int minheight;	/* And height */
+};
+
+
+struct video_channel
+{
+	int channel;
+	char name[32];
+	int tuners;
+	unsigned int  flags;
+#define VIDEO_VC_TUNER		1	/* Channel has a tuner */
+#define VIDEO_VC_AUDIO		2	/* Channel has audio */
+	unsigned short  type;
+#define VIDEO_TYPE_TV		1
+#define VIDEO_TYPE_CAMERA	2	
+	unsigned short norm;			/* Norm set by channel */
+};
+
+struct video_tuner
+{
+	int tuner;
+	char name[32];
+	unsigned long rangelow, rangehigh;	/* Tuner range */
+	unsigned int flags;
+#define VIDEO_TUNER_PAL		1
+#define VIDEO_TUNER_NTSC	2
+#define VIDEO_TUNER_SECAM	4
+#define VIDEO_TUNER_LOW		8	/* Uses KHz not MHz */
+#define VIDEO_TUNER_NORM	16	/* Tuner can set norm */
+#define VIDEO_TUNER_STEREO_ON	128	/* Tuner is seeing stereo */
+#define VIDEO_TUNER_RDS_ON      256     /* Tuner is seeing an RDS datastream */
+#define VIDEO_TUNER_MBS_ON      512     /* Tuner is seeing an MBS datastream */
+	unsigned short mode;			/* PAL/NTSC/SECAM/OTHER */
+#define VIDEO_MODE_PAL		0
+#define VIDEO_MODE_NTSC		1
+#define VIDEO_MODE_SECAM	2
+#define VIDEO_MODE_AUTO		3
+	unsigned short signal;			/* Signal strength 16bit scale */
+};
+
+struct video_picture
+{
+	unsigned short	brightness;
+	unsigned short	hue;
+	unsigned short	colour;
+	unsigned short	contrast;
+	unsigned short	whiteness;	/* Black and white only */
+	unsigned short	depth;		/* Capture depth */
+	unsigned short   palette;	/* Palette in use */
+#define VIDEO_PALETTE_GREY	1	/* Linear greyscale */
+#define VIDEO_PALETTE_HI240	2	/* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565	3	/* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24	4	/* 24bit RGB */
+#define VIDEO_PALETTE_RGB32	5	/* 32bit RGB */	
+#define VIDEO_PALETTE_RGB555	6	/* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422	7	/* YUV422 capture */
+#define VIDEO_PALETTE_YUYV	8
+#define VIDEO_PALETTE_UYVY	9	/* The great thing about standards is ... */
+#define VIDEO_PALETTE_YUV420	10
+#define VIDEO_PALETTE_YUV411	11	/* YUV411 capture */
+#define VIDEO_PALETTE_RAW	12	/* RAW capture (BT848) */
+#define VIDEO_PALETTE_YUV422P	13	/* YUV 4:2:2 Planar */
+#define VIDEO_PALETTE_YUV411P	14	/* YUV 4:1:1 Planar */
+#define VIDEO_PALETTE_YUV420P	15	/* YUV 4:2:0 Planar */
+#define VIDEO_PALETTE_YUV410P	16	/* YUV 4:1:0 Planar */
+#define VIDEO_PALETTE_PLANAR	13	/* start of planar entries */
+#define VIDEO_PALETTE_COMPONENT 7	/* start of component entries */
+};
+
+struct video_audio
+{
+	int	audio;		/* Audio channel */
+	unsigned short	volume;		/* If settable */
+	unsigned short	bass, treble;
+	unsigned int	flags;
+#define VIDEO_AUDIO_MUTE	1
+#define VIDEO_AUDIO_MUTABLE	2
+#define VIDEO_AUDIO_VOLUME	4
+#define VIDEO_AUDIO_BASS	8
+#define VIDEO_AUDIO_TREBLE	16	
+#define VIDEO_AUDIO_BALANCE	32
+	char    name[16];
+#define VIDEO_SOUND_MONO	1
+#define VIDEO_SOUND_STEREO	2
+#define VIDEO_SOUND_LANG1	4
+#define VIDEO_SOUND_LANG2	8
+        unsigned short   mode;
+        unsigned short	balance;	/* Stereo balance */
+        unsigned short	step;		/* Step actual volume uses */
+};
+
+struct video_clip
+{
+	int	x,y;
+	int	width, height;
+	struct	video_clip *next;	/* For user use/driver use only */
+};
+
+struct video_window
+{
+	unsigned int	x,y;			/* Position of window */
+	unsigned int	width,height;		/* Its size */
+	unsigned int	chromakey;
+	unsigned int	flags;
+	struct	video_clip *clips;	/* Set only */
+	int	clipcount;
+#define VIDEO_WINDOW_INTERLACE	1
+#define VIDEO_WINDOW_CHROMAKEY	16	/* Overlay by chromakey */
+#define VIDEO_CLIP_BITMAP	-1
+/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
+#define VIDEO_CLIPMAP_SIZE	(128 * 625)
+};
+
+struct video_capture
+{
+	unsigned int 	x,y;			/* Offsets into image */
+	unsigned int	width, height;		/* Area to capture */
+	unsigned short	decimation;		/* Decimation divider */
+	unsigned short	flags;			/* Flags for capture */
+#define VIDEO_CAPTURE_ODD		0	/* Temporal */
+#define VIDEO_CAPTURE_EVEN		1
+};
+
+struct video_buffer
+{
+	void	*base;
+	int	height,width;
+	int	depth;
+	int	bytesperline;
+};
+
+struct video_mmap
+{
+	unsigned	int frame;		/* Frame (0 - n) for double buffer */
+	int		height,width;
+	unsigned	int format;		/* should be VIDEO_PALETTE_* */
+};
+
+struct video_key
+{
+	unsigned char key[8];
+	unsigned int	flags;
+};
+
+
+#define VIDEO_MAX_FRAME		32
+
+struct video_mbuf
+{
+	int	size;		/* Total memory to map */
+	int	frames;		/* Frames */
+	int	offsets[VIDEO_MAX_FRAME];
+};
+	
+
+#define 	VIDEO_NO_UNIT	(-1)
+
+	
+struct video_unit
+{
+	int 	video;		/* Video minor */
+	int	vbi;		/* VBI minor */
+	int	radio;		/* Radio minor */
+	int	audio;		/* Audio minor */
+	int	teletext;	/* Teletext minor */
+};
+
+struct vbi_format {
+	unsigned int	sampling_rate;	/* in Hz */
+	unsigned int	samples_per_line;
+	unsigned int	sample_format;	/* VIDEO_PALETTE_RAW only (1 byte) */
+	int	start[2];	/* starting line for each frame */
+	unsigned int	count[2];	/* count of lines for each frame */
+	unsigned int	flags;
+#define	VBI_UNSYNC	1	/* can distingues between top/bottom field */
+#define	VBI_INTERLACED	2	/* lines are interlaced */
+};
+
+/* video_info is biased towards hardware mpeg encode/decode */
+/* but it could apply generically to any hardware compressor/decompressor */
+struct video_info
+{
+	unsigned int	frame_count;	/* frames output since decode/encode began */
+	unsigned int	h_size;		/* current unscaled horizontal size */
+	unsigned int	v_size;		/* current unscaled veritcal size */
+	unsigned int	smpte_timecode;	/* current SMPTE timecode (for current GOP) */
+	unsigned int	picture_type;	/* current picture type */
+	unsigned int	temporal_reference;	/* current temporal reference */
+	unsigned char 	user_data[256];	/* user data last found in compressed stream */
+	/* user_data[0] contains user data flags, user_data[1] has count */
+};
+
+/* generic structure for setting playback modes */
+struct video_play_mode
+{
+	int	mode;
+	int	p1;
+	int	p2;
+};
+
+/* for loading microcode / fpga programming */
+struct video_code
+{
+	char	loadwhat[16];	/* name or tag of file being passed */
+	int	datasize;
+	unsigned char	*data;
+};
+
+#define VIDIOCGCAP		_IOR('v',1,struct video_capability)	/* Get capabilities */
+#define VIDIOCGCHAN		_IOWR('v',2,struct video_channel)	/* Get channel info (sources) */
+#define VIDIOCSCHAN		_IOW('v',3,struct video_channel)	/* Set channel 	*/
+#define VIDIOCGTUNER		_IOWR('v',4,struct video_tuner)		/* Get tuner abilities */
+#define VIDIOCSTUNER		_IOW('v',5,struct video_tuner)		/* Tune the tuner for the current channel */
+#define VIDIOCGPICT		_IOR('v',6,struct video_picture)	/* Get picture properties */
+#define VIDIOCSPICT		_IOW('v',7,struct video_picture)	/* Set picture properties */
+#define VIDIOCCAPTURE		_IOW('v',8,int)				/* Start, end capture */
+#define VIDIOCGWIN		_IOR('v',9, struct video_window)	/* Get the video overlay window */
+#define VIDIOCSWIN		_IOW('v',10, struct video_window)	/* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
+#define VIDIOCGFBUF		_IOR('v',11, struct video_buffer)	/* Get frame buffer */
+#define VIDIOCSFBUF		_IOW('v',12, struct video_buffer)	/* Set frame buffer - root only */
+#define VIDIOCKEY		_IOR('v',13, struct video_key)		/* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
+#define VIDIOCGFREQ		_IOR('v',14, unsigned long)		/* Set tuner */
+#define VIDIOCSFREQ		_IOW('v',15, unsigned long)		/* Set tuner */
+#define VIDIOCGAUDIO		_IOR('v',16, struct video_audio)	/* Get audio info */
+#define VIDIOCSAUDIO		_IOW('v',17, struct video_audio)	/* Audio source, mute etc */
+#define VIDIOCSYNC		_IOW('v',18, int)			/* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE		_IOW('v',19, struct video_mmap)		/* Grab frames */
+#define VIDIOCGMBUF		_IOR('v',20, struct video_mbuf)		/* Memory map buffer info */
+#define VIDIOCGUNIT		_IOR('v',21, struct video_unit)		/* Get attached units */
+#define VIDIOCGCAPTURE		_IOR('v',22, struct video_capture)	/* Get subcapture */
+#define VIDIOCSCAPTURE		_IOW('v',23, struct video_capture)	/* Set subcapture */
+#define VIDIOCSPLAYMODE		_IOW('v',24, struct video_play_mode)	/* Set output video mode/feature */
+#define VIDIOCSWRITEMODE	_IOW('v',25, int)			/* Set write mode */
+#define VIDIOCGPLAYINFO		_IOR('v',26, struct video_info)		/* Get current playback info from hardware */
+#define VIDIOCSMICROCODE	_IOW('v',27, struct video_code)		/* Load microcode into hardware */
+#define	VIDIOCGVBIFMT		_IOR('v',28, struct vbi_format)		/* Get VBI information */
+#define	VIDIOCSVBIFMT		_IOW('v',29, struct vbi_format)		/* Set VBI information */
+
+
+#define BASE_VIDIOCPRIVATE	192		/* 192-255 are private */
+
+/* VIDIOCSWRITEMODE */
+#define VID_WRITE_MPEG_AUD		0
+#define VID_WRITE_MPEG_VID		1
+#define VID_WRITE_OSD			2
+#define VID_WRITE_TTX			3
+#define VID_WRITE_CC			4
+#define VID_WRITE_MJPEG			5
+
+/* VIDIOCSPLAYMODE */
+#define VID_PLAY_VID_OUT_MODE		0
+	/* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */
+#define VID_PLAY_GENLOCK		1
+	/* p1: 0 = OFF, 1 = ON */
+	/* p2: GENLOCK FINE DELAY value */ 
+#define VID_PLAY_NORMAL			2
+#define VID_PLAY_PAUSE			3
+#define VID_PLAY_SINGLE_FRAME		4
+#define VID_PLAY_FAST_FORWARD		5
+#define VID_PLAY_SLOW_MOTION		6
+#define VID_PLAY_IMMEDIATE_NORMAL	7
+#define VID_PLAY_SWITCH_CHANNELS	8
+#define VID_PLAY_FREEZE_FRAME		9
+#define VID_PLAY_STILL_MODE		10
+#define VID_PLAY_MASTER_MODE		11
+	/* p1: see below */
+#define		VID_PLAY_MASTER_NONE	1
+#define		VID_PLAY_MASTER_VIDEO	2
+#define		VID_PLAY_MASTER_AUDIO	3
+#define VID_PLAY_ACTIVE_SCANLINES	12
+	/* p1 = first active; p2 = last active */
+#define VID_PLAY_RESET			13
+#define VID_PLAY_END_MARK		14
+
+
+
+#define VID_HARDWARE_BT848	1
+#define VID_HARDWARE_QCAM_BW	2
+#define VID_HARDWARE_PMS	3
+#define VID_HARDWARE_QCAM_C	4
+#define VID_HARDWARE_PSEUDO	5
+#define VID_HARDWARE_SAA5249	6
+#define VID_HARDWARE_AZTECH	7
+#define VID_HARDWARE_SF16MI	8
+#define VID_HARDWARE_RTRACK	9
+#define VID_HARDWARE_ZOLTRIX	10
+#define VID_HARDWARE_SAA7146    11
+#define VID_HARDWARE_VIDEUM	12	/* Reserved for Winnov videum */
+#define VID_HARDWARE_RTRACK2	13
+#define VID_HARDWARE_PERMEDIA2	14	/* Reserved for Permedia2 */
+#define VID_HARDWARE_RIVA128	15	/* Reserved for RIVA 128 */
+#define VID_HARDWARE_PLANB	16	/* PowerMac motherboard video-in */
+#define VID_HARDWARE_BROADWAY	17	/* Broadway project */
+#define VID_HARDWARE_GEMTEK	18
+#define VID_HARDWARE_TYPHOON	19
+#define VID_HARDWARE_VINO	20	/* SGI Indy Vino */
+#define VID_HARDWARE_CADET	21	/* Cadet radio */
+#define VID_HARDWARE_TRUST	22	/* Trust FM Radio */
+#define VID_HARDWARE_TERRATEC	23	/* TerraTec ActiveRadio */
+#define VID_HARDWARE_CPIA	24
+#define VID_HARDWARE_ZR36120	25	/* Zoran ZR36120/ZR36125 */
+#define VID_HARDWARE_ZR36067	26	/* Zoran ZR36067/36060 */
+#define VID_HARDWARE_OV511	27	
+#define VID_HARDWARE_ZR356700	28	/* Zoran 36700 series */
+#define VID_HARDWARE_W9966	29
+#define VID_HARDWARE_SE401	30	/* SE401 USB webcams */
+#define VID_HARDWARE_PWC	31	/* Philips webcams */
+#define VID_HARDWARE_MEYE	32	/* Sony Vaio MotionEye cameras */
+#define VID_HARDWARE_CPIA2	33
+#define VID_HARDWARE_VICAM      34
+#define VID_HARDWARE_SF16FMR2	35
+#define VID_HARDWARE_W9968CF    36
+#endif /* __LINUX_VIDEODEV_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
Index: /BAORadio/libindi/v1/libs/webcam/videodev2.h
===================================================================
--- /BAORadio/libindi/v1/libs/webcam/videodev2.h	(revision 500)
+++ /BAORadio/libindi/v1/libs/webcam/videodev2.h	(revision 500)
@@ -0,0 +1,925 @@
+/*
+ Copyright 2006  Bill Dirks <bdirks@pacbell.net>
+ 		Justin Schoeman
+ 		et al.
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifndef __LINUX_VIDEODEV2_H
+#define __LINUX_VIDEODEV2_H
+/*
+ *	Video for Linux Two
+ *
+ *	Header file for v4l or V4L2 drivers and applications, for
+ *	Linux kernels 2.2.x or 2.4.x.
+ *
+ *	See http://bytesex.org/v4l/ for API specs and other
+ *	v4l2 documentation.
+ *
+ *	Author: Bill Dirks <bdirks@pacbell.net>
+ *		Justin Schoeman
+ *		et al.
+ */
+/*
+ *	M I S C E L L A N E O U S
+ */
+
+/*  Four-character-code (FOURCC) */
+#define v4l2_fourcc(a,b,c,d)\
+        (((unsigned int)(a)<<0)|((unsigned int)(b)<<8)|((unsigned int)(c)<<16)|((unsigned int)(d)<<24))
+
+/*
+ *	E N U M S
+ */
+enum v4l2_field {
+	V4L2_FIELD_ANY        = 0, /* driver can choose from none,
+				      top, bottom, interlaced
+				      depending on whatever it thinks
+				      is approximate ... */
+	V4L2_FIELD_NONE       = 1, /* this device has no fields ... */
+	V4L2_FIELD_TOP        = 2, /* top field only */
+	V4L2_FIELD_BOTTOM     = 3, /* bottom field only */
+	V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */
+	V4L2_FIELD_SEQ_TB     = 5, /* both fields sequential into one
+				      buffer, top-bottom order */
+	V4L2_FIELD_SEQ_BT     = 6, /* same as above + bottom-top order */
+	V4L2_FIELD_ALTERNATE  = 7  /* both fields alternating into
+				      separate buffers */
+};
+#define V4L2_FIELD_HAS_TOP(field)	\
+	((field) == V4L2_FIELD_TOP 	||\
+	 (field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_SEQ_TB	||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTTOM(field)	\
+	((field) == V4L2_FIELD_BOTTOM 	||\
+	 (field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_SEQ_TB	||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTH(field)	\
+	((field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_SEQ_TB	||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+
+enum v4l2_buf_type {
+	V4L2_BUF_TYPE_VIDEO_CAPTURE  = 1,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT   = 2,
+	V4L2_BUF_TYPE_VIDEO_OVERLAY  = 3,
+	V4L2_BUF_TYPE_VBI_CAPTURE    = 4,
+	V4L2_BUF_TYPE_VBI_OUTPUT     = 5,
+	V4L2_BUF_TYPE_PRIVATE        = 0x80
+};
+
+enum v4l2_ctrl_type {
+	V4L2_CTRL_TYPE_INTEGER	     = 1,
+	V4L2_CTRL_TYPE_BOOLEAN	     = 2,
+	V4L2_CTRL_TYPE_MENU	     = 3,
+	V4L2_CTRL_TYPE_BUTTON	     = 4
+};
+
+enum v4l2_tuner_type {
+	V4L2_TUNER_RADIO	     = 1,
+	V4L2_TUNER_ANALOG_TV	     = 2
+};
+
+enum v4l2_memory {
+	V4L2_MEMORY_MMAP             = 1,
+	V4L2_MEMORY_USERPTR          = 2,
+	V4L2_MEMORY_OVERLAY          = 3
+};
+
+/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
+enum v4l2_colorspace {
+	/* ITU-R 601 -- broadcast NTSC/PAL */
+	V4L2_COLORSPACE_SMPTE170M     = 1,
+
+	/* 1125-Line (US) HDTV */
+	V4L2_COLORSPACE_SMPTE240M     = 2,
+
+	/* HD and modern captures. */
+	V4L2_COLORSPACE_REC709        = 3,
+	
+	/* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
+	V4L2_COLORSPACE_BT878         = 4,
+	
+	/* These should be useful.  Assume 601 extents. */
+	V4L2_COLORSPACE_470_SYSTEM_M  = 5,
+	V4L2_COLORSPACE_470_SYSTEM_BG = 6,
+	
+	/* I know there will be cameras that send this.  So, this is
+	 * unspecified chromaticities and full 0-255 on each of the
+	 * Y'CbCr components
+	 */
+	V4L2_COLORSPACE_JPEG          = 7,
+	
+	/* For RGB colourspaces, this is probably a good start. */
+	V4L2_COLORSPACE_SRGB          = 8
+};
+
+enum v4l2_priority {
+	V4L2_PRIORITY_UNSET       = 0,  /* not initialized */
+	V4L2_PRIORITY_BACKGROUND  = 1,
+	V4L2_PRIORITY_INTERACTIVE = 2,
+	V4L2_PRIORITY_RECORD      = 3,
+	V4L2_PRIORITY_DEFAULT     = V4L2_PRIORITY_INTERACTIVE
+};
+
+struct v4l2_rect {
+	int   left;
+	int   top;
+	int   width;
+	int   height;
+};
+
+struct v4l2_fract {
+	unsigned int   numerator;
+	unsigned int   denominator;
+};
+
+/*
+ *	D R I V E R   C A P A B I L I T I E S
+ */
+struct v4l2_capability
+{
+	unsigned char	driver[16];	/* i.e. "bttv" */
+	unsigned char	card[32];	/* i.e. "Hauppauge WinTV" */
+	unsigned char	bus_info[32];	/* "PCI:" + pci_name(pci_dev) */
+	unsigned int   version;        /* should use KERNEL_VERSION() */
+	unsigned int	capabilities;	/* Device capabilities */
+	unsigned int	reserved[4];
+};
+
+/* Values for 'capabilities' field */
+#define V4L2_CAP_VIDEO_CAPTURE	0x00000001  /* Is a video capture device */
+#define V4L2_CAP_VIDEO_OUTPUT	0x00000002  /* Is a video output device */
+#define V4L2_CAP_VIDEO_OVERLAY	0x00000004  /* Can do video overlay */
+#define V4L2_CAP_VBI_CAPTURE	0x00000010  /* Is a VBI capture device */
+#define V4L2_CAP_VBI_OUTPUT	0x00000020  /* Is a VBI output device */
+#define V4L2_CAP_RDS_CAPTURE	0x00000100  /* RDS data capture */
+
+#define V4L2_CAP_TUNER		0x00010000  /* has a tuner */
+#define V4L2_CAP_AUDIO		0x00020000  /* has audio support */
+#define V4L2_CAP_RADIO		0x00040000  /* is a radio device */
+
+#define V4L2_CAP_READWRITE      0x01000000  /* read/write systemcalls */
+#define V4L2_CAP_ASYNCIO        0x02000000  /* async I/O */
+#define V4L2_CAP_STREAMING      0x04000000  /* streaming I/O ioctls */
+
+/*
+ *	V I D E O   I M A G E   F O R M A T
+ */
+
+struct v4l2_pix_format
+{
+	unsigned int         	 	width;
+	unsigned int	         	height;
+	unsigned int	         	pixelformat;
+	enum v4l2_field  	field;
+	unsigned int            	bytesperline;	/* for padding, zero if unused */
+	unsigned int          	 	sizeimage;
+        enum v4l2_colorspace	colorspace;
+	unsigned int			priv;		/* private data, depends on pixelformat */
+};
+
+/*           Pixel format    FOURCC                  depth  Description   */
+#define V4L2_PIX_FMT_RGB332  v4l2_fourcc('R','G','B','1') /*  8  RGB-3-3-2     */
+#define V4L2_PIX_FMT_RGB555  v4l2_fourcc('R','G','B','O') /* 16  RGB-5-5-5     */
+#define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R','G','B','P') /* 16  RGB-5-6-5     */
+#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16  RGB-5-5-5 BE  */
+#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16  RGB-5-6-5 BE  */
+#define V4L2_PIX_FMT_BGR24   v4l2_fourcc('B','G','R','3') /* 24  BGR-8-8-8     */
+#define V4L2_PIX_FMT_RGB24   v4l2_fourcc('R','G','B','3') /* 24  RGB-8-8-8     */
+#define V4L2_PIX_FMT_BGR32   v4l2_fourcc('B','G','R','4') /* 32  BGR-8-8-8-8   */
+#define V4L2_PIX_FMT_RGB32   v4l2_fourcc('R','G','B','4') /* 32  RGB-8-8-8-8   */
+#define V4L2_PIX_FMT_GREY    v4l2_fourcc('G','R','E','Y') /*  8  Greyscale     */
+#define V4L2_PIX_FMT_YVU410  v4l2_fourcc('Y','V','U','9') /*  9  YVU 4:1:0     */
+#define V4L2_PIX_FMT_YVU420  v4l2_fourcc('Y','V','1','2') /* 12  YVU 4:2:0     */
+#define V4L2_PIX_FMT_YUYV    v4l2_fourcc('Y','U','Y','V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_UYVY    v4l2_fourcc('U','Y','V','Y') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16  YVU422 planar */
+#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16  YVU411 planar */
+#define V4L2_PIX_FMT_Y41P    v4l2_fourcc('Y','4','1','P') /* 12  YUV 4:1:1     */
+
+/* two planes -- one Y, one Cr + Cb interleaved  */
+#define V4L2_PIX_FMT_NV12    v4l2_fourcc('N','V','1','2') /* 12  Y/CbCr 4:2:0  */
+#define V4L2_PIX_FMT_NV21    v4l2_fourcc('N','V','2','1') /* 12  Y/CrCb 4:2:0  */
+
+/*  The following formats are not defined in the V4L2 specification */
+#define V4L2_PIX_FMT_YUV410  v4l2_fourcc('Y','U','V','9') /*  9  YUV 4:1:0     */
+#define V4L2_PIX_FMT_YUV420  v4l2_fourcc('Y','U','1','2') /* 12  YUV 4:2:0     */
+#define V4L2_PIX_FMT_YYUV    v4l2_fourcc('Y','Y','U','V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_HI240   v4l2_fourcc('H','I','2','4') /*  8  8-bit color   */
+
+/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
+#define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B','A','8','1') /*  8  BGBG.. GRGR.. */
+
+/* compressed formats */
+#define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M','J','P','G') /* Motion-JPEG   */
+#define V4L2_PIX_FMT_JPEG     v4l2_fourcc('J','P','E','G') /* JFIF JPEG     */
+#define V4L2_PIX_FMT_DV       v4l2_fourcc('d','v','s','d') /* 1394          */
+#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M','P','E','G') /* MPEG          */
+
+/*  Vendor-specific formats   */
+#define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
+#define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S','9','1','0') /* SN9C10x compression */
+#define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P','W','C','1') /* pwc older webcam */
+#define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
+
+/*
+ *	F O R M A T   E N U M E R A T I O N
+ */
+struct v4l2_fmtdesc
+{
+	unsigned int	            index;             /* Format number      */
+	enum v4l2_buf_type  type;              /* buffer type        */
+	unsigned int               flags;
+	unsigned char	            description[32];   /* Description string */
+	unsigned int	            pixelformat;       /* Format fourcc      */
+	unsigned int	            reserved[4];
+};
+
+#define V4L2_FMT_FLAG_COMPRESSED 0x0001
+
+
+/*
+ *	T I M E C O D E
+ */
+struct v4l2_timecode
+{
+	unsigned int	type;
+	unsigned int	flags;
+	unsigned char	frames;
+	unsigned char	seconds;
+	unsigned char	minutes;
+	unsigned char	hours;
+	unsigned char	userbits[4];
+};
+
+/*  Type  */
+#define V4L2_TC_TYPE_24FPS		1
+#define V4L2_TC_TYPE_25FPS		2
+#define V4L2_TC_TYPE_30FPS		3
+#define V4L2_TC_TYPE_50FPS		4
+#define V4L2_TC_TYPE_60FPS		5
+
+/*  Flags  */
+#define V4L2_TC_FLAG_DROPFRAME		0x0001 /* "drop-frame" mode */
+#define V4L2_TC_FLAG_COLORFRAME		0x0002
+#define V4L2_TC_USERBITS_field		0x000C
+#define V4L2_TC_USERBITS_USERDEFINED	0x0000
+#define V4L2_TC_USERBITS_8BITCHARS	0x0008
+/* The above is based on SMPTE timecodes */
+
+
+/*
+ *	C O M P R E S S I O N   P A R A M E T E R S
+ */
+#if 0
+/* ### generic compression settings don't work, there is too much
+ * ### codec-specific stuff.  Maybe reuse that for MPEG codec settings
+ * ### later ... */
+struct v4l2_compression
+{
+	unsigned int	quality;
+	unsigned int	keyframerate;
+	unsigned int	pframerate;
+	unsigned int	reserved[5];
+
+/*  what we'll need for MPEG, extracted from some postings on
+    the v4l list (Gert Vervoort, PlasmaJohn).
+
+system stream:
+  - type: elementary stream(ES), packatised elementary stream(s) (PES)
+    program stream(PS), transport stream(TS)
+  - system bitrate
+  - PS packet size (DVD: 2048 bytes, VCD: 2324 bytes)
+  - TS video PID
+  - TS audio PID
+  - TS PCR PID
+  - TS system information tables (PAT, PMT, CAT, NIT and SIT)
+  - (MPEG-1 systems stream vs. MPEG-2 program stream (TS not supported
+    by MPEG-1 systems)
+
+audio:
+  - type: MPEG (+Layer I,II,III), AC-3, LPCM
+  - bitrate
+  - sampling frequency (DVD: 48 Khz, VCD: 44.1 KHz, 32 kHz)
+  - Trick Modes? (ff, rew)
+  - Copyright
+  - Inverse Telecine
+
+video:
+  - picturesize (SIF, 1/2 D1, 2/3 D1, D1) and PAL/NTSC norm can be set
+    through excisting V4L2 controls
+  - noise reduction, parameters encoder specific?
+  - MPEG video version: MPEG-1, MPEG-2
+  - GOP (Group Of Pictures) definition:
+    - N: number of frames per GOP
+    - M: distance between reference (I,P) frames
+    - open/closed GOP
+  - quantiser matrix: inter Q matrix (64 bytes) and intra Q matrix (64 bytes)
+  - quantiser scale: linear or logarithmic
+  - scanning: alternate or zigzag
+  - bitrate mode: CBR (constant bitrate) or VBR (variable bitrate).
+  - target video bitrate for CBR
+  - target video bitrate for VBR
+  - maximum video bitrate for VBR - min. quantiser value for VBR
+  - max. quantiser value for VBR
+  - adaptive quantisation value
+  - return the number of bytes per GOP or bitrate for bitrate monitoring
+
+*/
+};
+#endif
+
+struct v4l2_jpegcompression
+{
+	int quality;
+
+	int  APPn;              /* Number of APP segment to be written,
+				 * must be 0..15 */
+	int  APP_len;           /* Length of data in JPEG APPn segment */
+	char APP_data[60];      /* Data in the JPEG APPn segment. */
+	
+	int  COM_len;           /* Length of data in JPEG COM segment */
+	char COM_data[60];      /* Data in JPEG COM segment */
+	
+	unsigned int jpeg_markers;     /* Which markers should go into the JPEG
+				 * output. Unless you exactly know what
+				 * you do, leave them untouched.
+				 * Inluding less markers will make the
+				 * resulting code smaller, but there will
+				 * be fewer aplications which can read it.
+				 * The presence of the APP and COM marker
+				 * is influenced by APP_len and COM_len
+				 * ONLY, not by this property! */
+	
+#define V4L2_JPEG_MARKER_DHT (1<<3)    /* Define Huffman Tables */
+#define V4L2_JPEG_MARKER_DQT (1<<4)    /* Define Quantization Tables */
+#define V4L2_JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
+#define V4L2_JPEG_MARKER_COM (1<<6)    /* Comment segment */
+#define V4L2_JPEG_MARKER_APP (1<<7)    /* App segment, driver will
+                                        * always use APP0 */
+};
+
+
+/*
+ *	M E M O R Y - M A P P I N G   B U F F E R S
+ */
+struct v4l2_requestbuffers
+{
+	unsigned int	                count;
+	enum v4l2_buf_type      type;
+	enum v4l2_memory        memory;
+	unsigned int	                reserved[2];
+};
+
+struct v4l2_buffer
+{
+	unsigned int			index;
+	enum v4l2_buf_type      type;
+	unsigned int			bytesused;
+	unsigned int			flags;
+	enum v4l2_field		field;
+	struct timeval		timestamp;
+	struct v4l2_timecode	timecode;
+	unsigned int			sequence;
+
+	/* memory location */
+	enum v4l2_memory        memory;
+	union {
+		unsigned int           offset;
+		unsigned long   userptr;
+	} m;
+	unsigned int			length;
+	unsigned int			input;
+	unsigned int			reserved;
+};
+
+/*  Flags for 'flags' field */
+#define V4L2_BUF_FLAG_MAPPED	0x0001  /* Buffer is mapped (flag) */
+#define V4L2_BUF_FLAG_QUEUED	0x0002	/* Buffer is queued for processing */
+#define V4L2_BUF_FLAG_DONE	0x0004	/* Buffer is ready */
+#define V4L2_BUF_FLAG_KEYFRAME	0x0008	/* Image is a keyframe (I-frame) */
+#define V4L2_BUF_FLAG_PFRAME	0x0010	/* Image is a P-frame */
+#define V4L2_BUF_FLAG_BFRAME	0x0020	/* Image is a B-frame */
+#define V4L2_BUF_FLAG_TIMECODE	0x0100	/* timecode field is valid */
+#define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
+
+/*
+ *	O V E R L A Y   P R E V I E W
+ */
+struct v4l2_framebuffer
+{
+	unsigned int			capability;
+	unsigned int			flags;
+/* FIXME: in theory we should pass something like PCI device + memory
+ * region + offset instead of some physical address */
+	void*                   base;
+	struct v4l2_pix_format	fmt;
+};
+/*  Flags for the 'capability' field. Read only */
+#define V4L2_FBUF_CAP_EXTERNOVERLAY	0x0001
+#define V4L2_FBUF_CAP_CHROMAKEY		0x0002
+#define V4L2_FBUF_CAP_LIST_CLIPPING     0x0004
+#define V4L2_FBUF_CAP_BITMAP_CLIPPING	0x0008
+/*  Flags for the 'flags' field. */
+#define V4L2_FBUF_FLAG_PRIMARY		0x0001
+#define V4L2_FBUF_FLAG_OVERLAY		0x0002
+#define V4L2_FBUF_FLAG_CHROMAKEY	0x0004
+
+struct v4l2_clip
+{
+	struct v4l2_rect        c;
+	struct v4l2_clip	*next;
+};
+
+struct v4l2_window
+{
+	struct v4l2_rect        w;
+	enum v4l2_field  	field;
+	unsigned int			chromakey;
+	struct v4l2_clip	*clips;
+	unsigned int			clipcount;
+	void			*bitmap;
+};
+
+
+/*
+ *	C A P T U R E   P A R A M E T E R S
+ */
+struct v4l2_captureparm
+{
+	unsigned int		   capability;	  /*  Supported modes */
+	unsigned int		   capturemode;	  /*  Current mode */
+	struct v4l2_fract  timeperframe;  /*  Time per frame in .1us units */
+	unsigned int		   extendedmode;  /*  Driver-specific extensions */
+	unsigned int              readbuffers;   /*  # of buffers for read */
+	unsigned int		   reserved[4];
+};
+/*  Flags for 'capability' and 'capturemode' fields */
+#define V4L2_MODE_HIGHQUALITY	0x0001	/*  High quality imaging mode */
+#define V4L2_CAP_TIMEPERFRAME	0x1000	/*  timeperframe field is supported */
+
+struct v4l2_outputparm
+{
+	unsigned int		   capability;	 /*  Supported modes */
+	unsigned int		   outputmode;	 /*  Current mode */
+	struct v4l2_fract  timeperframe; /*  Time per frame in seconds */
+	unsigned int		   extendedmode; /*  Driver-specific extensions */
+	unsigned int              writebuffers; /*  # of buffers for write */
+	unsigned int		   reserved[4];
+};
+
+/*
+ *	I N P U T   I M A G E   C R O P P I N G
+ */
+
+struct v4l2_cropcap {
+	enum v4l2_buf_type      type;	
+        struct v4l2_rect        bounds;
+        struct v4l2_rect        defrect;
+        struct v4l2_fract       pixelaspect;
+};
+
+struct v4l2_crop {
+	enum v4l2_buf_type      type;
+	struct v4l2_rect        c;
+};
+
+/*
+ *      A N A L O G   V I D E O   S T A N D A R D
+ */
+
+typedef unsigned long long v4l2_std_id;
+
+/* one bit for each */
+#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
+#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
+#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
+#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
+#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
+#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
+#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
+#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
+
+#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
+#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
+#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
+#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
+
+#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
+#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
+
+#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
+#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
+#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
+#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
+#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
+#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
+#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
+
+/* ATSC/HDTV */
+#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
+#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
+
+/* some common needed stuff */
+#define V4L2_STD_PAL_BG		(V4L2_STD_PAL_B		|\
+				 V4L2_STD_PAL_B1	|\
+				 V4L2_STD_PAL_G)
+#define V4L2_STD_PAL_DK		(V4L2_STD_PAL_D		|\
+				 V4L2_STD_PAL_D1	|\
+				 V4L2_STD_PAL_K)
+#define V4L2_STD_PAL		(V4L2_STD_PAL_BG	|\
+				 V4L2_STD_PAL_DK	|\
+				 V4L2_STD_PAL_H		|\
+				 V4L2_STD_PAL_I)
+#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M	|\
+				 V4L2_STD_NTSC_M_JP)
+#define V4L2_STD_SECAM_DK      	(V4L2_STD_SECAM_D	|\
+				 V4L2_STD_SECAM_K	|\
+				 V4L2_STD_SECAM_K1)
+#define V4L2_STD_SECAM		(V4L2_STD_SECAM_B	|\
+				 V4L2_STD_SECAM_G	|\
+				 V4L2_STD_SECAM_H	|\
+				 V4L2_STD_SECAM_DK	|\
+				 V4L2_STD_SECAM_L)
+
+#define V4L2_STD_525_60		(V4L2_STD_PAL_M		|\
+				 V4L2_STD_PAL_60	|\
+				 V4L2_STD_NTSC)
+#define V4L2_STD_625_50		(V4L2_STD_PAL		|\
+				 V4L2_STD_PAL_N		|\
+				 V4L2_STD_PAL_Nc	|\
+				 V4L2_STD_SECAM)
+#define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
+		                 V4L2_STD_ATSC_16_VSB)
+
+#define V4L2_STD_UNKNOWN        0
+#define V4L2_STD_ALL            (V4L2_STD_525_60	|\
+				 V4L2_STD_625_50)
+
+struct v4l2_standard
+{
+	unsigned int	       	     index;
+	v4l2_std_id          id;
+	unsigned char		     name[24];
+	struct v4l2_fract    frameperiod; /* Frames, not fields */
+	unsigned int		     framelines;
+	unsigned int		     reserved[4];
+};
+
+
+/*
+ *	V I D E O   I N P U T S
+ */
+struct v4l2_input
+{
+	unsigned int	     index;		/*  Which input */
+	unsigned char	     name[32];	        /*  Label */
+	unsigned int	     type;		/*  Type of input */
+	unsigned int	     audioset;	        /*  Associated audios (bitfield) */
+	unsigned int        tuner;             /*  Associated tuner */
+	v4l2_std_id  std;
+	unsigned int	     status;
+	unsigned int	     reserved[4];
+};
+/*  Values for the 'type' field */
+#define V4L2_INPUT_TYPE_TUNER		1
+#define V4L2_INPUT_TYPE_CAMERA		2
+
+/* field 'status' - general */
+#define V4L2_IN_ST_NO_POWER    0x00000001  /* Attached device is off */
+#define V4L2_IN_ST_NO_SIGNAL   0x00000002
+#define V4L2_IN_ST_NO_COLOR    0x00000004
+
+/* field 'status' - analog */
+#define V4L2_IN_ST_NO_H_LOCK   0x00000100  /* No horizontal sync lock */
+#define V4L2_IN_ST_COLOR_KILL  0x00000200  /* Color killer is active */
+
+/* field 'status' - digital */
+#define V4L2_IN_ST_NO_SYNC     0x00010000  /* No synchronization lock */
+#define V4L2_IN_ST_NO_EQU      0x00020000  /* No equalizer lock */
+#define V4L2_IN_ST_NO_CARRIER  0x00040000  /* Carrier recovery failed */
+
+/* field 'status' - VCR and set-top box */
+#define V4L2_IN_ST_MACROVISION 0x01000000  /* Macrovision detected */
+#define V4L2_IN_ST_NO_ACCESS   0x02000000  /* Conditional access denied */
+#define V4L2_IN_ST_VTR         0x04000000  /* VTR time constant */
+
+/*
+ *	V I D E O   O U T P U T S
+ */
+struct v4l2_output
+{
+	unsigned int	     index;		/*  Which output */
+	unsigned char	     name[32];	        /*  Label */
+	unsigned int	     type;		/*  Type of output */
+	unsigned int	     audioset;	        /*  Associated audios (bitfield) */
+	unsigned int	     modulator;         /*  Associated modulator */
+	v4l2_std_id  std;
+	unsigned int	     reserved[4];
+};
+/*  Values for the 'type' field */
+#define V4L2_OUTPUT_TYPE_MODULATOR		1
+#define V4L2_OUTPUT_TYPE_ANALOG			2
+#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY	3
+
+/*
+ *	C O N T R O L S
+ */
+struct v4l2_control
+{
+	unsigned int		     id;
+	int		     value;
+};
+
+/*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
+struct v4l2_queryctrl
+{
+	unsigned int	             id;
+	enum v4l2_ctrl_type  type;
+	unsigned char		     name[32];	/* Whatever */
+	int		     minimum;	/* Note signedness */
+	int		     maximum;
+	int	             step;
+	int		     default_value;
+	unsigned int                flags;
+	unsigned int		     reserved[2];
+};
+
+/*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
+struct v4l2_querymenu
+{
+	unsigned int		id;
+	unsigned int		index;
+	unsigned char		name[32];	/* Whatever */
+	unsigned int		reserved;
+};
+
+/*  Control flags  */
+#define V4L2_CTRL_FLAG_DISABLED		0x0001
+#define V4L2_CTRL_FLAG_GRABBED		0x0002
+
+/*  Control IDs defined by V4L2 */
+#define V4L2_CID_BASE			0x00980900
+/*  IDs reserved for driver specific controls */
+#define V4L2_CID_PRIVATE_BASE		0x08000000
+
+#define V4L2_CID_BRIGHTNESS		(V4L2_CID_BASE+0)
+#define V4L2_CID_CONTRAST		(V4L2_CID_BASE+1)
+#define V4L2_CID_SATURATION		(V4L2_CID_BASE+2)
+#define V4L2_CID_HUE			(V4L2_CID_BASE+3)
+#define V4L2_CID_AUDIO_VOLUME		(V4L2_CID_BASE+5)
+#define V4L2_CID_AUDIO_BALANCE		(V4L2_CID_BASE+6)
+#define V4L2_CID_AUDIO_BASS		(V4L2_CID_BASE+7)
+#define V4L2_CID_AUDIO_TREBLE		(V4L2_CID_BASE+8)
+#define V4L2_CID_AUDIO_MUTE		(V4L2_CID_BASE+9)
+#define V4L2_CID_AUDIO_LOUDNESS		(V4L2_CID_BASE+10)
+#define V4L2_CID_BLACK_LEVEL		(V4L2_CID_BASE+11)
+#define V4L2_CID_AUTO_WHITE_BALANCE	(V4L2_CID_BASE+12)
+#define V4L2_CID_DO_WHITE_BALANCE	(V4L2_CID_BASE+13)
+#define V4L2_CID_RED_BALANCE		(V4L2_CID_BASE+14)
+#define V4L2_CID_BLUE_BALANCE		(V4L2_CID_BASE+15)
+#define V4L2_CID_GAMMA			(V4L2_CID_BASE+16)
+#define V4L2_CID_WHITENESS		(V4L2_CID_GAMMA) /* ? Not sure */
+#define V4L2_CID_EXPOSURE		(V4L2_CID_BASE+17)
+#define V4L2_CID_AUTOGAIN		(V4L2_CID_BASE+18)
+#define V4L2_CID_GAIN			(V4L2_CID_BASE+19)
+#define V4L2_CID_HFLIP			(V4L2_CID_BASE+20)
+#define V4L2_CID_VFLIP			(V4L2_CID_BASE+21)
+#define V4L2_CID_HCENTER		(V4L2_CID_BASE+22)
+#define V4L2_CID_VCENTER		(V4L2_CID_BASE+23)
+#define V4L2_CID_LASTP1			(V4L2_CID_BASE+24) /* last CID + 1 */
+
+/*
+ *	T U N I N G
+ */
+struct v4l2_tuner
+{
+	unsigned int                   index;
+	unsigned char			name[32];
+	enum v4l2_tuner_type    type;
+	unsigned int			capability;
+	unsigned int			rangelow;
+	unsigned int			rangehigh;
+	unsigned int			rxsubchans;
+	unsigned int			audmode;
+	int			signal;
+	int			afc;
+	unsigned int			reserved[4];
+};
+
+struct v4l2_modulator
+{
+	unsigned int			index;
+	unsigned char			name[32];
+	unsigned int			capability;
+	unsigned int			rangelow;
+	unsigned int			rangehigh;
+	unsigned int			txsubchans;
+	unsigned int			reserved[4];
+};
+
+/*  Flags for the 'capability' field */
+#define V4L2_TUNER_CAP_LOW		0x0001
+#define V4L2_TUNER_CAP_NORM		0x0002
+#define V4L2_TUNER_CAP_STEREO		0x0010
+#define V4L2_TUNER_CAP_LANG2		0x0020
+#define V4L2_TUNER_CAP_SAP		0x0020
+#define V4L2_TUNER_CAP_LANG1		0x0040
+
+/*  Flags for the 'rxsubchans' field */
+#define V4L2_TUNER_SUB_MONO		0x0001
+#define V4L2_TUNER_SUB_STEREO		0x0002
+#define V4L2_TUNER_SUB_LANG2		0x0004
+#define V4L2_TUNER_SUB_SAP		0x0004
+#define V4L2_TUNER_SUB_LANG1		0x0008
+
+/*  Values for the 'audmode' field */
+#define V4L2_TUNER_MODE_MONO		0x0000
+#define V4L2_TUNER_MODE_STEREO		0x0001
+#define V4L2_TUNER_MODE_LANG2		0x0002
+#define V4L2_TUNER_MODE_SAP		0x0002
+#define V4L2_TUNER_MODE_LANG1		0x0003
+
+struct v4l2_frequency
+{
+	unsigned int	              tuner;
+	enum v4l2_tuner_type  type;
+        unsigned int	              frequency;
+	unsigned int	              reserved[8];
+};
+
+/*
+ *	A U D I O
+ */
+struct v4l2_audio
+{
+	unsigned int	index;
+	unsigned char	name[32];
+	unsigned int	capability;
+	unsigned int	mode;
+	unsigned int	reserved[2];
+};
+/*  Flags for the 'capability' field */
+#define V4L2_AUDCAP_STEREO		0x00001
+#define V4L2_AUDCAP_AVL			0x00002
+
+/*  Flags for the 'mode' field */
+#define V4L2_AUDMODE_AVL		0x00001
+
+struct v4l2_audioout
+{
+	unsigned int	index;
+	unsigned char	name[32];
+	unsigned int	capability;
+	unsigned int	mode;
+	unsigned int	reserved[2];
+};
+
+/*
+ *	D A T A   S E R V I C E S   ( V B I )
+ *
+ *	Data services API by Michael Schimek
+ */
+
+struct v4l2_vbi_format
+{
+	unsigned int	sampling_rate;		/* in 1 Hz */
+	unsigned int	offset;
+	unsigned int	samples_per_line;
+	unsigned int	sample_format;		/* V4L2_PIX_FMT_* */
+	int	start[2];
+	unsigned int	count[2];
+	unsigned int	flags;			/* V4L2_VBI_* */
+	unsigned int	reserved[2];		/* must be zero */
+};
+
+/*  VBI flags  */
+#define V4L2_VBI_UNSYNC		(1<< 0)
+#define V4L2_VBI_INTERLACED	(1<< 1)
+
+
+/*
+ *	A G G R E G A T E   S T R U C T U R E S
+ */
+
+/*	Stream data format
+ */
+struct v4l2_format
+{
+	enum v4l2_buf_type type;
+	union
+	{
+		struct v4l2_pix_format	pix;  // V4L2_BUF_TYPE_VIDEO_CAPTURE
+		struct v4l2_window	win;  // V4L2_BUF_TYPE_VIDEO_OVERLAY
+		struct v4l2_vbi_format	vbi;  // V4L2_BUF_TYPE_VBI_CAPTURE
+		unsigned char	raw_data[200];        // user-defined
+	} fmt;
+};
+
+
+/*	Stream type-dependent parameters
+ */
+struct v4l2_streamparm
+{
+	enum v4l2_buf_type type;
+	union
+	{
+		struct v4l2_captureparm	capture;
+		struct v4l2_outputparm	output;
+		unsigned char	raw_data[200];  /* user-defined */
+	} parm;
+};
+
+
+
+/*
+ *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
+ *
+ */
+#define VIDIOC_QUERYCAP		_IOR  ('V',  0, struct v4l2_capability)
+#define VIDIOC_RESERVED		_IO   ('V',  1)
+#define VIDIOC_ENUM_FMT         _IOWR ('V',  2, struct v4l2_fmtdesc)
+#define VIDIOC_G_FMT		_IOWR ('V',  4, struct v4l2_format)
+#define VIDIOC_S_FMT		_IOWR ('V',  5, struct v4l2_format)
+#if 0
+#define VIDIOC_G_COMP		_IOR  ('V',  6, struct v4l2_compression)
+#define VIDIOC_S_COMP		_IOW  ('V',  7, struct v4l2_compression)
+#endif
+#define VIDIOC_REQBUFS		_IOWR ('V',  8, struct v4l2_requestbuffers)
+#define VIDIOC_QUERYBUF		_IOWR ('V',  9, struct v4l2_buffer)
+#define VIDIOC_G_FBUF		_IOR  ('V', 10, struct v4l2_framebuffer)
+#define VIDIOC_S_FBUF		_IOW  ('V', 11, struct v4l2_framebuffer)
+#define VIDIOC_OVERLAY		_IOW  ('V', 14, int)
+#define VIDIOC_QBUF		_IOWR ('V', 15, struct v4l2_buffer)
+#define VIDIOC_DQBUF		_IOWR ('V', 17, struct v4l2_buffer)
+#define VIDIOC_STREAMON		_IOW  ('V', 18, int)
+#define VIDIOC_STREAMOFF	_IOW  ('V', 19, int)
+#define VIDIOC_G_PARM		_IOWR ('V', 21, struct v4l2_streamparm)
+#define VIDIOC_S_PARM		_IOWR ('V', 22, struct v4l2_streamparm)
+#define VIDIOC_G_STD		_IOR  ('V', 23, v4l2_std_id)
+#define VIDIOC_S_STD		_IOW  ('V', 24, v4l2_std_id)
+#define VIDIOC_ENUMSTD		_IOWR ('V', 25, struct v4l2_standard)
+#define VIDIOC_ENUMINPUT	_IOWR ('V', 26, struct v4l2_input)
+#define VIDIOC_G_CTRL		_IOWR ('V', 27, struct v4l2_control)
+#define VIDIOC_S_CTRL		_IOWR ('V', 28, struct v4l2_control)
+#define VIDIOC_G_TUNER		_IOWR ('V', 29, struct v4l2_tuner)
+#define VIDIOC_S_TUNER		_IOW  ('V', 30, struct v4l2_tuner)
+#define VIDIOC_G_AUDIO		_IOR  ('V', 33, struct v4l2_audio)
+#define VIDIOC_S_AUDIO		_IOW  ('V', 34, struct v4l2_audio)
+#define VIDIOC_QUERYCTRL	_IOWR ('V', 36, struct v4l2_queryctrl)
+#define VIDIOC_QUERYMENU	_IOWR ('V', 37, struct v4l2_querymenu)
+#define VIDIOC_G_INPUT		_IOR  ('V', 38, int)
+#define VIDIOC_S_INPUT		_IOWR ('V', 39, int)
+#define VIDIOC_G_OUTPUT		_IOR  ('V', 46, int)
+#define VIDIOC_S_OUTPUT		_IOWR ('V', 47, int)
+#define VIDIOC_ENUMOUTPUT	_IOWR ('V', 48, struct v4l2_output)
+#define VIDIOC_G_AUDOUT		_IOR  ('V', 49, struct v4l2_audioout)
+#define VIDIOC_S_AUDOUT		_IOW  ('V', 50, struct v4l2_audioout)
+#define VIDIOC_G_MODULATOR	_IOWR ('V', 54, struct v4l2_modulator)
+#define VIDIOC_S_MODULATOR	_IOW  ('V', 55, struct v4l2_modulator)
+#define VIDIOC_G_FREQUENCY	_IOWR ('V', 56, struct v4l2_frequency)
+#define VIDIOC_S_FREQUENCY	_IOW  ('V', 57, struct v4l2_frequency)
+#define VIDIOC_CROPCAP		_IOWR ('V', 58, struct v4l2_cropcap)
+#define VIDIOC_G_CROP		_IOWR ('V', 59, struct v4l2_crop)
+#define VIDIOC_S_CROP		_IOW  ('V', 60, struct v4l2_crop)
+#define VIDIOC_G_JPEGCOMP	_IOR  ('V', 61, struct v4l2_jpegcompression)
+#define VIDIOC_S_JPEGCOMP	_IOW  ('V', 62, struct v4l2_jpegcompression)
+#define VIDIOC_QUERYSTD      	_IOR  ('V', 63, v4l2_std_id)
+#define VIDIOC_TRY_FMT      	_IOWR ('V', 64, struct v4l2_format)
+#define VIDIOC_ENUMAUDIO	_IOWR ('V', 65, struct v4l2_audio)
+#define VIDIOC_ENUMAUDOUT	_IOWR ('V', 66, struct v4l2_audioout)
+#define VIDIOC_G_PRIORITY       _IOR  ('V', 67, enum v4l2_priority)
+#define VIDIOC_S_PRIORITY       _IOW  ('V', 68, enum v4l2_priority)
+
+/* for compatibility, will go away some day */
+#define VIDIOC_OVERLAY_OLD     	_IOWR ('V', 14, int)
+#define VIDIOC_S_PARM_OLD      	_IOW  ('V', 22, struct v4l2_streamparm)
+#define VIDIOC_S_CTRL_OLD      	_IOW  ('V', 28, struct v4l2_control)
+#define VIDIOC_G_AUDIO_OLD     	_IOWR ('V', 33, struct v4l2_audio)
+#define VIDIOC_G_AUDOUT_OLD    	_IOWR ('V', 49, struct v4l2_audioout)
+#define VIDIOC_CROPCAP_OLD     	_IOR  ('V', 58, struct v4l2_cropcap)
+
+#define BASE_VIDIOC_PRIVATE	192		/* 192-255 are private */
+
+#endif /* __LINUX_VIDEODEV2_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
Index: /BAORadio/libindi/v1/test
===================================================================
--- /BAORadio/libindi/v1/test	(revision 500)
+++ /BAORadio/libindi/v1/test	(revision 500)
@@ -0,0 +1,1 @@
+test
Index: /BAORadio/libindi/v1/tools/compiler.c
===================================================================
--- /BAORadio/libindi/v1/tools/compiler.c	(revision 500)
+++ /BAORadio/libindi/v1/tools/compiler.c	(revision 500)
@@ -0,0 +1,669 @@
+/* module to compile and execute a c-style arithmetic expression made of INDI
+ * operands. operand names must contain 2 dots and be surrounded by quotes.
+ * The expression is compiled and the names of each operand are stored. The
+ * values of an operand can be set later by name. Evaluation uses the last
+ * known operand value.
+ *
+ * one reason this is so nice and tight is that all opcodes are the same size
+ * (an int) and the tokens the parser returns are directly usable as opcodes.
+ * constants and variables are compiled as an opcode with an offset into the
+ * auxiliary consts and vars arrays.
+ *
+ * this is not reentrant, but new expressions can be compiled as desired.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int next_token (void);
+static int chk_funcs (void);
+static void skip_double (void);
+static int compile (int prec);
+static int execute (double *result);
+static int parse_fieldname (char name[], int len);
+
+/* parser tokens and opcodes, as necessary */
+enum {
+    HALT,			/* HALT = 0 serves as good initial default */
+
+    /* binary operators (precedences in table, below) */
+    ADD,
+    SUB,
+    MULT,
+    DIV,
+    AND,
+    OR,
+    GT,
+    GE,
+    EQ,
+    NE,
+    LT,
+    LE,
+
+    /* unary ops, precedence all UNI_PREC */
+    NEG,
+    NOT,
+
+    /* symantically operands, ie, constants, variables and all functions */
+    CONST,
+    VAR,
+    ABS,
+    FLOOR,
+    SIN,
+    COS,
+    TAN,
+    ASIN,
+    ACOS,
+    ATAN,
+    PITOK,			/* built-in constant, pi */
+    DEGRAD,
+    RADDEG,
+    LOG,
+    LOG10,
+    EXP,
+    SQRT,
+    POW,
+    ATAN2,
+};
+
+/* purely tokens - never get compiled as such */
+#define	LPAREN	255
+#define	RPAREN	254
+#define	COMMA	253
+#define	ERR	(-1)
+
+/* precedence of each of the binary operators.
+ * in case of a tie, compiler associates left-to-right.
+ * N.B. each entry's index must correspond to its #define!
+ */
+static int precedence[] = {0,5,5,6,6,2,1,4,4,3,3,4,4};
+#define	UNI_PREC	7	/* unary ops have highest precedence */
+
+/* execute-time operand stack */
+#define	MAX_STACK	32
+static double stack[MAX_STACK], *sp;
+
+/* space for compiled opcodes - the "program".
+ * opcodes go in lower 8 bits.
+ * when an opcode has an operand (as CONST and VAR) it is really an array
+ *   index in the remaining upper bits.
+ */
+#define	MAX_PROG 32
+static int program[MAX_PROG], *pc;
+#define	OP_SHIFT	8
+#define	OP_MASK		0xff
+
+/* auxiliary operand info.
+ * the operands (all but lower 8 bits) of CONST and VAR are really indeces
+ * into these arrays. thus, no point in making them any longer than you have
+ * bits more than 8 in your machine's int to index into it, ie, make
+ *    MAX_OPX < 1 << ((sizeof(int)-1)*8)
+ */
+#define	MAX_OPX		64	/* max number of operands */
+#define	MAXFLDLEN	64	/* longest allowed operand name */
+typedef struct {
+    int set;			/* 1 when v has been set */
+    char name[MAXFLDLEN];	/* name of operand */
+    double v;			/* last known value of this operand */
+} Var;
+static Var vars[MAX_OPX];	/* operands */
+static int nvars;		/* number of vars[] in actual use */
+static double consts[MAX_OPX];	/* constants */
+static int nconsts;		/* number of consts[] in actual use */
+
+/* these are global just for easy/rapid access */
+static int parens_nest;	/* to check that parens end up nested */
+static char *err_msg;   /* caller provides storage; we point at it with this */
+static char *cexpr, *lcexpr; /* pointers that move along caller's expression */
+
+/* compile the given c-style expression.
+ * return 0 if ok, else return -1 and a reason message in errbuf.
+ */
+int
+compileExpr (char *exp, char *errbuf)
+{
+	/* init the globals.
+	 * also delete any flogs used in the previous program.
+	 */
+	cexpr = exp;
+	err_msg = errbuf;
+	pc = program;
+	nvars = nconsts = 0;
+	parens_nest = 0;
+
+	pc = program;
+	if (compile(0) == ERR) {
+	    (void) sprintf (err_msg + strlen(err_msg), " near `%.10s'", lcexpr);
+	    return (-1);
+	}
+	if (pc == program) {
+	    (void) sprintf (err_msg, "Null program");
+	    return (-1);
+	}
+	*pc++ = HALT;
+	return (0);
+}
+
+/* execute the expression previously compiled with compileExpr().
+ * return 0 with *vp set to the answer if ok, else return -1 with a reason
+ * why not message in errbuf.
+ */
+int
+evalExpr (double *vp, char *errbuf)
+{
+	err_msg = errbuf;
+	sp = stack + MAX_STACK;	/* grows towards lower addresses */
+	pc = program;
+	return (execute(vp));
+}
+
+/* set the value for an operand with the given name to the given value.
+ * return 0 if found else -1.
+ */
+int
+setOperand (char *name, double valu)
+{
+	int i;
+
+	for (i = 0; i < nvars; i++) {
+	    if (strcmp (name, vars[i].name) == 0) {
+		vars[i].v = valu;
+		vars[i].set = 1;
+		return(0);
+	    }
+	}
+
+	return (-1);
+}
+
+/* return 0 if all operands are set, else -1 */
+int 
+allOperandsSet ()
+{
+	int i;
+
+	for (i = 0; i < nvars; i++)
+	    if (!vars[i].set)
+		return (-1);
+	return (0);
+}
+
+/* return a malloced array of each operand name.
+ * N.B. caller must free array, and not modify names.
+ */
+int
+getAllOperands (char ***ops)
+{
+	int i;
+
+	*ops = (char **) malloc (nvars * sizeof(char *));
+
+	for (i = 0; i < nvars; i++)
+	    (*ops)[i] = vars[i].name;
+
+	return (nvars);
+}
+
+/* return a malloced array of each initialized operand name.
+ * N.B. caller must free array, and not modify the names.
+ */
+int
+getSetOperands (char ***ops)
+{
+	int i, n;
+
+	*ops = (char **) malloc (nvars * sizeof(char *));
+
+	for (n = i = 0; i < nvars; i++)
+	    if (vars[i].set)
+		(*ops)[n++] = vars[i].name;
+
+	return (n);
+}
+
+/* return a malloced array of each uninitialized operand name.
+ * N.B. caller must free array, and not modify the names.
+ */
+int
+getUnsetOperands (char ***ops)
+{
+	int i, n;
+
+	*ops = (char **) malloc (nvars * sizeof(char *));
+
+	for (n = i = 0; i < nvars; i++)
+	    if (!vars[i].set)
+		(*ops)[n++] = vars[i].name;
+
+	return (n);
+}
+
+/* called when each different field is written.
+ * this is just called by srch_log() to hide the fact from users of srch*
+ * that srch is really using our vars array to store values.
+ * since this gets called for all fields, it's not an error to not find name.
+ * don't stop when see the first one because a term might appear more than once.
+ */
+void
+compiler_log (name, value)
+char *name;
+double value;
+{
+	Var *vp;
+
+	for (vp = vars; vp < &vars[nvars]; vp++)
+	    if (vp->name && strcmp (vp->name, name) == 0)
+		vp->v = value;
+}
+
+/* get and return the opcode corresponding to the next token.
+ * leave with lcexpr pointing at the new token, cexpr just after it.
+ * also watch for mismatches parens and proper operator/operand alternation.
+ */
+static int
+next_token ()
+{
+	static char toomv[] = "More than %d variables";
+	static char toomc[] = "More than %d constants";
+	static char badop[] = "Illegal operator";
+	int tok = ERR;	/* just something illegal */
+	char c;
+
+	while (isspace(c = *cexpr))
+	    cexpr++;
+	lcexpr = cexpr++;
+
+	/* mainly check for a binary operator */
+	switch (c) {
+	case ',': tok = COMMA; break;
+	case '\0': --cexpr; tok = HALT; break; /* keep returning HALT */
+	case '+': tok = ADD; break; /* compiler knows when it's really unary */
+	case '-': tok = SUB; break; /* compiler knows when it's really negate */
+	case '*': tok = MULT; break;
+	case '/': tok = DIV; break;
+	case '(': parens_nest++; tok = LPAREN; break;
+	case ')':
+	    if (--parens_nest < 0) {
+	        (void) sprintf (err_msg, "Too many right parens");
+		return (ERR);
+	    } else
+		tok = RPAREN;
+	    break;
+	case '|':
+	    if (*cexpr == '|') { cexpr++; tok = OR; }
+	    else { (void) sprintf (err_msg, badop); return (ERR); }
+	    break;
+	case '&':
+	    if (*cexpr == '&') { cexpr++; tok = AND; }
+	    else { (void) sprintf (err_msg, badop); return (ERR); }
+	    break;
+	case '=':
+	    if (*cexpr == '=') { cexpr++; tok = EQ; }
+	    else { (void) sprintf (err_msg, badop); return (ERR); }
+	    break;
+	case '!':
+	    if (*cexpr == '=') { cexpr++; tok = NE; } else { tok = NOT; }
+	    break;
+	case '<':
+	    if (*cexpr == '=') { cexpr++; tok = LE; }
+	    else tok = LT;
+	    break;
+	case '>':
+	    if (*cexpr == '=') { cexpr++; tok = GE; }
+	    else tok = GT;
+	    break;
+	}
+
+	if (tok != ERR)
+	    return (tok);
+
+	/* not op so check for a constant, variable or function */
+	if (isdigit(c) || c == '.') {
+	    /* looks like a constant.
+	     * leading +- already handled
+	     */
+	    if (nconsts > MAX_OPX) {
+		(void) sprintf (err_msg, toomc, MAX_OPX);
+		return (ERR);
+	    }
+	    consts[nconsts] = atof (lcexpr);
+	    tok = CONST | (nconsts++ << OP_SHIFT);
+	    skip_double();
+	} else if (isalpha(c)) {
+	    /* check list of functions */
+	    tok = chk_funcs();
+	    if (tok == ERR) {
+		(void) sprintf (err_msg, "Bad function");
+		return (ERR);
+	    }
+	} else if (c == '"') {
+	    /* a variable */
+	    if (nvars > MAX_OPX) {
+		(void) sprintf (err_msg, toomv, MAX_OPX);
+		return (ERR);
+	    }
+	    if (parse_fieldname (vars[nvars].name, MAXFLDLEN) < 0) {
+		(void) sprintf (err_msg, "Bad field");
+		return (ERR);
+	    } else
+		tok = VAR | (nvars++ << OP_SHIFT);
+	}
+
+	if (tok != ERR)
+	    return (tok);
+
+	/* what the heck is it? */
+	(void) sprintf (err_msg, "Syntax error");
+	return (ERR);
+}
+
+/* return funtion token, else ERR.
+ * if find one, update cexpr too.
+ */
+static int
+chk_funcs()
+{
+	static struct {
+	    char *st_name;
+	    int st_tok;
+	} symtab[] = {
+	     /* be sure to put short names AFTER longer ones.
+	      * otherwise, order does not matter.
+	      */
+	    {"abs", ABS},	{"floor", FLOOR},	{"acos", ACOS},
+	    {"asin", ASIN},	{"atan2", ATAN2},	{"atan", ATAN},
+	    {"cos", COS},	{"degrad", DEGRAD},	{"exp", EXP},
+	    {"log10", LOG10},	{"log", LOG},		{"pi", PITOK},
+	    {"pow", POW},	{"raddeg", RADDEG},	{"sin", SIN},
+	    {"sqrt", SQRT},	{"tan", TAN},
+	};
+	int i;
+
+	for (i = 0; i < sizeof(symtab)/sizeof(symtab[0]); i++) {
+	    int l = strlen (symtab[i].st_name);
+	    if (strncmp (lcexpr, symtab[i].st_name, l) == 0) {
+		cexpr += l-1;
+		return (symtab[i].st_tok);
+	    }
+	}
+	return (ERR);
+}
+
+/* move cexpr on past a double.
+ * allow sci notation.
+ * no need to worry about a leading '-' or '+' but allow them after an 'e'.
+ * TODO: this handles all the desired cases, but also admits a bit too much
+ *   such as things like 1eee2...3. geeze; to skip a double right you almost
+ *   have to go ahead and crack it!
+ */
+static void
+skip_double()
+{
+	int sawe = 0;	/* so we can allow '-' or '+' right after an 'e' */
+
+	for (;;) {
+	    char c = *cexpr;
+	    if (isdigit(c) || c=='.' || (sawe && (c=='-' || c=='+'))) {
+		sawe = 0;
+		cexpr++;
+	    } else if (c == 'e') {
+		sawe = 1;
+		cexpr++;
+	    } else
+		break;
+	}
+}
+
+/* call this whenever you want to dig out the next (sub)expression.
+ * keep compiling instructions as long as the operators are higher precedence
+ * than prec (or until see HALT, COMMA or RPAREN) then return that
+ * "look-ahead" token.
+ * if error, fill in a message in err_msg[] and return ERR.
+ */
+static int
+compile (prec)
+int prec;
+{
+	int expect_binop = 0;	/* set after we have seen any operand.
+				 * used by SUB so it can tell if it really 
+				 * should be taken to be a NEG instead.
+				 */
+	int tok = next_token ();
+	int *oldpc;
+
+	for (;;) {
+	    int p;
+	    if (tok == ERR)
+		return (ERR);
+	    if (pc - program >= MAX_PROG) {
+		(void) sprintf (err_msg, "Program is too long");
+		return (ERR);
+	    }
+
+	    /* check for special things like functions, constants and parens */
+            switch (tok & OP_MASK) {
+	    case COMMA: return (tok);
+            case HALT: return (tok);
+	    case ADD:
+		if (expect_binop)
+		    break;	/* procede with binary addition */
+		/* just skip a unary positive(?) */
+		tok = next_token();
+		if (tok == HALT) {
+		    (void) sprintf (err_msg, "Term expected after unary +");
+		    return (ERR);
+		}
+		continue;
+	    case SUB:
+		if (expect_binop)
+		    break;	/* procede with binary subtract */
+		oldpc = pc;
+		tok = compile (UNI_PREC);
+		if (oldpc == pc) {
+		    (void) sprintf (err_msg, "Term expected after unary -");
+		    return (ERR);
+		}
+		*pc++ = NEG;
+		expect_binop = 1;
+		continue;
+	    case NOT:
+		oldpc = pc;
+		tok = compile (UNI_PREC);
+		if (oldpc == pc) {
+		    (void) sprintf (err_msg, "Term expected after unary !");
+		    return (ERR);
+		}
+		*pc++ = NOT;
+		expect_binop = 1;
+		continue;
+	    /* one-arg functions */
+            case ABS: case FLOOR: case SIN: case COS: case TAN: case ASIN:
+	    case ACOS: case ATAN: case DEGRAD: case RADDEG: case LOG:
+	    case LOG10: case EXP: case SQRT:
+		/* eat up the function's parenthesized argument */
+		if (next_token() != LPAREN) {
+		    (void) sprintf (err_msg, "expecting '(' after function");
+		    return (ERR);
+		}
+		oldpc = pc;
+		if (compile (0) != RPAREN || oldpc == pc) {
+		    (void) sprintf (err_msg, "1-arg function arglist error");
+		    return (ERR);
+		}
+		*pc++ = tok;
+		tok = next_token();
+		expect_binop = 1;
+		continue;
+	    /* two-arg functions */
+	    case POW: case ATAN2:
+		/* eat up the function's parenthesized arguments */
+		if (next_token() != LPAREN) {
+		    (void) sprintf (err_msg, "Saw a built-in function: expecting (");
+		    return (ERR);
+		}
+		oldpc = pc;
+		if (compile (0) != COMMA || oldpc == pc) {
+		    (void) sprintf (err_msg, "1st of 2-arg function arglist error");
+		    return (ERR);
+		}
+		oldpc = pc;
+		if (compile (0) != RPAREN || oldpc == pc) {
+		    (void) sprintf (err_msg, "2nd of 2-arg function arglist error");
+		    return (ERR);
+		}
+		*pc++ = tok;
+		tok = next_token();
+		expect_binop = 1;
+		continue;
+	    /* constants and variables are just like 0-arg functions w/o ()'s */
+            case CONST:
+	    case PITOK:
+	    case VAR:
+		*pc++ = tok;
+		tok = next_token();
+		expect_binop = 1;
+		continue;
+            case LPAREN:
+		oldpc = pc;
+		if (compile (0) != RPAREN) {
+		    (void) sprintf (err_msg, "Unmatched left paren");
+		    return (ERR);
+		}
+		if (oldpc == pc) {
+		    (void) sprintf (err_msg, "Null expression");
+		    return (ERR);
+		}
+		tok = next_token();
+		expect_binop = 1;
+		continue;
+            case RPAREN:
+		return (RPAREN);
+            }
+
+	    /* everything else is a binary operator */
+	    if (tok < ADD || tok > LE) {
+		printf ("Bug! Bogus token: %d\n", tok);
+		abort();
+	    }
+	    p = precedence[tok];
+            if (p > prec) {
+                int newtok;
+		oldpc = pc;
+                newtok = compile (p);
+		if (newtok == ERR)
+		    return (ERR);
+		if (oldpc == pc) {
+		    (void) strcpy (err_msg, "Term or factor expected");
+		    return (ERR);
+		}
+                *pc++ = tok;
+		expect_binop = 1;
+                tok = newtok;
+            } else
+                return (tok);
+        }
+}
+
+/* "run" the program[] compiled with compile().
+ * if ok, return 0 and the final result,
+ * else return -1 with a reason why not message in err_msg.
+ */
+static int
+execute(result)
+double *result;
+{
+	int instr; 
+
+	do {
+	    instr = *pc++;
+	    switch (instr & OP_MASK) {
+	    /* put these in numberic order so hopefully even the dumbest
+	     * compiler will choose to use a jump table, not a cascade of ifs.
+	     */
+	    case HALT:	break;	/* outer loop will stop us */
+	    case ADD:	sp[1] = sp[1] +  sp[0]; sp++; break;
+	    case SUB:	sp[1] = sp[1] -  sp[0]; sp++; break;
+	    case MULT:	sp[1] = sp[1] *  sp[0]; sp++; break;
+	    case DIV:	sp[1] = sp[1] /  sp[0]; sp++; break;
+	    case AND:	sp[1] = sp[1] && sp[0] ? 1 : 0; sp++; break;
+	    case OR:	sp[1] = sp[1] || sp[0] ? 1 : 0; sp++; break;
+	    case GT:	sp[1] = sp[1] >  sp[0] ? 1 : 0; sp++; break;
+	    case GE:	sp[1] = sp[1] >= sp[0] ? 1 : 0; sp++; break;
+	    case EQ:	sp[1] = sp[1] == sp[0] ? 1 : 0; sp++; break;
+	    case NE:	sp[1] = sp[1] != sp[0] ? 1 : 0; sp++; break;
+	    case LT:	sp[1] = sp[1] <  sp[0] ? 1 : 0; sp++; break;
+	    case LE:	sp[1] = sp[1] <= sp[0] ? 1 : 0; sp++; break;
+	    case NEG:	*sp = -*sp; break;
+	    case NOT:	*sp = (double)(*sp==0); break;
+	    case CONST:	*--sp = consts[instr >> OP_SHIFT]; break;
+	    case VAR:	*--sp = vars[instr>>OP_SHIFT].v; break;
+	    case PITOK:	*--sp = 4.0*atan(1.0); break;
+	    case ABS:	*sp = fabs (*sp); break;
+	    case FLOOR:	*sp = floor (*sp); break;
+	    case SIN:	*sp = sin (*sp); break;
+	    case COS:	*sp = cos (*sp); break;
+	    case TAN:	*sp = tan (*sp); break;
+	    case ASIN:	*sp = asin (*sp); break;
+	    case ACOS:	*sp = acos (*sp); break;
+	    case ATAN:	*sp = atan (*sp); break;
+	    case DEGRAD:*sp *= atan(1.0)/45.0; break;
+	    case RADDEG:*sp *= 45.0/atan(1.0); break;
+	    case LOG:	*sp = log (*sp); break;
+	    case LOG10:	*sp = log10 (*sp); break;
+	    case EXP:	*sp = exp (*sp); break;
+	    case SQRT:	*sp = sqrt (*sp); break;
+	    case POW:	sp[1] = pow (sp[1], sp[0]); sp++; break;
+	    case ATAN2:	sp[1] = atan2 (sp[1], sp[0]); sp++; break;
+	    default:
+		(void) sprintf (err_msg, "Bug! bad opcode: 0x%x", instr);
+		return (-1);
+	    }
+	    if (sp < stack) {
+		(void) sprintf (err_msg, "Runtime stack overflow");
+		return (-1);
+	    } else if (sp - stack > MAX_STACK) {
+		(void) sprintf (err_msg, "Bug! runtime stack underflow");
+		return (-1);
+	    }
+	} while (instr != HALT);
+
+	/* result should now be on top of stack */
+	if (sp != &stack[MAX_STACK - 1]) {
+	    (void) sprintf (err_msg, "Bug! stack has %d items",
+							MAX_STACK - (sp-stack));
+	    return (-1);
+	}
+	*result = *sp;
+	return (0);
+}
+
+/* starting with lcexpr pointing at a string expected to be a field name,
+ * ie, at a '"', fill into up to the next '"' into name[], including trailing 0.
+ * if there IS no '"' within len-1 chars, return -1, else 0.
+ * the only sanity check is the string contains two dots.
+ * when return, leave lcexpr alone but move cexpr to just after the second '"'.
+ */
+static int
+parse_fieldname (name, len)
+char name[];
+int len;
+{
+	char c = '\0';
+	int ndots = 0;
+
+	cexpr = lcexpr + 1;
+	while (--len > 0 && (c = *cexpr++) != '"' && c) {
+	    *name++ = c;
+	    ndots += c == '.';
+	}
+	if (len == 0 || c != '"' || ndots != 2)
+	    return (-1);
+	*name = '\0';
+	return (0);
+}
+
+/* For RCS Only -- Do Not Edit */
+static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: compiler.c,v $ $Date: 2005/11/21 21:33:32 $ $Revision: 1.1 $ $Name:  $"};
Index: /BAORadio/libindi/v1/tools/evalINDI.c
===================================================================
--- /BAORadio/libindi/v1/tools/evalINDI.c	(revision 500)
+++ /BAORadio/libindi/v1/tools/evalINDI.c	(revision 500)
@@ -0,0 +1,561 @@
+/* evaluate an expression of INDI operands
+ */
+
+/* Overall design:
+ * compile expression, building operand table, if trouble exit 2
+ * open INDI connection, if trouble exit 2
+ * send getProperties as required to get operands flowing
+ * watch for messages until get initial values of each operand
+ * evaluate expression, repeat if -w each time an op arrives until true
+ * exit val==0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "indiapi.h"
+#include "lilxml.h"
+
+extern int compileExpr (char *expr, char *errmsg);
+extern int evalExpr (double *vp, char *errmsg);
+extern int allOperandsSet (void);
+extern int getAllOperands (char ***ops);
+extern int getSetOperands (char ***ops);
+extern int getUnsetOperands (char ***ops);
+extern int setOperand (char *name, double valu);
+
+static void usage (void);
+static void compile (char *expr);
+static FILE *openINDIServer (void);
+static void getProps(FILE *fp);
+static void initProps (FILE *fp);
+static int pstatestr (char *state);
+static time_t timestamp (char *ts);
+static int devcmp (char *op1, char *op2);
+static int runEval (FILE *fp);
+static int setOp (XMLEle *root);
+static XMLEle *nxtEle (FILE *fp);
+static int readServerChar (FILE *fp);
+static void onAlarm (int dummy);
+
+static char *me;
+static char host_def[] = "localhost";   /* default host name */
+static char *host = host_def;           /* working host name */
+#define INDIPORT        7624            /* default port */
+static int port = INDIPORT;             /* working port number */
+#define TIMEOUT         2               /* default timeout, secs */
+static int timeout = TIMEOUT;           /* working timeout, secs */
+static LilXML *lillp;			/* XML parser context */
+static int directfd = -1;		/* direct filedes to server, if >= 0 */
+static int verbose;			/* more tracing */
+static int eflag;			/* print each updated expression value*/
+static int fflag;			/* print final expression value */
+static int iflag;			/* read expresion from stdin */
+static int oflag;			/* print operands as they change */
+static int wflag;			/* wait for expression to be true */
+static int bflag;			/* beep when true */
+
+int
+main (int ac, char *av[])
+{
+	FILE *fp;
+
+	/* save our name for usage() */
+	me = av[0];
+
+	/* crack args */
+	while (--ac && **++av == '-') {
+	    char *s = *av;
+	    while (*++s) {
+		switch (*s) {
+		case 'b':	/* beep when true */
+		    bflag++;
+		    break;
+		case 'd':
+		    if (ac < 2) {
+			fprintf (stderr, "-d requires open fileno\n");
+			usage();
+		    }
+		    directfd = atoi(*++av);
+		    ac--;
+		    break;
+		case 'e':	/* print each updated expression value */
+		    eflag++;
+		    break;
+		case 'f':	/* print final expression value */
+		    fflag++;
+		    break;
+		case 'h':
+		    if (directfd >= 0) {
+			fprintf (stderr, "Can not combine -d and -h\n");
+			usage();
+		    }
+		    if (ac < 2) {
+			fprintf (stderr, "-h requires host name\n");
+			usage();
+		    }
+		    host = *++av;
+		    ac--;
+		    break;
+		case 'i':	/* read expression from stdin */
+		    iflag++;
+		    break;
+		case 'o':	/* print operands as they change */
+		    oflag++;
+		    break;
+		case 'p':
+		    if (directfd >= 0) {
+			fprintf (stderr, "Can not combine -d and -p\n");
+			usage();
+		    }
+		    if (ac < 2) {
+			fprintf (stderr, "-p requires tcp port number\n");
+			usage();
+		    }
+		    port = atoi(*++av);
+		    ac--;
+		    break;
+		case 't':
+		    if (ac < 2) {
+			fprintf (stderr, "-t requires timeout\n");
+			usage();
+		    }
+		    timeout = atoi(*++av);
+		    ac--;
+		    break;
+		case 'v':	/* verbose */
+		    verbose++;
+		    break;
+		case 'w':	/* wait for expression to be true */
+		    wflag++;
+		    break;
+		default:
+		    fprintf (stderr, "Unknown flag: %c\n", *s);
+		    usage();
+		}
+	    }
+	}
+
+	/* now there are ac args starting with av[0] */
+
+	/* compile expression from av[0] or stdin */
+	if (ac == 0)
+	    compile (NULL);
+	else if (ac == 1)
+	    compile (av[0]);
+	else
+	    usage();
+
+        /* open connection */
+	if (directfd >= 0) {
+	    fp = fdopen (directfd, "r+");
+	    setbuf (fp, NULL);		/* don't absorb next guy's stuff */
+	    if (!fp) {
+		fprintf (stderr, "Direct fd %d: %s\n",directfd,strerror(errno));
+		exit(1);
+	    }
+	    if (verbose)
+		fprintf (stderr, "Using direct fd %d\n", directfd);
+	} else {
+	    fp = openINDIServer();
+	    if (verbose)
+		fprintf (stderr, "Connected to %s on port %d\n", host, port);
+	}
+
+	/* build a parser context for cracking XML responses */
+	lillp = newLilXML();
+
+	/* set up to catch an io timeout function */
+	signal (SIGALRM, onAlarm);
+
+	/* send getProperties */
+	getProps(fp);
+
+	/* initialize all properties */
+	initProps(fp);
+
+	/* evaluate expression, return depending on flags */
+	return (runEval(fp));
+}
+
+static void
+usage()
+{
+	fprintf (stderr, "Usage: %s [options] [exp]\n", me);
+	fprintf (stderr, "Purpose: evaluate an expression of INDI operands\n");
+	fprintf (stderr, "Version: $Revision: 1.5 $\n");
+	fprintf (stderr, "Options:\n");
+	fprintf (stderr, "   -b   : beep when expression evaluates as true\n");
+	fprintf (stderr, "   -d f : use file descriptor f already open to server\n");
+
+	fprintf (stderr, "   -e   : print each updated expression value\n");
+	fprintf (stderr, "   -f   : print final expression value\n");
+        fprintf (stderr, "   -h h : alternate host, default is %s\n", host_def);
+	fprintf (stderr, "   -i   : read expression from stdin\n");
+	fprintf (stderr, "   -o   : print operands as they change\n");
+	fprintf (stderr, "   -p p : alternate port, default is %d\n", INDIPORT);
+	fprintf (stderr, "   -t t : max secs to wait, 0 is forever, default is %d\n",TIMEOUT);
+	fprintf (stderr, "   -v   : verbose (cummulative)\n");
+	fprintf (stderr, "   -w   : wait for expression to evaluate as true\n");
+	fprintf (stderr, "[exp] is an arith expression built from the following operators and functons:\n");
+	fprintf (stderr, "     ! + - * / && || > >= == != < <=\n");
+	fprintf (stderr, "     pi sin(rad) cos(rad) tan(rad) asin(x) acos(x) atan(x) atan2(y,x) abs(x)\n");
+	fprintf (stderr, "     degrad(deg) raddeg(rad) floor(x) log(x) log10(x) exp(x) sqrt(x) pow(x,exp)\n");
+	fprintf (stderr, "   operands are of the form \"device.name.element\" (including quotes), where\n");
+	fprintf (stderr, "   element may be:\n");
+	fprintf (stderr, "     _STATE evaluated to 0,1,2,3 from Idle,Ok,Busy,Alert.\n");
+	fprintf (stderr, "     _TS evaluated to UNIX seconds from epoch.\n");
+	fprintf (stderr, "   Switch vectors are evaluated to 0,1 from Off,On.\n");
+	fprintf (stderr, "   Light vectors are evaluated to 0-3 as per _STATE.\n");
+	fprintf (stderr, "Examples:\n");
+	fprintf (stderr, "   To print 0/1 whether Security.Doors.Front or .Rear are in Alert:\n");
+	fprintf (stderr, "     evalINDI -f '\"Security.Doors.Front\"==3 || \"Security.Doors.Rear\"==3'\n");
+	fprintf (stderr, "   To exit 0 if the Security property as a whole is in a state of Ok:\n");
+	fprintf (stderr, "     evalINDI '\"Security.Security._STATE\"==1'\n");
+	fprintf (stderr, "   To wait for RA and Dec to be near zero and watch their values as they change:\n");
+	fprintf (stderr, "     evalINDI -t 0 -wo 'abs(\"Mount.EqJ2K.RA\")<.01 && abs(\"Mount.EqJ2K.Dec\")<.01'\n");
+	fprintf (stderr, "Exit 0 if expression evaluates to non-0, 1 if 0, else 2\n");
+
+	exit (1);
+}
+
+/* compile the given expression else read from stdin.
+ * exit(2) if trouble.
+ */
+static void
+compile (char *expr)
+{
+	char errmsg[1024];
+	char *exp = expr;
+
+	if (!exp) {
+	    /* read expression from stdin */
+	    int nr, nexp = 0;
+	    exp = malloc(1024);
+	    while ((nr = fread (exp+nexp, 1, 1024, stdin)) > 0)
+		exp = realloc (exp, (nexp+=nr)+1024);
+	    exp[nexp] = '\0';
+	}
+
+	if (verbose)
+	    fprintf (stderr, "Compiling: %s\n", exp);
+	if (compileExpr (exp, errmsg) < 0) {
+	    fprintf (stderr, "Compile err: %s\n", errmsg);
+	    exit(2);
+	}
+
+	if (exp != expr)
+	    free (exp);
+}
+
+/* open a connection to the given host and port or die.
+ * return FILE pointer to socket.
+ */
+static FILE *
+openINDIServer (void)
+{
+	struct sockaddr_in serv_addr;
+	struct hostent *hp;
+	int sockfd;
+
+	/* lookup host address */
+	hp = gethostbyname (host);
+	if (!hp) {
+	    perror ("gethostbyname");
+	    exit (2);
+	}
+
+	/* create a socket to the INDI server */
+	(void) memset ((char *)&serv_addr, 0, sizeof(serv_addr));
+	serv_addr.sin_family = AF_INET;
+	serv_addr.sin_addr.s_addr =
+			    ((struct in_addr *)(hp->h_addr_list[0]))->s_addr;
+	serv_addr.sin_port = htons(port);
+	if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+	    perror ("socket");
+	    exit(2);
+	}
+
+	/* connect */
+	if (connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){
+	    perror ("connect");
+	    exit(2);
+	}
+
+	/* prepare for line-oriented i/o with client */
+	return (fdopen (sockfd, "r+"));
+}
+
+/* invite each device referenced in the expression to report its properties.
+ */
+static void
+getProps(FILE *fp)
+{
+	char **ops;
+	int nops;
+	int i, j;
+
+	/* get each operand used in the expression */
+	nops = getAllOperands (&ops);
+
+	/* send getProperties for each unique device referenced */
+	for (i = 0; i < nops; i++) {
+	    for (j = 0; j < i; j++)
+		if (devcmp (ops[i], ops[j]) == 0)
+		    break;
+	    if (j < i)
+		continue;
+	    if (verbose)
+		fprintf (stderr, "sending getProperties for %.*s\n",
+					strchr (ops[i],'.')-ops[i], ops[i]);
+	    fprintf (fp, "<getProperties version='%g' device='%.*s'/>\n", INDIV,
+					strchr (ops[i],'.')-ops[i], ops[i]);
+	}
+}
+
+/* wait for defXXX or setXXX for each property in the expression.
+ * return when find all operands are found or
+ * exit(2) if time out waiting for all known operands.
+ */
+static void
+initProps (FILE *fp)
+{
+	alarm (timeout);
+	while (allOperandsSet() < 0) {
+	    if (setOp (nxtEle (fp)) == 0)
+		alarm(timeout);
+	}
+	alarm (0);
+}
+
+/* pull apart the name and value from the given message, and set operand value.
+ * ignore any other messages.
+ * return 0 if found a recognized operand else -1
+ */
+static int
+setOp (XMLEle *root)
+{
+	char *t = tagXMLEle (root);
+	char *d = findXMLAttValu (root, "device");
+	char *n = findXMLAttValu (root, "name");
+	int nset = 0;
+	double v;
+	char prop[1024];
+	XMLEle *ep;
+
+	/* check values */
+	if (!strcmp (t,"defNumberVector") || !strcmp (t,"setNumberVector")) {
+	    for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		char *et = tagXMLEle(ep);
+		if (!strcmp (et,"defNumber") || !strcmp (et,"oneNumber")) {
+		    sprintf (prop, "%s.%s.%s", d, n, findXMLAttValu(ep,"name"));
+		    v = atof(pcdataXMLEle(ep));
+		    if (setOperand (prop, v) == 0) {
+			nset++;
+			if (oflag)
+			    fprintf (stderr, "%s=%g\n", prop, v);
+		    }
+		}
+	    }
+	} else if(!strcmp(t,"defSwitchVector") || !strcmp(t,"setSwitchVector")){
+	    for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		char *et = tagXMLEle(ep);
+		if (!strcmp (et,"defSwitch") || !strcmp (et,"oneSwitch")) {
+		    sprintf (prop, "%s.%s.%s", d, n, findXMLAttValu(ep,"name"));
+		    v = (double)!strcmp(pcdataXMLEle(ep),"On");
+		    if (setOperand (prop, v) == 0) {
+			nset++;
+			if (oflag)
+			    fprintf (stderr, "%s=%g\n", prop, v);
+		    }
+		}
+	    }
+	} else if(!strcmp(t,"defLightVector") || !strcmp(t,"setLightVector")){
+	    for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+		char *et = tagXMLEle(ep);
+		if (!strcmp (et,"defLight") || !strcmp (et,"oneLight")) {
+		    sprintf (prop, "%s.%s.%s", d, n, findXMLAttValu(ep,"name"));
+		    v = (double)pstatestr(pcdataXMLEle(ep));
+		    if (setOperand (prop, v) == 0) {
+			nset++;
+			if (oflag)
+			    fprintf (stderr, "%s=%g\n", prop, v);
+		    }
+		}
+	    }
+	}
+
+	/* check special elements */
+	t = findXMLAttValu (root, "state");
+	if (t[0]) {
+	    sprintf (prop, "%s.%s._STATE", d, n);
+	    v = (double)pstatestr(t);
+	    if (setOperand (prop, v) == 0) {
+		nset++;
+		if (oflag)
+		    fprintf (stderr, "%s=%g\n", prop, v);
+	    }
+	}
+	t = findXMLAttValu (root, "timestamp");
+	if (t[0]) {
+	    sprintf (prop, "%s.%s._TS", d, n);
+	    v = (double)timestamp(t);
+	    if (setOperand (prop, v) == 0) {
+		nset++;
+		if (oflag)
+		    fprintf (stderr, "%s=%g\n", prop, v);
+	    }
+	}
+
+	/* return whether any were set */
+	return (nset > 0 ? 0 : -1);
+}
+
+/* evaluate the expression after seeing any operand change.
+ * return whether expression evaluated to 0.
+ * exit(2) is trouble or timeout waiting for operands we expect.
+ */
+static int
+runEval (FILE *fp)
+{
+	char errmsg[1024];
+	double v;
+
+	alarm(timeout);
+	while (1) {
+	    if (evalExpr (&v, errmsg) < 0) {
+		fprintf (stderr, "Eval: %s\n", errmsg);
+		exit(2);
+	    }
+	    if (bflag && v)
+		fprintf (stderr, "\a");
+	    if (eflag)
+		fprintf (stderr, "%g\n", v);
+	    if (!wflag || v != 0)
+		break;
+	    while (setOp (nxtEle (fp)) < 0)
+		continue;
+	    alarm(timeout);
+	}
+	alarm(0);
+
+	if (!eflag && fflag)
+	    fprintf (stderr, "%g\n", v);
+
+	return (v == 0);
+}
+
+/* return 0|1|2|3 depending on whether state is Idle|Ok|Busy|<other>.
+ */
+static int
+pstatestr (char *state)
+{
+	if (!strcmp (state, "Idle"))
+	    return (0);
+	if (!strcmp (state, "Ok"))
+	    return (1);
+	if (!strcmp (state, "Busy"))
+	    return (2);
+	return (3);
+}
+
+/* return UNIX time for the given ISO 8601 time string
+ */
+static time_t
+timestamp (char *ts)
+{
+	struct tm tm;
+
+	if (6 == sscanf (ts, "%d-%d-%dT%d:%d:%d", &tm.tm_year, &tm.tm_mon,
+			&tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec)) {
+	    tm.tm_mon -= 1;		/* want 0..11 */
+	    tm.tm_year -= 1900;		/* want years since 1900 */
+	    return (mktime (&tm));
+	} else
+	    return ((time_t)-1);
+}
+
+/* return 0 if the device portion of the two given property specs match, else 1
+ */
+static int
+devcmp (char *op1, char *op2)
+{
+	int n1 = strchr(op1,'.') - op1;
+	int n2 = strchr(op2,'.') - op2;
+	return (n1 != n2 || strncmp (op1,op2,n1));
+}
+
+/* monitor server and return the next complete XML message.
+ * exit(2) if time out.
+ * N.B. caller must call delXMLEle()
+ */
+static XMLEle *
+nxtEle (FILE *fp)
+{
+	char msg[1024];
+
+	/* read from server, exit if trouble or see malformed XML */
+	while(1) {
+	    XMLEle *root = readXMLEle (lillp, readServerChar(fp), msg);
+	    if (root) {
+		/* found a complete XML element */
+		if (verbose > 1)
+		    prXMLEle (stderr, root, 0);
+		return (root);
+	    } else if (msg[0]) {
+		fprintf (stderr, "Bad XML from %s/%d: %s\n", host, port, msg);
+		exit(2);
+	    }
+	}
+}
+
+/* read next char from the INDI server connected by fp */
+static int
+readServerChar (FILE *fp)
+{
+	int c = fgetc (fp);
+
+	if (c == EOF) {
+	    if (ferror(fp))
+		perror ("read");
+	    else
+		fprintf (stderr,"INDI server %s/%d disconnected\n", host, port);
+	    exit (2);
+	}
+
+	if (verbose > 2)
+	    fprintf (stderr, "Read %c\n", c);
+
+	return (c);
+}
+
+/* called after timeout seconds waiting to hear from server.
+ * print reason for trouble and exit(2).
+ */
+static void
+onAlarm (int dummy)
+{
+	char **ops;
+	int nops;
+
+	/* report any unseen operands if any, else just say timed out */
+	if ((nops = getUnsetOperands (&ops)) > 0) {
+	    fprintf (stderr, "No values seen for");
+	    while (nops-- > 0)
+		fprintf (stderr, " %s", ops[nops]);
+	    fprintf (stderr, "\n");
+	} else 
+	    fprintf (stderr, "Timed out waiting for new values\n");
+
+	exit (2);
+}
Index: /BAORadio/libindi/v1/tools/getINDIproperty.c
===================================================================
--- /BAORadio/libindi/v1/tools/getINDIproperty.c	(revision 500)
+++ /BAORadio/libindi/v1/tools/getINDIproperty.c	(revision 500)
@@ -0,0 +1,605 @@
+/* connect to an INDI server and show all desired device.property.element
+ *   with possible wild card * in any category.
+ * All types but BLOBs are handled from their defXXX messages. Receipt of a
+ *   defBLOB sends enableBLOB then uses setBLOBVector for the value. BLOBs
+ *   are stored in a file dev.nam.elem.format. only .z compression is handled.
+ * exit status: 0 at least some found, 1 some not found, 2 real trouble.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "indiapi.h"
+#include "lilxml.h"
+#include "base64.h"
+#include "zlib.h"
+
+
+/* table of INDI definition elements, plus setBLOB.
+ * we also look for set* if -m
+ */
+typedef struct {
+    char *vec;		/* vector name */
+    char *one;		/* one element name */
+} INDIDef;
+static INDIDef defs[] = {
+    {"defTextVector",   "defText"},
+    {"defNumberVector", "defNumber"},
+    {"defSwitchVector", "defSwitch"},
+    {"defLightVector",  "defLight"},
+    {"defBLOBVector",   "defBLOB"},
+    {"setBLOBVector",   "oneBLOB"},
+    {"setTextVector",   "oneText"},
+    {"setNumberVector", "oneNumber"},
+    {"setSwitchVector", "oneSwitch"},
+    {"setLightVector",  "oneLight"},
+};
+static int ndefs = 6;			/* or 10 if -m */
+
+/* table of keyword to use in query vs name of INDI defXXX attribute */
+typedef struct {
+    char *keyword;
+    char *indiattr;
+} INDIkwattr;
+static INDIkwattr kwattr[] = {
+    {"_LABEL", "label"},
+    {"_GROUP", "group"},
+    {"_STATE", "state"},
+    {"_PERM", "perm"},
+    {"_TO", "timeout"},
+    {"_TS", "timestamp"},
+};
+#define NKWA   (sizeof(kwattr)/sizeof(kwattr[0]))
+
+typedef struct {
+    char *d;				/* device to seek */
+    char *p;				/* property to seek */
+    char *e;				/* element to seek */
+    int wc : 1;				/* whether pattern uses wild cards */
+    int ok : 1;				/* something matched this query */
+} SearchDef;
+static SearchDef *srchs;		/* properties to look for */
+static int nsrchs;
+
+static void usage (void);
+static void crackDPE (char *spec);
+static void addSearchDef (char *dev, char *prop, char *ele);
+static void openINDIServer(void);
+static void getprops(void);
+static void listenINDI(void);
+static int finished (void);
+static void onAlarm (int dummy);
+static int readServerChar(void);
+static void findDPE (XMLEle *root);
+static void findEle (XMLEle *root, char *dev, char *nam, char *defone,
+    SearchDef *sp);
+static void enableBLOBs(char *dev, char *nam);
+static void oneBLOB (XMLEle *root, char *dev, char *nam, char *enam, char *p,
+    int plen);
+
+static char *me;			/* our name for usage() message */
+static char host_def[] = "localhost";	/* default host name */
+static char *host = host_def;		/* working host name */
+#define INDIPORT	7624		/* default port */
+static int port = INDIPORT;		/* working port number */
+#define TIMEOUT		2		/* default timeout, secs */
+static int timeout = TIMEOUT;		/* working timeout, secs */
+static int verbose;			/* report extra info */
+static LilXML *lillp;			/* XML parser context */
+#define WILDCARD	'*'		/* show all in this category */
+static int onematch;			/* only one possible match */
+static int justvalue;			/* if just one match show only value */
+static int monitor;			/* keep watching even after seen def */
+static int directfd = -1;		/* direct filedes to server, if >= 0 */
+static FILE *svrwfp;			/* FILE * to talk to server */
+static FILE *svrrfp;			/* FILE * to read from server */
+static int wflag;			/* show wo properties too */
+
+int
+main (int ac, char *av[])
+{
+	/* save our name */
+	me = av[0];
+
+	/* crack args */
+	while (--ac && **++av == '-') {
+	    char *s = *av;
+	    while (*++s) {
+		switch (*s) {
+		case '1':	/* just value */
+		    justvalue++;
+		    break;
+		case 'd':
+		    if (ac < 2) {
+			fprintf (stderr, "-d requires open fileno\n");
+			usage();
+		    }
+		    directfd = atoi(*++av);
+		    ac--;
+		    break;
+		case 'h':
+		    if (directfd >= 0) {
+			fprintf (stderr, "Can not combine -d and -h\n");
+			usage();
+		    }
+		    if (ac < 2) {
+			fprintf (stderr, "-h requires host name\n");
+			usage();
+		    }
+		    host = *++av;
+		    ac--;
+		    break;
+		case 'm':
+		    monitor++;
+		    ndefs = 10;			/* include set*Vectors too */
+		    break;
+		case 'p':
+		    if (directfd >= 0) {
+			fprintf (stderr, "Can not combine -d and -p\n");
+			usage();
+		    }
+		    if (ac < 2) {
+			fprintf (stderr, "-p requires tcp port number\n");
+			usage();
+		    }
+		    port = atoi(*++av);
+		    ac--;
+		    break;
+		case 't':
+		    if (ac < 2) {
+			fprintf (stderr, "-t requires timeout\n");
+			usage();
+		    }
+		    timeout = atoi(*++av);
+		    ac--;
+		    break;
+		case 'v':	/* verbose */
+		    verbose++;
+		    break;
+		case 'w':
+		    wflag++;
+		    break;
+		default:
+		    fprintf (stderr, "Unknown flag: %c\n", *s);
+		    usage();
+		}
+	    }
+	}
+
+	/* now ac args starting with av[0] */
+	if (ac == 0)
+	    av[ac++] = "*.*.*";		/* default is get everything */
+
+	/* crack each d.p.e */
+	while (ac--)
+	    crackDPE (*av++);
+	onematch = nsrchs == 1 && !srchs[0].wc;
+
+	/* open connection */
+	if (directfd >= 0) {
+	    svrwfp = fdopen (directfd, "w");
+	    svrrfp = fdopen (directfd, "r");
+	    setbuf (svrrfp, NULL);	/* don't absorb next guy's stuff */
+	    if (!svrwfp || !svrrfp) {
+		fprintf (stderr, "Direct fd %d: %s\n",directfd,strerror(errno));
+		exit(1);
+	    }
+	    if (verbose)
+		fprintf (stderr, "Using direct fd %d\n", directfd);
+	} else {
+	    openINDIServer();
+	    if (verbose)
+		fprintf (stderr, "Connected to %s on port %d\n", host, port);
+	}
+
+	/* build a parser context for cracking XML responses */
+	lillp = newLilXML();
+
+	/* issue getProperties */
+	getprops();
+
+	/* listen for responses, looking for d.p.e or timeout */
+	listenINDI();
+
+	return (0);
+}
+
+static void
+usage()
+{
+	int i;
+
+	fprintf(stderr, "Purpose: retrieve readable properties from an INDI server\n");
+	fprintf(stderr, "%s\n", "$Revision: 1.11 $");
+	fprintf(stderr, "Usage: %s [options] [device.property.element ...]\n",me);
+	fprintf(stderr, "  Any component may be \"*\" to match all (beware shell metacharacters).\n");
+	fprintf(stderr, "  Reports all properties if none specified.\n");
+	fprintf(stderr, "  BLOBs are saved in file named device.property.element.format\n");
+	fprintf(stderr, "  In perl try: %s\n", "%props = split (/[=\\n]/, `getINDI`);");
+	fprintf(stderr, "  Set element to one of following to return property attribute:\n");
+	for (i = 0; i < NKWA; i++)
+	    fprintf (stderr, "    %10s to report %s\n", kwattr[i].keyword,
+	    						kwattr[i].indiattr);
+	fprintf(stderr, "Output format: output is fully qualified name=value one per line\n");
+	fprintf(stderr, "  or just value if -1 and exactly one query without wildcards.\n");
+	fprintf(stderr, "Options:\n");
+	fprintf(stderr, "  -1    : print just value if expecting exactly one response\n");
+	fprintf(stderr, "  -d f  : use file descriptor f already open to server\n");
+	fprintf(stderr, "  -h h  : alternate host, default is %s\n", host_def);
+	fprintf(stderr, "  -m    : keep monitoring for more updates\n");
+	fprintf(stderr, "  -p p  : alternate port, default is %d\n", INDIPORT);
+	fprintf(stderr, "  -t t  : max time to wait, default is %d secs\n",TIMEOUT);
+	fprintf(stderr, "  -v    : verbose (cumulative)\n");
+	fprintf(stderr, "  -w    : show write-only properties too\n");
+	fprintf(stderr, "Exit status:\n");
+	fprintf(stderr, "  0: found at least one match for each query\n");
+	fprintf(stderr, "  1: at least one query returned nothing\n");
+	fprintf(stderr, "  2: real trouble, try repeating with -v\n");
+
+	exit (2);
+}
+
+/* crack spec and add to srchs[], else exit */
+static void
+crackDPE (char *spec)
+{
+	char d[1024], p[1024], e[1024];
+
+	if (verbose)
+	    fprintf (stderr, "looking for %s\n", spec);
+	if (sscanf (spec, "%[^.].%[^.].%[^.]", d, p, e) != 3) {
+	    fprintf (stderr, "Unknown format for property spec: %s\n", spec);
+	    usage();
+	}
+
+	addSearchDef (d, p, e);
+}
+
+/* grow srchs[] with the new search */
+static void
+addSearchDef (char *dev, char *prop, char *ele)
+{
+	if (!srchs)
+	    srchs = (SearchDef *) malloc (1);		/* realloc seed */
+	srchs = (SearchDef *) realloc (srchs, (nsrchs+1)*sizeof(SearchDef));
+	srchs[nsrchs].d = strcpy (malloc(strlen(dev)+1), dev);
+	srchs[nsrchs].p = strcpy (malloc(strlen(prop)+1), prop);
+	srchs[nsrchs].e = strcpy (malloc(strlen(ele)+1), ele);
+	srchs[nsrchs].wc = *dev==WILDCARD || *prop==WILDCARD || *ele==WILDCARD;
+	srchs[nsrchs].ok = 0;
+	nsrchs++;
+}
+
+/* open a connection to the given host and port.
+ * set svrwfp and svrrfp or die.
+ */
+static void
+openINDIServer (void)
+{
+	struct sockaddr_in serv_addr;
+	struct hostent *hp;
+	int sockfd;
+
+	/* lookup host address */
+	hp = gethostbyname (host);
+	if (!hp) {
+	    herror ("gethostbyname");
+	    exit (2);
+	}
+
+	/* create a socket to the INDI server */
+	(void) memset ((char *)&serv_addr, 0, sizeof(serv_addr));
+	serv_addr.sin_family = AF_INET;
+	serv_addr.sin_addr.s_addr =
+			    ((struct in_addr *)(hp->h_addr_list[0]))->s_addr;
+	serv_addr.sin_port = htons(port);
+	if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+	    perror ("socket");
+	    exit(2);
+	}
+
+	/* connect */
+	if (connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){
+	    perror ("connect");
+	    exit(2);
+	}
+
+	/* prepare for line-oriented i/o with client */
+	svrwfp = fdopen (sockfd, "w");
+	svrrfp = fdopen (sockfd, "r");
+}
+
+/* issue getProperties to svrwfp, possibly constrained to one device */
+static void
+getprops()
+{
+	char *onedev = NULL;
+	int i;
+
+	/* find if only need one device */
+	for (i = 0; i < nsrchs; i++) {
+	    char *d = srchs[i].d;
+	    if (*d == WILDCARD || (onedev && strcmp(d,onedev))) {
+		onedev = NULL;
+		break;
+	    } else
+		onedev = d;
+	}
+
+	if (onedev)
+	    fprintf(svrwfp, "<getProperties version='%g' device='%s'/>\n",
+								INDIV, onedev);
+	else
+	    fprintf(svrwfp, "<getProperties version='%g'/>\n", INDIV);
+	fflush (svrwfp);
+
+	if (verbose)
+	    fprintf (stderr, "Queried properties from %s\n", onedev?onedev:"*");
+}
+
+/* listen for INDI traffic on svrrfp.
+ * print matching srchs[] and return when see all.
+ * timeout and exit if any trouble.
+ */
+static void
+listenINDI ()
+{
+	char msg[1024];
+
+	/* arrange to call onAlarm() if not seeing any more defXXX */
+	signal (SIGALRM, onAlarm);
+	alarm (timeout);
+
+	/* read from server, exit if find all requested properties */
+	while (1) {
+	    XMLEle *root = readXMLEle (lillp, readServerChar(), msg);
+	    if (root) {
+		/* found a complete XML element */
+		if (verbose > 1)
+		    prXMLEle (stderr, root, 0);
+		findDPE (root);
+		if (finished() == 0)
+		    exit (0);		/* found all we want */
+		delXMLEle (root);	/* not yet, delete and continue */
+	    } else if (msg[0]) {
+		fprintf (stderr, "Bad XML from %s/%d: %s\n", host, port, msg);
+		exit(2);
+	    }
+	}
+}
+
+/* return 0 if we are sure we have everything we are looking for, else -1 */
+static int
+finished ()
+{
+	int i;
+
+	if (monitor)
+	    return(-1);
+
+	for (i = 0; i < nsrchs; i++)
+	    if (srchs[i].wc || !srchs[i].ok)
+		return (-1);
+	return (0);
+}
+
+/* called after timeout seconds either because we are matching wild cards or
+ * there is something still not found
+ */
+static void
+onAlarm (int dummy)
+{
+	int trouble = 0;
+	int i;
+
+	for (i = 0; i < nsrchs; i++) {
+	    if (!srchs[i].ok) {
+		trouble = 1;
+		fprintf (stderr, "No %s.%s.%s from %s:%d\n", srchs[i].d,
+					srchs[i].p, srchs[i].e, host, port);
+	    }
+	}
+
+	exit (trouble ? 1 : 0);
+}
+
+/* read one char from svrrfp */
+static int
+readServerChar ()
+{
+	int c = fgetc (svrrfp);
+
+	if (c == EOF) {
+	    if (ferror(svrrfp))
+		perror ("read");
+	    else
+		fprintf (stderr,"INDI server %s/%d disconnected\n", host, port);
+	    exit (2);
+	}
+
+	if (verbose > 2)
+	    fprintf (stderr, "Read %c\n", c);
+
+	return (c);
+}
+
+/* print value if root is any srchs[] we are looking for*/
+static void
+findDPE (XMLEle *root)
+{
+	int i, j;
+
+	for (i = 0; i < nsrchs; i++) {
+	    /* for each property we are looking for */
+	    for (j = 0; j < ndefs; j++) {
+		/* for each possible type */
+		if (strcmp (tagXMLEle (root), defs[j].vec) == 0) {
+		    /* legal defXXXVector, check device */
+		    char *dev = findXMLAttValu (root, "device");
+		    char *idev = srchs[i].d;
+		    if (idev[0] == WILDCARD || !strcmp (dev,idev)) {
+			/* found device, check name */
+			char *nam = findXMLAttValu (root, "name");
+			char *iprop = srchs[i].p;
+			if (iprop[0] == WILDCARD || !strcmp (nam,iprop)) {
+			    /* found device and name, check perm */
+			    char *perm = findXMLAttValu (root, "perm");
+			    if (!wflag && perm[0] && !strchr (perm, 'r')) {
+				if (verbose)
+				    fprintf (stderr, "%s.%s is write-only\n",
+								    dev, nam);
+			    } else {
+				/* check elements or attr keywords */
+				if (!strcmp (defs[j].vec, "defBLOBVector"))
+				    enableBLOBs (dev,nam);
+				else
+				    findEle(root,dev,nam,defs[j].one,&srchs[i]);
+				if (onematch)
+				    return;		/* only one can match */
+				if (!strncmp (defs[j].vec, "def", 3))
+				    alarm (timeout);	/* reset timer if def */
+			    }
+			}
+		    }
+		}
+	    }
+	}
+}
+
+/* print elements in root speced in sp (known to be of type defone).
+ * print just value if onematch and justvalue else fully qualified name.
+ */
+static void
+findEle (XMLEle *root, char *dev, char *nam, char *defone, SearchDef *sp)
+{
+	char *iele = sp->e;
+	XMLEle *ep;
+	int i;
+
+	/* check for attr keyword */
+	for (i = 0; i < NKWA; i++) {
+	    if (strcmp (iele, kwattr[i].keyword) == 0) {
+		/* just print the property state, not the element values */
+		char *s = findXMLAttValu (root, kwattr[i].indiattr);
+		sp->ok = 1;   			/* progress */
+		if (onematch && justvalue)
+		    printf ("%s\n", s);
+		else
+		    printf ("%s.%s.%s=%s\n", dev, nam, kwattr[i].keyword, s);
+		return;
+	    }
+	}
+
+	/* no special attr, look for specific element name */
+	for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+	    if (!strcmp (tagXMLEle (ep), defone)) {
+		/* legal defXXX, check deeper */
+		char *enam = findXMLAttValu (ep, "name");
+		if (iele[0]==WILDCARD || !strcmp(enam,iele)) {
+		    /* found it! */
+		    char *p = pcdataXMLEle(ep);
+		    sp->ok = 1;   		/* progress */
+		    if (!strcmp (defone, "oneBLOB"))
+			oneBLOB (ep, dev, nam, enam, p, pcdatalenXMLEle(ep));
+		    else if (onematch && justvalue)
+			printf ("%s\n", p);
+		    else
+			printf ("%s.%s.%s=%s\n",  dev, nam, enam, p);
+		    if (onematch)
+			return;      	/* only one can match*/
+		}
+	    }
+	}
+}
+
+/* send server command to svrwfp that enables blobs for the given dev nam
+ */
+static void
+enableBLOBs(char *dev, char *nam)
+{
+	if (verbose)
+	    fprintf (stderr, "sending enableBLOB %s.%s\n", dev, nam);
+	fprintf (svrwfp,"<enableBLOB device='%s' name='%s'>Also</enableBLOB>\n",
+								    dev, nam);
+	fflush (svrwfp);
+}
+
+/* given a oneBLOB, save
+ */
+static void
+oneBLOB (XMLEle *root, char *dev, char *nam, char *enam, char *p, int plen)
+{
+	char *format;
+	FILE *fp;
+	int bloblen;
+	unsigned char *blob;
+	int ucs;
+	int isz;
+	char fn[128];
+	int i;
+
+	/* get uncompressed size */
+	ucs = atoi(findXMLAttValu (root, "size"));
+	if (verbose)
+	    fprintf (stderr, "%s.%s.%s reports uncompressed size as %d\n",
+							dev, nam, enam, ucs);
+
+	/* get format and length */
+	format = findXMLAttValu (root, "format");
+	isz = !strcmp (&format[strlen(format)-2], ".z");
+
+	/* decode blob from base64 in p */
+	blob = malloc (3*plen/4);
+	bloblen = from64tobits ((char *)blob, p);
+	if (bloblen < 0) {
+	    fprintf (stderr, "%s.%s.%s bad base64\n", dev, nam, enam);
+	    exit(2);
+	}
+
+	/* uncompress effectively in place if z */
+	if (isz) {
+	    uLong nuncomp = ucs;
+	    unsigned char *uncomp = malloc (ucs);
+	    int ok = uncompress (uncomp, &nuncomp, blob, bloblen);
+	    if (ok != Z_OK) {
+		fprintf (stderr, "%s.%s.%s uncompress error %d\n", dev, nam,
+								    enam, ok);
+		exit(2);
+	    }
+	    free (blob);
+	    blob = uncomp;
+	    bloblen = nuncomp;
+	}
+
+	/* rig up a file name from property name */
+	i = sprintf (fn, "%s.%s.%s%s", dev, nam, enam, format);
+	if (isz)
+	    fn[i-2] = '\0'; 	/* chop off .z */
+
+	/* save */
+	fp = fopen (fn, "w");
+	if (fp) {
+	    if (verbose)
+		fprintf (stderr, "Wrote %s\n", fn);
+	    fwrite (blob, bloblen, 1, fp);
+	    fclose (fp);
+	} else {
+	    fprintf (stderr, "%s: %s\n", fn, strerror(errno));
+	}
+
+	/* clean up */
+	free (blob);
+}
+
+/* For RCS Only -- Do Not Edit */
+static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: getINDI.c,v $ $Date: 2007/10/11 20:11:23 $ $Revision: 1.11 $ $Name:  $"};
Index: /BAORadio/libindi/v1/tools/setINDIproperty.c
===================================================================
--- /BAORadio/libindi/v1/tools/setINDIproperty.c	(revision 500)
+++ /BAORadio/libindi/v1/tools/setINDIproperty.c	(revision 500)
@@ -0,0 +1,519 @@
+/* connect to an INDI server and set one or more device.property.element.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "indiapi.h"
+#include "lilxml.h"
+
+/* table of INDI definition elements we can set
+ * N.B. do not change defs[] order, they are indexed via -x/-n/-s args
+ */
+typedef struct {
+    char *defType;			/* defXXXVector name */
+    char *defOne;			/* defXXX name */
+    char *newType;			/* newXXXVector name */
+    char *oneType;			/* oneXXX name */
+} INDIDef;
+static INDIDef defs[] = {
+    {"defTextVector",   "defText",   "newTextVector",   "oneText"},
+    {"defNumberVector", "defNumber", "newNumberVector", "oneNumber"},
+    {"defSwitchVector", "defSwitch", "newSwitchVector", "oneSwitch"},
+};
+#define	NDEFS	(sizeof(defs)/sizeof(defs[0]))
+
+#define INDIPORT	7624		/* default port */
+static char host_def[] = "localhost";	/* default host name */
+
+static char *me;			/* our name for usage message */
+static char *host = host_def;		/* working host name */
+static int port = INDIPORT;		/* working port number */
+static int verbose;			/* report extra info */
+static int directfd = -1;		/* direct filedes to server, if >= 0 */
+#define TIMEOUT         2               /* default timeout, secs */
+static int timeout = TIMEOUT;           /* working timeout, secs */
+static LilXML *lillp;			/* XML parser context */
+
+typedef struct {
+    char *e, *v;			/* element name and value */
+    int ok;				/* set when found */
+} SetEV;
+
+typedef struct {
+    char *d;				/* device */
+    char *p;				/* property */
+    SetEV *ev;				/* elements */
+    int nev;				/* n elements */
+    INDIDef *dp;			/* one of defs if known, else NULL */
+} SetSpec;
+
+static SetSpec *sets;			/* set of properties to set */
+static int nsets;
+
+
+static void usage (void);
+static int crackSpec (int *acp, char **avp[]);
+static void openINDIServer(FILE **rfpp, FILE **wfpp);
+static void listenINDI (FILE *rfp, FILE *wfp);
+static int finished (void);
+static void onAlarm (int dummy);
+static int readServerChar (FILE *fp);
+static void findSet (XMLEle *root, FILE *fp);
+static void scanEV (SetSpec *sp, char e[], char v[]);
+static void sendNew (FILE *fp, INDIDef *dp, SetSpec *sp);
+static void sendSpecs(FILE *wfp);
+
+int
+main (int ac, char *av[])
+{
+	FILE *rfp, *wfp;
+	int stop = 0;
+	int allspeced;
+
+	/* save our name */
+	me = av[0];
+
+	/* crack args */
+	while (!stop && --ac && **++av == '-') {
+	    char *s = *av;
+	    while (*++s) {
+		switch (*s) {
+
+		case 'd':
+		    if (ac < 2) {
+			fprintf (stderr, "-d requires open fileno\n");
+			usage();
+		    }
+		    directfd = atoi(*++av);
+		    ac--;
+		    break;
+
+		case 'h':
+		    if (directfd >= 0) {
+			fprintf (stderr, "Can not combine -d and -h\n");
+			usage();
+		    }
+		    if (ac < 2) {
+			fprintf (stderr, "-h requires host name\n");
+			usage();
+		    }
+		    host = *++av;
+		    ac--;
+		    break;
+
+		case 'p':
+		    if (directfd >= 0) {
+			fprintf (stderr, "Can not combine -d and -p\n");
+			usage();
+		    }
+		    if (ac < 2) {
+			fprintf (stderr, "-p requires tcp port number\n");
+			usage();
+		    }
+		    port = atoi(*++av);
+		    ac--;
+		    break;
+
+		case 't':
+		    if (ac < 2) {
+			fprintf (stderr, "-t requires timeout\n");
+			usage();
+		    }
+		    timeout = atoi(*++av);
+		    ac--;
+		    break;
+
+		case 'v':	/* verbose */
+		    verbose++;
+		    break;
+
+		case 'x':	/* FALLTHRU */
+		case 'n':	/* FALLTHRU */
+		case 's':
+		    /* stop if see one of the property types */
+		    stop = 1;
+		    break;
+
+		default:
+		    fprintf (stderr, "Unknown flag: %c\n", *s);
+		    usage();
+		}
+	    }
+	}
+
+	/* now ac args starting at av[0] */
+	if (ac < 1)
+	    usage();
+
+	/* crack each property, add to sets[]  */
+	allspeced = 1;
+	do {
+	    if (!crackSpec (&ac, &av))
+		allspeced = 0;
+	} while (ac > 0);
+
+	/* open connection */
+	if (directfd >= 0) {
+	    wfp = fdopen (directfd, "w");
+	    rfp = fdopen (directfd, "r");
+	    setbuf (rfp, NULL);		/* don't absorb next guy's stuff */
+	    if (!rfp || !wfp) {
+		fprintf (stderr, "Direct fd %d: %s\n",directfd,strerror(errno));
+		exit(1);
+	    }
+	    if (verbose)
+		fprintf (stderr, "Using direct fd %d\n", directfd);
+	} else {
+	    openINDIServer(&rfp, &wfp);
+	    if (verbose)
+		fprintf (stderr, "Connected to %s on port %d\n", host, port);
+	}
+
+	/* build a parser context for cracking XML responses */
+	lillp = newLilXML();
+
+	/* just send it all speced, else check with server */
+	if (allspeced) {
+	    sendSpecs(wfp);
+	} else {
+	    /* issue getProperties */
+	    if (verbose)
+		fprintf (stderr, "Querying for properties\n");
+	    fprintf(wfp, "<getProperties version='%g'/>\n", INDIV);
+	    fflush (wfp);
+
+	    /* listen for properties, set when see any we recognize */
+	    listenINDI(rfp, wfp);
+	}
+
+	return (0);
+}
+
+static void
+usage()
+{
+	fprintf(stderr, "Purpose: set one or more writable INDI properties\n");
+	fprintf(stderr, "%s\n", "$Revision: 1.4 $");
+	fprintf(stderr, "Usage: %s [options] {[type] device.property.e1[;e2...]=v1[;v2...]} ...\n",
+									    me);
+	fprintf(stderr, "Options:\n");
+	fprintf(stderr, "  -d f  : use file descriptor f already open to server\n");
+	fprintf(stderr, "  -h h  : alternate host, default is %s\n", host_def);
+	fprintf(stderr, "  -p p  : alternate port, default is %d\n", INDIPORT);
+	fprintf(stderr, "  -t t  : max time to wait, default is %d secs\n",TIMEOUT);
+	fprintf(stderr, "  -v    : verbose (cumulative)\n");
+	fprintf(stderr, "Each property optionally preceded by its type is sent without first confirming\n");
+	fprintf(stderr, "its structure. This is much more efficient but there is no error checking.\n");
+	fprintf(stderr, "Types are indicated with the following flags:\n");
+	fprintf(stderr, "  -x    : Text\n");
+	fprintf(stderr, "  -n    : Number\n");
+	fprintf(stderr, "  -s    : Switch\n");
+	fprintf(stderr, "Exit status:\n");
+	fprintf(stderr, "  0: all settings successful\n");
+	fprintf(stderr, "  1: at least one setting was invalid\n");
+	fprintf(stderr, "  2: real trouble, try repeating with -v\n");
+
+	exit (2);
+}
+
+/* crack property set spec, add to sets [], move to next spec.
+ * return 1 if see a type
+ */
+static int
+crackSpec (int *acp, char **avp[])
+{
+	char d[1024], p[1024], e[2048], v[2048];
+	char *spec = *avp[0];
+	INDIDef *dp = NULL;
+
+	/* check if first arg is type indicator */
+	if (spec[0] == '-') {
+	    switch (spec[1]) {
+	    case 'x':	dp = &defs[0]; break;
+	    case 'n':	dp = &defs[1]; break;
+	    case 's':	dp = &defs[2]; break;
+	    default:
+		fprintf (stderr, "Bad property type: %s\n", spec);
+		usage();
+	    }
+	    (*acp)--;
+	    (*avp)++;
+	    spec = *avp[0];
+	}
+
+	/* then scan arg for property spec */
+	if (sscanf (spec, "%[^.].%[^.].%[^.=]=%s", d, p, e, v) != 4) {
+	    fprintf (stderr, "Bad property format: %s\n", spec);
+	    usage();
+	}
+
+	/* add to list */
+	if (!sets)
+	    sets = (SetSpec *) malloc (1);		/* seed realloc */
+	sets = (SetSpec *) realloc (sets, (nsets+1)*sizeof(SetSpec));
+	sets[nsets].d = strcpy (malloc(strlen(d)+1), d);
+	sets[nsets].p = strcpy (malloc(strlen(p)+1), p);
+	sets[nsets].dp = dp;
+	sets[nsets].ev = (SetEV *) malloc (1);		/* seed realloc */
+	sets[nsets].nev = 0;
+	scanEV (&sets[nsets++], e, v);
+
+	/* update caller's pointers */
+	(*acp)--;
+	(*avp)++;
+
+	/* return 1 if saw a spec */
+	return (dp ? 1 : 0);
+}
+
+/* open a read and write connection to host and port or die.
+ * exit if trouble.
+ */
+static void
+openINDIServer (FILE **rfpp, FILE **wfpp)
+{
+	struct sockaddr_in serv_addr;
+	struct hostent *hp;
+	int sockfd;
+
+	/* lookup host address */
+	hp = gethostbyname (host);
+	if (!hp) {
+	    perror ("gethostbyname");
+	    exit (2);
+	}
+
+	/* create a socket to the INDI server */
+	(void) memset ((char *)&serv_addr, 0, sizeof(serv_addr));
+	serv_addr.sin_family = AF_INET;
+	serv_addr.sin_addr.s_addr =
+			    ((struct in_addr *)(hp->h_addr_list[0]))->s_addr;
+	serv_addr.sin_port = htons(port);
+	if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+	    perror ("socket");
+	    exit(2);
+	}
+
+	/* connect */
+	if (connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){
+	    perror ("connect");
+	    exit(2);
+	}
+
+	/* prepare for line-oriented i/o to client */
+	*rfpp = fdopen (sockfd, "r");
+	*wfpp = fdopen (sockfd, "w");
+}
+
+/* listen for property reports, send new sets if match */
+static void
+listenINDI (FILE *rfp, FILE *wfp)
+{
+	char msg[1024];
+
+	/* arrange to call onAlarm() if not seeing any more defXXX */
+	signal (SIGALRM, onAlarm);
+	alarm (timeout);
+
+	/* read from server, exit if find all properties */
+	while (1) {
+	    XMLEle *root = readXMLEle (lillp, readServerChar(rfp), msg);
+	    if (root) {
+		/* found a complete XML element */
+		if (verbose > 1)
+		    prXMLEle (stderr, root, 0);
+		findSet (root, wfp);
+		if (finished() == 0) {
+		    shutdown (fileno(wfp), SHUT_WR);	/* insure flush */
+		    exit (0);		/* found all we want */
+		}
+		delXMLEle (root);	/* not yet, delete and continue */
+	    } else if (msg[0]) {
+		fprintf (stderr, "Bad XML from %s/%d: %s\n", host, port, msg);
+		exit(2);
+	    }
+	}
+}
+
+/* return 0 if we are sure we set everything we wanted to, else -1 */
+static int
+finished ()
+{
+	int i, j;
+
+	for (i = 0; i < nsets; i++)
+	    for (j = 0; j < sets[i].nev; j++)
+		if (!sets[i].ev[j].ok)
+		    return (-1);
+	return (0);
+}
+
+/* called after timeout seconds because we did not find something we trying
+ * to set.
+ */
+static void
+onAlarm (int dummy)
+{
+	int i, j;
+
+	for (i = 0; i < nsets; i++)
+	    for (j = 0; j < sets[i].nev; j++)
+		if (!sets[i].ev[j].ok)
+		    fprintf (stderr, "No %s.%s.%s from %s:%d\n", sets[i].d,
+				    sets[i].p, sets[i].ev[j].e, host, port);
+
+	exit (1);
+}
+
+static int
+readServerChar (FILE *fp)
+{
+	int c = fgetc (fp);
+
+	if (c == EOF) {
+	    if (ferror(fp))
+		perror ("read");
+	    else
+		fprintf (stderr,"INDI server %s:%d disconnected\n", host, port);
+	    exit (2);
+	}
+
+	if (verbose > 2)
+	    fprintf (stderr, "Read %c\n", c);
+
+	return (c);
+}
+
+/* issue a set command if it matches the given property */
+static void
+findSet (XMLEle *root, FILE *fp)
+{
+	char *rtype, *rdev, *rprop;
+	XMLEle *ep;
+	int t, s, i;
+
+	/* check type */
+	rtype = tagXMLEle (root);
+	for (t = 0; t < NDEFS; t++)
+	    if (strcmp (rtype, defs[t].defType) == 0)
+		break;
+	if (t == NDEFS)
+	    return;
+	alarm (timeout);	/* reset timeout */
+
+	/* check each set for matching device and property name, send if ok */
+	rdev  = findXMLAttValu (root, "device");
+	rprop = findXMLAttValu (root, "name");
+	if (verbose > 1)
+	    fprintf (stderr, "Read definition for %s.%s\n", rdev, rprop);
+	for (s = 0; s < nsets; s++) {
+	    if (!strcmp (rdev, sets[s].d) && !strcmp (rprop, sets[s].p)) {
+		/* found device and name,  check perm */
+		if (!strchr (findXMLAttValu (root, "perm"), 'w')) {
+		    if (verbose)
+			fprintf (stderr, "%s.%s is read-only\n", rdev, rprop);
+		    exit (1);
+		}
+		/* check matching elements */
+		for (i = 0; i < sets[s].nev; i++) {
+		    for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) {
+			if (!strcmp(findXMLAttValu (ep,"name"),sets[s].ev[i].e)
+				    && !strcmp(tagXMLEle(ep), defs[t].defOne)) {
+			    sets[s].ev[i].ok = 1;
+			    break;
+			}
+		    }
+		    if (!ep)
+			return;		/* not in this msg, maybe later */
+		}
+		/* all element names found, send new values */
+		sendNew (fp, &defs[t], &sets[s]);
+	    }
+	}
+}
+
+/* send the given set specification of the given INDI type to channel on fp */
+static void
+sendNew (FILE *fp, INDIDef *dp, SetSpec *sp)
+{
+	int i;
+
+	fprintf (fp, "<%s device='%s' name='%s'>\n", dp->newType, sp->d, sp->p);
+	for (i = 0; i < sp->nev; i++) {
+	    if (verbose)
+		fprintf (stderr, "  %s.%s.%s <- %s\n", sp->d, sp->p,
+						    sp->ev[i].e, sp->ev[i].v);
+	    fprintf (fp, "  <%s name='%s'>%s</%s>\n", dp->oneType, sp->ev[i].e,
+						    sp->ev[i].v, dp->oneType);
+	}
+	fprintf (fp, "</%s>\n", dp->newType);
+	fflush (fp);
+	if (feof(fp) || ferror(fp)) {
+	    fprintf (stderr, "Send error\n");
+	    exit(2);
+	}
+}
+
+/* scan e1[;e2...] v1[;v2,...] from e[] and v[] and add to spec sp.
+ * exit if trouble.
+ */
+static void
+scanEV (SetSpec *sp, char e[], char v[])
+{
+	static char sep[] = ";";
+	char *ep, *vp;
+
+	if (verbose > 1)
+	    fprintf (stderr, "Scanning %s = %s\n", e, v);
+
+	while (1) {
+	    char *e0 = strtok_r (e, sep, &ep);
+	    char *v0 = strtok_r (v, sep, &vp);
+
+	    if (!e0 && !v0)
+		break;
+	    if (!e0) {
+		fprintf (stderr, "More values than elements for %s.%s\n",
+								sp->d, sp->p);
+		exit(2);
+	    }
+	    if (!v0) {
+		fprintf (stderr, "More elements than values for %s.%s\n",
+								sp->d, sp->p);
+		exit(2);
+	    }
+
+	    sp->ev = (SetEV *) realloc (sp->ev, (sp->nev+1)*sizeof(SetEV));
+	    sp->ev[sp->nev].e = strcpy (malloc(strlen(e0)+1), e0);
+	    sp->ev[sp->nev].v = strcpy (malloc(strlen(v0)+1), v0);
+	    sp->nev++;
+
+	    e = NULL;
+	    v = NULL;
+	}
+}
+
+/* send each SetSpec, all of which have a known type, to wfp
+ */
+static void
+sendSpecs(FILE *wfp)
+{
+	int i;
+	
+	for (i = 0; i < nsets; i++)
+	    sendNew (wfp, sets[i].dp, &sets[i]);
+}
+
+/* For RCS Only -- Do Not Edit */
+static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: setINDI.c,v $ $Date: 2007/10/11 20:12:11 $ $Revision: 1.4 $ $Name:  $"};
