Commit 1b79ab46538942d56deeb33d3f9c5c71bb3a20e9
1 parent
c1f67e41
Exists in
master
Add a new component for cameras
Showing
4 changed files
with
318 additions
and
1 deletions
Show diff stats
src/guitastro/__init__.py
@@ -140,6 +140,11 @@ guitastro.component_mount_pointing | @@ -140,6 +140,11 @@ guitastro.component_mount_pointing | ||
140 | .. automodule:: guitastro.component_mount_pointing | 140 | .. automodule:: guitastro.component_mount_pointing |
141 | :members: | 141 | :members: |
142 | 142 | ||
143 | +guitastro.component_sensor_detector | ||
144 | +------------------------------------ | ||
145 | +.. automodule:: guitastro.component_sensor_detector | ||
146 | + :members: | ||
147 | + | ||
143 | guitastro.device | 148 | guitastro.device |
144 | ------------------- | 149 | ------------------- |
145 | .. automodule:: guitastro.device | 150 | .. automodule:: guitastro.device |
@@ -0,0 +1,273 @@ | @@ -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__ == "__main__": | @@ -3315,3 +3315,42 @@ if __name__ == "__main__": | ||
3315 | in_fullname = "/home/myuser/messier63.fits.gz" | 3315 | in_fullname = "/home/myuser/messier63.fits.gz" |
3316 | out_fullname = fn.join(in_fullname) | 3316 | out_fullname = fn.join(in_fullname) |
3317 | print(out_fullname) | 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__ == "__main__": | @@ -650,6 +650,6 @@ if __name__ == "__main__": | ||
650 | Create initial source code of a component file. | 650 | Create initial source code of a component file. |
651 | """ | 651 | """ |
652 | gta1 = GuitastroDev() | 652 | gta1 = GuitastroDev() |
653 | - res = gta1.create_component("DetectorFocuser", "MountyPointing") | 653 | + res = gta1.create_component("MountPointing", "SensorDetector") |
654 | print(f"res={res}") | 654 | print(f"res={res}") |
655 | 655 |