Commit 1b79ab46538942d56deeb33d3f9c5c71bb3a20e9

Authored by Alain Klotz
1 parent c1f67e41
Exists in master

Add a new component for cameras

src/guitastro/__init__.py
... ... @@ -140,6 +140,11 @@ guitastro.component_mount_pointing
140 140 .. automodule:: guitastro.component_mount_pointing
141 141 :members:
142 142  
  143 +guitastro.component_sensor_detector
  144 +------------------------------------
  145 +.. automodule:: guitastro.component_sensor_detector
  146 + :members:
  147 +
143 148 guitastro.device
144 149 -------------------
145 150 .. automodule:: guitastro.device
... ...
src/guitastro/component_sensor_detector.py 0 → 100644
... ... @@ -0,0 +1,273 @@
  1 +try:
  2 + from .siteobs import Siteobs
  3 +except:
  4 + from siteobs import Siteobs
  5 +
  6 +try:
  7 + from .ima import Ima
  8 +except:
  9 + from ima import Ima
  10 +
  11 +try:
  12 + from .etc import ExposureTimeCalculator
  13 +except:
  14 + from etc import ExposureTimeCalculator
  15 +
  16 +try:
  17 + from .component import Component, ComponentException
  18 +except:
  19 + from component import Component, ComponentException
  20 +
  21 +try:
  22 + from .guitastrotools import GuitastroException, GuitastroTools
  23 +except:
  24 + from guitastrotools import GuitastroException, GuitastroTools
  25 +
  26 +# #####################################################################
  27 +# #####################################################################
  28 +# #####################################################################
  29 +# Class Component Sensor Detector
  30 +# #####################################################################
  31 +# #####################################################################
  32 +# #####################################################################
  33 +
  34 +class ComponentSensorDetectorException(GuitastroException):
  35 +
  36 + ERR_DETECTOR_IS_EXPOSING = 1
  37 + ERR_DETECTOR_IS_READING = 2
  38 +
  39 + errors = [""]*3
  40 + errors[ERR_DETECTOR_IS_EXPOSING] = "The detector is in exposure. Cannot start other exposures"
  41 + errors[ERR_DETECTOR_IS_READING] = "The detector is reading. Cannot start other exposures"
  42 +
  43 +
  44 +class ComponentSensorDetector(ComponentSensorDetectorException, Component, GuitastroTools):
  45 + """Component for Sensor detector
  46 +
  47 + Implement only simulation operations.
  48 +
  49 + Usage : ComponentSensorDetector()
  50 + """
  51 +
  52 + # --- same as sensoraxis.py
  53 + SENSOR_STATE_UNKNOWN = -1
  54 + SENSOR_STATE_STOPED = 0
  55 + SENSOR_STATE_IDLE = 1
  56 + SENSOR_STATE_EXPOSING = 2
  57 + SENSOR_STATE_READING = 3
  58 +
  59 + # =====================================================================
  60 + # methods
  61 + # =====================================================================
  62 +
  63 + # ------------ init
  64 +
  65 + def _my_init_params(self, param_optionals: dict, sensor_types: dict):
  66 + # --- This method could be overriden
  67 + return param_optionals, sensor_types
  68 +
  69 + def init(self, *args, **kwargs):
  70 + """
  71 + Conversion from Uniform Python object into protocol language
  72 + Usage : ComponentSensorDetector("HADEC", name="Test")
  73 + """
  74 + # === Parameters of the command line
  75 + # --- Dico of optional parameters for all axis_types
  76 + param_optionals = {}
  77 + param_optionals["MODEL"] = (str, "")
  78 + param_optionals["MANUFACTURER"] = (str, "")
  79 + param_optionals["SERIAL_NUMBER"] = (str, "")
  80 + param_optionals["REAL"] = (bool, False)
  81 + param_optionals["DESCRIPTION"] = (str, "No description.")
  82 + param_optionals["SITE"] = (Siteobs,"GPS 0 E 45 100")
  83 + param_optionals["LOGO_FILE"] = (str,"")
  84 + param_optionals["ETC"] = (ExposureTimeCalculator, None)
  85 + # --- Dico of axis_types and their parameters
  86 + sensor_types = {}
  87 + sensor_types["CCD"]= {"MANDATORY" : {"NAME":[str,"Unknown"]}, "OPTIONAL" : {"LABEL":[str,"CCD Sensor"]} }
  88 + sensor_types["CMOS"]= {"MANDATORY" : {"NAME":[str,"Unknown"]}, "OPTIONAL" : {"LABEL":[str,"CMOS Sensor"]} }
  89 + # --- Add params and types when inherited
  90 + param_optionals, sensor_types = self._my_init_params(param_optionals, sensor_types)
  91 + # --- Decode args and kwargs parameters
  92 + self._sensor_params = self.decode_args_kwargs(0, sensor_types, param_optionals, *args, **kwargs)
  93 + self._sensor_type = self._sensor_params["SELECTED_ARG"]
  94 + # === Observatory location for ephemeris
  95 + if str(type(self._sensor_params["SITE"])) == "<class 'siteobs.Siteobs'>":
  96 + self.siteobs = self._sensor_params["SITE"]
  97 + else:
  98 + self.siteobs = Siteobs(self._sensor_params["SITE"])
  99 + # === Image in memory
  100 + self.ima = Ima()
  101 + self.ima.longitude(self.siteobs.longitude)
  102 + if str(type(self._sensor_params["ETC"])) == "<class 'etc.ExposureTimeCalculator'>":
  103 + self.ima.etc = self._sensor_params["ETC"]
  104 + # === Name
  105 + self.name = self._sensor_params["NAME"]
  106 + # === Initial state real or simulation
  107 + real = self._sensor_params["REAL"]
  108 + # === Call init1 (inherited from Component. Will be overriden by a concrete method)
  109 + self._my_init1(*args, **kwargs)
  110 + # === Initialisation of axis list according the sensor_type
  111 + # === Default axes setup
  112 + # === Call init2 (inherited from Component. Will be overriden by a concrete method)
  113 + self._my_init2(*args, **kwargs)
  114 + # === Default database
  115 + param = {}
  116 + param['exptime'] = 0.1
  117 + param['binning'] = [1, 1]
  118 + self._queue.put(param)
  119 +
  120 + # ------------ prop
  121 +
  122 + def prop(self):
  123 + """Component property minimal concrete method
  124 +
  125 + Extended properties will be added in the method _my_prop.
  126 + """
  127 + prop = {}
  128 + prop['category'] = 'SensorDetector'
  129 + prop['actions'] = ['GET', 'SET', 'DO']
  130 + prop['DO'] = {}
  131 + prop['DO']['NATIVE'] = "The message is sent to the device with no transformation"
  132 + prop['DO']['ACQ'] = {}
  133 + prop['DO']['ACQ']['START'] = "Start a new image acquisition"
  134 + prop['DO']['ACQ']['STOP'] = "Stop the current sensor image with a readout"
  135 + prop['DO']['ACQ']['CANCEL'] = "Cancel the current sensor image without readout"
  136 + prop = self._my_prop(prop)
  137 + return prop
  138 +
  139 + # ------------ do
  140 +
  141 + def _do_stop(self, *args, **kwargs):
  142 + operation = args[0].upper()
  143 + # --- make the simulation
  144 + self.log = f"stop simulation of {operation}"
  145 + self.database.query("motion_simu", self.SENSOR_STATE_STOPED)
  146 + # --- call the real
  147 + if self.real:
  148 + self._my_do_stop(*args, **kwargs)
  149 +
  150 + def _do(self, *args, **kwargs):
  151 + """Do an action of the component.
  152 + Args:
  153 +
  154 + *args: List of operations extracted from split of the command:
  155 +
  156 + * args[0]: main operation
  157 + * args[1]: sub operation
  158 +
  159 + Returns:
  160 +
  161 + Result depending the operation.
  162 + """
  163 + result = None
  164 + self._verify_nargs(1, *args)
  165 + operation = args[0].upper()
  166 + operations = list(self.prop()['DO'].keys())
  167 + if operation not in operations:
  168 + msg = f"{operation} not found amongst {operations}"
  169 + raise ComponentException(ComponentException.ERR_OPERATION_NOT_FOUND, msg)
  170 + # ---
  171 + kwargs['operation'] = operation
  172 + if operation == "START":
  173 + # For real and simu
  174 + result = self._do_start(*args, **kwargs)
  175 + elif operation == "STOP":
  176 + # For real and simu
  177 + result = self._do_stop(*args, **kwargs)
  178 + # --- only call the real method
  179 + self.log = f"start operation {operation}"
  180 + if self.real:
  181 + result = self._my_do(*args, **kwargs)
  182 + return self._fresult(result)
  183 +
  184 + def _my_do(self, *args, **kwargs):
  185 + value = None
  186 + return value
  187 +
  188 + # ------------ set
  189 +
  190 + def _my_set(self, *args, **kwargs):
  191 + return args, kwargs
  192 +
  193 + # ------------ get
  194 +
  195 + def _my_get_final(self, *args, **kwargs):
  196 + # This method should be overriden
  197 + pass
  198 +
  199 + def _my_get(self, *args, **kwargs):
  200 + self._my_get_final(*args, **kwargs)
  201 + return None
  202 +
  203 + # =====================================================================
  204 + # =====================================================================
  205 + # Ima methods
  206 + # =====================================================================
  207 + # =====================================================================
  208 +
  209 + # ------------ conversion int -> string for human output
  210 +
  211 + def status2string(self, status:int, verb:bool= False):
  212 + if status == self.SENSOR_STATE_STOPED:
  213 + msg = "stoped" if verb else "stop"
  214 + elif status == self.SENSOR_STATE_IDLE:
  215 + msg = "idle" if verb else "idle"
  216 + elif status == self.SENSOR_STATE_EXPOSING:
  217 + msg = "exposing" if verb else "expose"
  218 + elif status == self.SENSOR_STATE_READING:
  219 + msg = "reading" if verb else "read"
  220 + else:
  221 + msg = "unknown" if verb else "unk"
  222 + return msg
  223 +
  224 +
  225 +
  226 +# #####################################################################
  227 +# #####################################################################
  228 +# #####################################################################
  229 +# Main
  230 +# #####################################################################
  231 +# #####################################################################
  232 +# #####################################################################
  233 +
  234 +if __name__ == "__main__":
  235 +
  236 + default = 0
  237 + example = input(f"Select the example (0 to 0) ({default}) ")
  238 + try:
  239 + example = int(example)
  240 + except:
  241 + example = default
  242 +
  243 + print("Example = {}".format(example))
  244 +
  245 + import time
  246 + if example == 0:
  247 + """
  248 + Simple camera simulator
  249 + """
  250 + # --- siteobs
  251 + siteobs = Siteobs("GPS 0 E 49 200")
  252 + # --- horizon
  253 + siteobs.horizon_altaz = [(0,40), (180,0), (360,40)]
  254 + # --- Image simulator
  255 + etc = ExposureTimeCalculator()
  256 + etc.camera("Audine Kaf401ME")
  257 + etc.optics("Takahashi_180ED")
  258 + # --- Component init
  259 + comp = ComponentSensorDetector("CCD", name="test", site=siteobs, etc=etc)
  260 + comp.verbose = 1
  261 + comp.command("SET", "exptime", 1.0)
  262 + comp.command("SET", "binning", [1, 1])
  263 + # --- Start the ACQ
  264 + comp.command("DO", "ACQ", "START")
  265 + k = 0
  266 + while k<3:
  267 + # --- Get the current coordinates
  268 + status = comp.command("GET", "status")
  269 + print(f"{k:2d} status = {status} {comp.status2string(status)}")
  270 + time.sleep(2)
  271 + k += 1
  272 +
  273 +
... ...
src/guitastro/filenames.py
... ... @@ -3315,3 +3315,42 @@ if __name__ == &quot;__main__&quot;:
3315 3315 in_fullname = "/home/myuser/messier63.fits.gz"
3316 3316 out_fullname = fn.join(in_fullname)
3317 3317 print(out_fullname)
  3318 +
  3319 + if example == 16:
  3320 + """
  3321 + Create many contexts
  3322 + """
  3323 + contexts = []
  3324 + contexts.append({'context':"sequences", 'description':"Sequence files (.p, .f)", 'rootdir':"/tmp/pyros/sequences", 'pathnaming':"PyROS.seq.1"})
  3325 + contexts.append({'context':"img/darks/L0", 'description':"Dark images L0 (individuals)", 'rootdir':"/tmp/pyros/img/darks/l0", 'pathnaming':"PyROS.img.1", 'extension':".fit"})
  3326 + contexts.append({'context':"img/darks/L1", 'description':"Dark images L1 (stacks)", 'rootdir':"/tmp/pyros/img/darks/l1", 'pathnaming':"PyROS.img.1", 'extension':".fit"})
  3327 +
  3328 + fn = FileNames()
  3329 +
  3330 + for context in fn.fcontexts:
  3331 + fn.fcontext = context # select the context
  3332 + if fn.fcontext == "default":
  3333 + continue
  3334 + del fn.fcontext
  3335 +
  3336 + for context in contexts:
  3337 +
  3338 + fn.fcontext_create(context['context'], context['description'])
  3339 + fn.fcontext = context['context'] # select the context
  3340 + if context.get('rootdir') != None:
  3341 + fn.rootdir = context.get('rootdir')
  3342 + if context.get('naming') != None:
  3343 + fn.naming = context.get('naming')
  3344 + if context.get('pathing') != None:
  3345 + fn.pathing = context.get('pathing')
  3346 + if context.get('pathnaming') != None:
  3347 + fn.pathnaming = context.get('pathnaming')
  3348 + if context.get('extension') != None:
  3349 + fn.extension = context.get('extension')
  3350 +
  3351 + for context in fn.fcontexts:
  3352 + fn.fcontext = context # select the context
  3353 + if fn.fcontext == "default":
  3354 + continue
  3355 + print(f"{fn.fcontext} : {fn.fcontext_value('description')}")
  3356 +
... ...
src/guitastro/guitastrotools.py
... ... @@ -650,6 +650,6 @@ if __name__ == &quot;__main__&quot;:
650 650 Create initial source code of a component file.
651 651 """
652 652 gta1 = GuitastroDev()
653   - res = gta1.create_component("DetectorFocuser", "MountyPointing")
  653 + res = gta1.create_component("MountPointing", "SensorDetector")
654 654 print(f"res={res}")
655 655  
... ...