Commit bd83eb17322571a0b26d3be2db5b47602e530881
1 parent
1179175f
Exists in
dev
Control command Cagire web + back
Showing
10 changed files
with
668 additions
and
2 deletions
Show diff stats
simulators/config/grammar.json
@@ -245,6 +245,197 @@ | @@ -245,6 +245,197 @@ | ||
245 | "label": "Change the wanted filter", | 245 | "label": "Change the wanted filter", |
246 | "input_label": [], | 246 | "input_label": [], |
247 | "help": "Change the wanted filter" | 247 | "help": "Change the wanted filter" |
248 | + }, | ||
249 | + { | ||
250 | + "name": "EXPOSURE", | ||
251 | + "label": "Exposure time for 1 image in seconds", | ||
252 | + "input_label": [ | ||
253 | + { | ||
254 | + "exposure" : [15, "Int", "Exposure time"] | ||
255 | + } | ||
256 | + ], | ||
257 | + "help": "Exposure time for 1 image in seconds" | ||
258 | + }, | ||
259 | + { | ||
260 | + "name": "BINNING", | ||
261 | + "label": "Binning of cells", | ||
262 | + "input_label": [ | ||
263 | + { | ||
264 | + "binning" : [15, "Int", "Binning"] | ||
265 | + } | ||
266 | + ], | ||
267 | + "help": "Set the Binning of cells." | ||
268 | + } | ||
269 | + ], | ||
270 | + "get": [ | ||
271 | + { | ||
272 | + "name": "STATUS", | ||
273 | + "label": "Get camera status values (dict)", | ||
274 | + "input_label": [], | ||
275 | + "help": "Get camera status values (dict): struct(key, value, type, unit, comment)" | ||
276 | + }, | ||
277 | + { | ||
278 | + "name": "SETUP", | ||
279 | + "label": "Get static values for config (dict)", | ||
280 | + "input_label": [], | ||
281 | + "help": "Get static values for config (eg. limit speed)" | ||
282 | + }, | ||
283 | + { | ||
284 | + "name": "TIMER", | ||
285 | + "label": "Get the ime before end of pose", | ||
286 | + "input_label": [], | ||
287 | + "help": "Time before end of pose (-1 == idle / finished, 0 == readout (recup-ing img))" | ||
288 | + } | ||
289 | + | ||
290 | + ], | ||
291 | + "do": [ | ||
292 | + { | ||
293 | + "name": "COOLER ON", | ||
294 | + "label": "Turn On the cooler with the given temperature", | ||
295 | + "input_label": [ | ||
296 | + { | ||
297 | + "temp":[15, "Float", "temperature"] | ||
298 | + } | ||
299 | + ], | ||
300 | + "help": "Turn On the cooler with the given temperature." | ||
301 | + }, | ||
302 | + { | ||
303 | + "name": "COOLER OFF", | ||
304 | + "label": "Turn off the cooler", | ||
305 | + "input_label": [], | ||
306 | + "help": "Turn off the cooler." | ||
307 | + }, | ||
308 | + { | ||
309 | + "name": "DOME SHUTTER OPEN", | ||
310 | + "label": "Open the dome shutter", | ||
311 | + "input_label": [], | ||
312 | + "help": "Open the dome shutter." | ||
313 | + }, | ||
314 | + { | ||
315 | + "name": "DOME SHUTTER CLOSE", | ||
316 | + "label": "Close the dome shutter", | ||
317 | + "input_label": [], | ||
318 | + "help": "Close the dome shutter" | ||
319 | + }, | ||
320 | + { | ||
321 | + "name": "DOME SHUTTER SYNCHRO", | ||
322 | + "label": "Dome Shutter Synchro", | ||
323 | + "input_label": [], | ||
324 | + "help": "Dome Shutter Synchro" | ||
325 | + }, | ||
326 | + { | ||
327 | + "name": "START", | ||
328 | + "label": "Start Pose", | ||
329 | + "input_label": [], | ||
330 | + "help": "Start Pose" | ||
331 | + }, | ||
332 | + { | ||
333 | + "name": "ABORT", | ||
334 | + "label": "Stop Pose", | ||
335 | + "input_label": [], | ||
336 | + "help": "Stop Pose" | ||
337 | + }, | ||
338 | + { | ||
339 | + "name": "STOP", | ||
340 | + "label": "End image then stop pose", | ||
341 | + "input_label": [], | ||
342 | + "help": "End image then stop pose" | ||
343 | + } | ||
344 | + | ||
345 | + ] | ||
346 | + | ||
347 | + | ||
348 | + }, | ||
349 | + "CameraNIR" : { | ||
350 | + "set": [ | ||
351 | + { | ||
352 | + "name": "WINDOW", | ||
353 | + "label": "Set the window coordinates", | ||
354 | + "input_label": [ | ||
355 | + { | ||
356 | + "x1":[10, "Int", "x left bottom"], | ||
357 | + "x2":[10, "Int", "y left bottom"], | ||
358 | + "y1":[10, "Int", "x right top corner"], | ||
359 | + "y2":[10, "Int", "y right top corner"] | ||
360 | + } | ||
361 | + ], | ||
362 | + "help": "Coordinates of window corners (left bot, right top)" | ||
363 | + }, | ||
364 | + { | ||
365 | + "name": "READMODE [MODE 1]", | ||
366 | + "label": "Set Mode of observation (ramp, ...)", | ||
367 | + "input_label": [], | ||
368 | + "help": "Set the Mode of observation (ramp, ...)" | ||
369 | + }, | ||
370 | + { | ||
371 | + "name": "READMODE [MODE 2]", | ||
372 | + "label": "Set Mode of observation (ramp, ...)", | ||
373 | + "input_label": [], | ||
374 | + "help": "Set the Mode of observation (ramp, ...)" | ||
375 | + }, | ||
376 | + { | ||
377 | + "name": "READMODE [MODE 3]", | ||
378 | + "label": "Set Mode of observation (ramp, ...)", | ||
379 | + "input_label": [], | ||
380 | + "help": "Set the Mode of observation (ramp, ...)" | ||
381 | + }, | ||
382 | + { | ||
383 | + "name": "FILENAME", | ||
384 | + "label": "Change the used file", | ||
385 | + "input_label": [ | ||
386 | + { | ||
387 | + "filename" : [256, "Str", "filename"] | ||
388 | + } | ||
389 | + ], | ||
390 | + "help": "Optional, not wanting default file name (reset between each image)" | ||
391 | + }, | ||
392 | + { | ||
393 | + "name": "HEADER", | ||
394 | + "label": "Set particular values in the header", | ||
395 | + "input_label": [ | ||
396 | + { | ||
397 | + "header values" : [1024, "Str (dict)", "header values"] | ||
398 | + } | ||
399 | + ], | ||
400 | + "help": "Set particular values in the header" | ||
401 | + }, | ||
402 | + { | ||
403 | + "name": "READOUT_FREQUENCY", | ||
404 | + "label": "Readout frequency in pix/s (~= Hz)", | ||
405 | + "input_label": [ | ||
406 | + { | ||
407 | + "readout freq" : [15, "Float", "readout freq pix/s ~= Hz"] | ||
408 | + } | ||
409 | + ], | ||
410 | + "help": "Readout frequency in pix/s (~= Hz)" | ||
411 | + }, | ||
412 | + { | ||
413 | + "name": "FILTER [FILTER 1]", | ||
414 | + "label": "Change the wanted filter", | ||
415 | + "input_label": [], | ||
416 | + "help": "Change the wanted filter" | ||
417 | + }, | ||
418 | + { | ||
419 | + "name": "FILTER [FILTER 2]", | ||
420 | + "label": "Change the wanted filter", | ||
421 | + "input_label": [], | ||
422 | + "help": "Change the wanted filter" | ||
423 | + }, | ||
424 | + { | ||
425 | + "name": "FILTER [FILTER 3]", | ||
426 | + "label": "Change the wanted filter", | ||
427 | + "input_label": [], | ||
428 | + "help": "Change the wanted filter" | ||
429 | + }, | ||
430 | + { | ||
431 | + "name": "NB_IMAGES", | ||
432 | + "label": "Number of images in the ramp (x1.4s)", | ||
433 | + "input_label": [ | ||
434 | + { | ||
435 | + "nb_imgs" : [15, "Int", "nb images"] | ||
436 | + } | ||
437 | + ], | ||
438 | + "help": "Set the number of images in the ramp (x1.4s)" | ||
248 | } | 439 | } |
249 | ], | 440 | ], |
250 | "get": [ | 441 | "get": [ |
src/dashboard/templates/dashboard/observation_status.html
@@ -125,6 +125,11 @@ | @@ -125,6 +125,11 @@ | ||
125 | {% for log in cagire_logs %} | 125 | {% for log in cagire_logs %} |
126 | <li>{{log.created}} : {{log.message}}</li> {% endfor %} | 126 | <li>{{log.created}} : {{log.message}}</li> {% endfor %} |
127 | </ul> | 127 | </ul> |
128 | + {% if not config.global_mode %} | ||
129 | + <form action={% url "send_command_to_cameraNIR" %}> | ||
130 | + <input class="send_command_button" id="send_command_cameraNIR" type="submit" value="Send Command" /> | ||
131 | + </form> | ||
132 | + {% endif %} | ||
128 | </div> | 133 | </div> |
129 | <div class="element" id=DDRAGORED> | 134 | <div class="element" id=DDRAGORED> |
130 | <h2><button id="ddrago_r_button">DDRAGO RED</button></h2> | 135 | <h2><button id="ddrago_r_button">DDRAGO RED</button></h2> |
src/dashboard/templates/dashboard/send_command_cameraNIR.html
0 โ 100644
@@ -0,0 +1,124 @@ | @@ -0,0 +1,124 @@ | ||
1 | +{% extends "base.html" %} | ||
2 | +{% load staticfiles%} | ||
3 | + | ||
4 | +{% block title %} | ||
5 | + Send Command to CAGIRE | ||
6 | +{% endblock %} | ||
7 | + | ||
8 | +{% block content %} | ||
9 | +<html lang="en"> | ||
10 | +<head> | ||
11 | + <meta charset="UTF-8"> | ||
12 | + | ||
13 | +</head> | ||
14 | +<body> | ||
15 | + <style> | ||
16 | + | ||
17 | + .conteneur | ||
18 | + { | ||
19 | + display: flex; | ||
20 | + flex-wrap: wrap-reverse; | ||
21 | + justify-content: space-between; | ||
22 | + } | ||
23 | + .element | ||
24 | + { | ||
25 | + | ||
26 | + margin: auto; | ||
27 | + list-style-image: none; | ||
28 | + font-family: 'Montserra', sans-serif; | ||
29 | + | ||
30 | + } | ||
31 | + | ||
32 | + .element h2 | ||
33 | + { | ||
34 | + text-align: center; | ||
35 | + font-weight: normal; | ||
36 | + } | ||
37 | + .log | ||
38 | + { | ||
39 | + font-size: 1.13em; | ||
40 | + list-style-image: none; | ||
41 | + list-style-type: none; | ||
42 | + color: green; | ||
43 | + font-weight: bold; | ||
44 | + font-family: "Arial"; | ||
45 | + height: 500px; | ||
46 | + width: 650px; | ||
47 | + overflow: scroll; | ||
48 | + background-color: black; | ||
49 | + } | ||
50 | + | ||
51 | + #id_first_command | ||
52 | + { | ||
53 | + font-size: 19px; | ||
54 | + } | ||
55 | + | ||
56 | + | ||
57 | + #submit_button | ||
58 | + { | ||
59 | + display: block; | ||
60 | + font-size: 20px; | ||
61 | + margin: auto; | ||
62 | + } | ||
63 | + #expert_mode | ||
64 | + { | ||
65 | + font-size: 15px; | ||
66 | + } | ||
67 | +</style> | ||
68 | + | ||
69 | + <!-- TODO:Passer aux django forms une fois que la grammaire sera fixรฉe --> | ||
70 | + | ||
71 | + <div class="conteneur"> | ||
72 | + <div id="command" class="element"> | ||
73 | + <form id=command_form method="POST" action={% url "submit_command_to_cameraNIR" %}> | ||
74 | + | ||
75 | + <label for="Command"><h2>Select the command</h2></label><br/> | ||
76 | + | ||
77 | + <select name="first_command" id="id_first_command"> | ||
78 | + <option value="Command" selected>Command :</option> | ||
79 | + <option value="SET">SET</option> | ||
80 | + <option value="GET">GET</option> | ||
81 | + <option value="DO">DO</option> | ||
82 | + </select> | ||
83 | + | ||
84 | + </form> | ||
85 | + <br><br> | ||
86 | + <form id="command_form_expert" method="POST" action="{% url "submit_command_to_cameraNIR_expert" %}"> | ||
87 | + <label for="Command"><h2>Enter the command in expert mode</h2></label><br/> | ||
88 | + <button id="expert_mode" type="button">Expert Mode</button> | ||
89 | + {% csrf_token %} | ||
90 | + </form> | ||
91 | + </div> | ||
92 | + <div id="logs" class="element"> | ||
93 | + <div id="cagire"> | ||
94 | + <h2>CAGIRE</h2> | ||
95 | + <ul class="log" id="cagire_logs"> | ||
96 | + <br> | ||
97 | + </ul> | ||
98 | + </div> | ||
99 | + </div> | ||
100 | + </div> | ||
101 | + <script> var data = {{ json_str | safe }}</script> | ||
102 | + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> | ||
103 | + <script src="{% static "/js/command_control_cameraNIR.js" %}" type=text/javascript></script> | ||
104 | + <script> | ||
105 | + | ||
106 | + $( "#command_form" ).submit(function( event ) { | ||
107 | + alert( "Handler for .submit() called." ); | ||
108 | + event.preventDefault(); | ||
109 | + var inputElem = document.createElement('input'); | ||
110 | + inputElem.type = 'hidden'; | ||
111 | + inputElem.name = 'csrfmiddlewaretoken'; | ||
112 | + inputElem.value = '{{ csrf_token }}'; | ||
113 | + | ||
114 | + document.getElementById("command_form").appendChild(inputElem); | ||
115 | + $( "#command_form" ).submit(); | ||
116 | +}); | ||
117 | + | ||
118 | + | ||
119 | + </script> | ||
120 | + | ||
121 | + | ||
122 | +</body> | ||
123 | +</html> | ||
124 | +{% endblock %} | ||
0 | \ No newline at end of file | 125 | \ No newline at end of file |
src/dashboard/urls.py
@@ -24,6 +24,9 @@ urlpatterns = [ | @@ -24,6 +24,9 @@ urlpatterns = [ | ||
24 | path('observation_status/send_command_to_telescope/submit_expert', views.submit_command_to_telescope_expert, name='submit_command_to_telescope_expert'), | 24 | path('observation_status/send_command_to_telescope/submit_expert', views.submit_command_to_telescope_expert, name='submit_command_to_telescope_expert'), |
25 | path('observation_status/send_command_to_telescope/submit', views.submit_command_to_telescope, name='submit_command_to_telescope'), | 25 | path('observation_status/send_command_to_telescope/submit', views.submit_command_to_telescope, name='submit_command_to_telescope'), |
26 | path('observation_status/send_command_to_telescope', views.send_command_to_telescope, name='send_command_to_telescope'), | 26 | path('observation_status/send_command_to_telescope', views.send_command_to_telescope, name='send_command_to_telescope'), |
27 | + path('observation_status/send_command_to_cameraNIR/submit_expert', views.submit_command_to_cameraNIR_expert, name='submit_command_to_cameraNIR_expert'), | ||
28 | + path('observation_status/send_command_to_cameraNIR/submit', views.submit_command_to_cameraNIR, name='submit_command_to_cameraNIR'), | ||
29 | + path('observation_status/send_command_to_cameraNIR', views.send_command_to_cameraNIR, name='send_command_to_cameraNIR'), | ||
27 | path('observation_status/send_command_to_cameraVIS_1/submit_expert', views.submit_command_to_cameraVIS_1_expert, name='submit_command_to_cameraVIS_1_expert'), | 30 | path('observation_status/send_command_to_cameraVIS_1/submit_expert', views.submit_command_to_cameraVIS_1_expert, name='submit_command_to_cameraVIS_1_expert'), |
28 | path('observation_status/send_command_to_cameraVIS_1/submit', views.submit_command_to_cameraVIS_1, name='submit_command_to_cameraVIS_1'), | 31 | path('observation_status/send_command_to_cameraVIS_1/submit', views.submit_command_to_cameraVIS_1, name='submit_command_to_cameraVIS_1'), |
29 | path('observation_status/send_command_to_cameraVIS_1', views.send_command_to_cameraVIS_1, name='send_command_to_cameraVIS_1'), | 32 | path('observation_status/send_command_to_cameraVIS_1', views.send_command_to_cameraVIS_1, name='send_command_to_cameraVIS_1'), |
src/dashboard/views.py
@@ -19,6 +19,7 @@ from random import randint | @@ -19,6 +19,7 @@ from random import randint | ||
19 | from devices.Telescope import TelescopeController | 19 | from devices.Telescope import TelescopeController |
20 | from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault | 20 | from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault |
21 | from devices.CameraVISRemoteControlDefault import CameraVISRemoteControlDefault | 21 | from devices.CameraVISRemoteControlDefault import CameraVISRemoteControlDefault |
22 | +from devices.CameraNIRRemoteControlDefault import CameraNIRRemoteControlDefault | ||
22 | from django.core.mail import send_mail | 23 | from django.core.mail import send_mail |
23 | import time | 24 | import time |
24 | import utils.celme as celme | 25 | import utils.celme as celme |
@@ -361,6 +362,53 @@ def submit_command_to_cameraVIS_1_expert(request): | @@ -361,6 +362,53 @@ def submit_command_to_cameraVIS_1_expert(request): | ||
361 | 362 | ||
362 | 363 | ||
363 | 364 | ||
365 | +@login_required | ||
366 | +@level_required(3) | ||
367 | +def send_command_to_cameraNIR(request): | ||
368 | + data = "" | ||
369 | + with open('../simulators/config/grammar.json') as f: | ||
370 | + data = json.load(f, object_pairs_hook=OrderedDict) | ||
371 | + json_str = json.dumps(data) | ||
372 | + return render(request, "dashboard/send_command_cameraNIR.html", locals()) | ||
373 | + | ||
374 | + | ||
375 | +@login_required | ||
376 | +@level_required(3) | ||
377 | +def submit_command_to_cameraNIR(request): | ||
378 | + if request.method == 'POST': | ||
379 | + commands = [request.POST.get("first_command"), request.POST.get("first_param")] | ||
380 | + try: #TODO faire un truc plus joli pour gรฉrer les params queqlue soit leur nombre | ||
381 | + input_0 = request.POST.get("input_number_0") | ||
382 | + input_1 = request.POST.get("input_number_1") | ||
383 | + input_2 = request.POST.get("input_number_2") | ||
384 | + if input_0: | ||
385 | + commands.append(input_0) | ||
386 | + if input_1: | ||
387 | + commands.append(input_1) | ||
388 | + if input_2: | ||
389 | + commands.append(input_2) | ||
390 | + except Exception: | ||
391 | + pass | ||
392 | + response = CameraNIRRemoteControlDefault(commands, expert_mode=False).exec_command() | ||
393 | + #TODO passer en JS pour send les rรฉponses en AJAX | ||
394 | + return redirect('send_command_to_cameraNIR') | ||
395 | + | ||
396 | +@login_required | ||
397 | +@level_required(3) | ||
398 | +def submit_command_to_cameraNIR_expert(request): | ||
399 | + #import os | ||
400 | + if request.method == 'POST': | ||
401 | + param = request.POST.get("commande_expert") | ||
402 | + if param: | ||
403 | + response = CameraNIRRemoteControlDefault(param, expert_mode=True).exec_command() | ||
404 | + #os.system("echo \"status :" + response + "\" >> /home/portos/IRAP/pyros/src/status") | ||
405 | + return HttpResponse(json.dumps({'message': "Command send OK", 'response': response})) | ||
406 | + return HttpResponse(json.dumps({'message': "Missing command data"})) | ||
407 | + return redirect('submit_command_to_cameraNIR') | ||
408 | + | ||
409 | + | ||
410 | + | ||
411 | + | ||
364 | 412 | ||
365 | 413 | ||
366 | 414 |
src/devices/CameraNIR.py
@@ -5,7 +5,11 @@ from .Device import DeviceController | @@ -5,7 +5,11 @@ from .Device import DeviceController | ||
5 | ''' | 5 | ''' |
6 | Device controller for NIRCamera. | 6 | Device controller for NIRCamera. |
7 | This class must implement set, get and do functions (DeviceController is an abstract) | 7 | This class must implement set, get and do functions (DeviceController is an abstract) |
8 | + | ||
8 | ''' | 9 | ''' |
10 | + | ||
11 | +#TODO: refactoriser cette classe, la seule mรฉthode utilisรฉe est sendMessage, les autres sont obsolรจtes | ||
12 | + | ||
9 | class NIRCameraController(DeviceController): | 13 | class NIRCameraController(DeviceController): |
10 | 14 | ||
11 | def __init__(self): | 15 | def __init__(self): |
@@ -34,3 +38,7 @@ class NIRCameraController(DeviceController): | @@ -34,3 +38,7 @@ class NIRCameraController(DeviceController): | ||
34 | def open_shutter(self): | 38 | def open_shutter(self): |
35 | self.do("OPEN SHUTTER") | 39 | self.do("OPEN SHUTTER") |
36 | return 0 | 40 | return 0 |
41 | + | ||
42 | + def send_command(self, command): | ||
43 | + self.sendMessage(command) | ||
44 | + return self.blockAndReadMessage() |
@@ -0,0 +1,78 @@ | @@ -0,0 +1,78 @@ | ||
1 | +from devices.CameraRemoteControlAbstract import CameraRemoteControlAbstract | ||
2 | +from devices import CameraNIR | ||
3 | + | ||
4 | +''' | ||
5 | + Class binding method for real grammar corresponding to the generic command received in the command_matchers | ||
6 | +''' | ||
7 | + | ||
8 | +class CameraNIRRemoteControlDefault(CameraRemoteControlAbstract): | ||
9 | + def __init__(self, command, expert_mode): | ||
10 | + super().__init__(command, expert_mode) | ||
11 | + self._camera = CameraNIR.NIRCameraController() | ||
12 | + | ||
13 | + self._command_matcher_set = { | ||
14 | + "WINDOW": self.set, | ||
15 | + "READMODE [MODE 1]": self.set, | ||
16 | + "READMODE [MODE 2]": self.set, | ||
17 | + "READMODE [MODE 3]": self.set, | ||
18 | + "FILENAME": self.set, | ||
19 | + "HEADER": self.set, | ||
20 | + "READOUT_FREQUENCY": self.set, | ||
21 | + "FILTER [FILTER 1]": self.set, | ||
22 | + "FILTER [FILTER 2]": self.set, | ||
23 | + "FILTER [FILTER 3]": self.set, | ||
24 | + "NB_IMAGES": self.set, | ||
25 | + } | ||
26 | + self._command_matcher_get = { | ||
27 | + "STATUS": self.get, | ||
28 | + "SETUP": self.get, | ||
29 | + "TIMER": self.get | ||
30 | + } | ||
31 | + self._command_matcher_do = { | ||
32 | + "COOLER ON": self.do, | ||
33 | + "COOLER OFF": self.do, | ||
34 | + "DOME SHUTTER OPEN": self.do, | ||
35 | + "DOME SHUTTER CLOSE": self.do, | ||
36 | + "DOME SHUTTER SYNCHRO": self.do, | ||
37 | + "START": self.do, | ||
38 | + "ABORT": self.do, | ||
39 | + "STOP": self.do | ||
40 | + } | ||
41 | + | ||
42 | + | ||
43 | + | ||
44 | + | ||
45 | + def exec_command(self): | ||
46 | + | ||
47 | + #os.system("echo \"status :" + str(self._command) + "\" >> /home/portos/IRAP/pyros/src/commande_recu") | ||
48 | + if self._command[0] == "GET": | ||
49 | + self._current_matcher = self._command_matcher_get | ||
50 | + elif self._command[0] == "SET": | ||
51 | + self._current_matcher = self._command_matcher_set | ||
52 | + elif self._command[0] == "DO": | ||
53 | + self._current_matcher = self._command_matcher_do | ||
54 | + else: return "KO: Unknown command" | ||
55 | + if self._command[1] in self._current_matcher: | ||
56 | + return self._current_matcher[self._command[1]]() | ||
57 | + else: | ||
58 | + return "KO: Unknown command" | ||
59 | + | ||
60 | + | ||
61 | + ''' | ||
62 | + Locals methods for the generic grammar | ||
63 | + ''' | ||
64 | + | ||
65 | + def do(self): | ||
66 | + definitive_command = "DO " + self._command[1] + ' ' + ' '.join(self._command[2:]) | ||
67 | + response = self._camera.send_command(definitive_command) | ||
68 | + return response | ||
69 | + | ||
70 | + def set(self): | ||
71 | + definitive_command = "SET " + self._command[1] + ' ' + ' '.join(self._command[2:]) | ||
72 | + response = self._camera.send_command(definitive_command) | ||
73 | + return response | ||
74 | + | ||
75 | + def get(self): | ||
76 | + definitive_command = "GET " + self._command[1] #+ ' ' + ' '.join(self._command[2:]) | ||
77 | + response = self._camera.send_command(definitive_command) | ||
78 | + return response | ||
0 | \ No newline at end of file | 79 | \ No newline at end of file |
src/devices/CameraVISRemoteControlDefault.py
1 | from devices.CameraRemoteControlAbstract import CameraRemoteControlAbstract | 1 | from devices.CameraRemoteControlAbstract import CameraRemoteControlAbstract |
2 | from devices import CameraVIS | 2 | from devices import CameraVIS |
3 | 3 | ||
4 | +''' | ||
5 | + Class binding method for real grammar corresponding to the generic command received in the command_matchers | ||
6 | +''' | ||
7 | + | ||
4 | class CameraVISRemoteControlDefault(CameraRemoteControlAbstract): | 8 | class CameraVISRemoteControlDefault(CameraRemoteControlAbstract): |
5 | def __init__(self, command, expert_mode, chosen_camera): | 9 | def __init__(self, command, expert_mode, chosen_camera): |
6 | super().__init__(command, expert_mode) | 10 | super().__init__(command, expert_mode) |
@@ -19,7 +23,9 @@ class CameraVISRemoteControlDefault(CameraRemoteControlAbstract): | @@ -19,7 +23,9 @@ class CameraVISRemoteControlDefault(CameraRemoteControlAbstract): | ||
19 | "READOUT_FREQUENCY": self.set, | 23 | "READOUT_FREQUENCY": self.set, |
20 | "FILTER [FILTER 1]": self.set, | 24 | "FILTER [FILTER 1]": self.set, |
21 | "FILTER [FILTER 2]": self.set, | 25 | "FILTER [FILTER 2]": self.set, |
22 | - "FILTER [FILTER 3]": self.set | 26 | + "FILTER [FILTER 3]": self.set, |
27 | + "BINNING": self.set, | ||
28 | + "EXPOSURE": self.set | ||
23 | } | 29 | } |
24 | self._command_matcher_get = { | 30 | self._command_matcher_get = { |
25 | "STATUS": self.get, | 31 | "STATUS": self.get, |
src/devices/Device.py
@@ -104,7 +104,7 @@ class DeviceController(): | @@ -104,7 +104,7 @@ class DeviceController(): | ||
104 | readable, writable, exceptional = select.select([self.sock], [], [self.sock], 0) | 104 | readable, writable, exceptional = select.select([self.sock], [], [self.sock], 0) |
105 | if not (readable or exceptional): | 105 | if not (readable or exceptional): |
106 | #ret = self.sock.recv(size).decode() | 106 | #ret = self.sock.recv(size).decode() |
107 | - raise (Exception("KO: socket error")) | 107 | + raise (Exception("KO: socket error or not implemented command")) |
108 | 108 | ||
109 | ret = self.sock.recv(size).decode() | 109 | ret = self.sock.recv(size).decode() |
110 | if (not ret): | 110 | if (not ret): |
@@ -0,0 +1,203 @@ | @@ -0,0 +1,203 @@ | ||
1 | +var LOGS_REFRESH_FREQUENCE = 2000; //in milliseconds | ||
2 | +var expert_mode = false; | ||
3 | + | ||
4 | +jQuery(document).ready(function(){ | ||
5 | + | ||
6 | + var current_command = data; | ||
7 | + var help = null; | ||
8 | + | ||
9 | + /** | ||
10 | + These functions are event watchers on the img_display_help | ||
11 | + **/ | ||
12 | + | ||
13 | + $(document).on("mouseenter", "#img_display_help", function() { | ||
14 | + $('#img_display_help').attr('width','40px'); | ||
15 | + $('#img_display_help').attr('height','40px'); | ||
16 | + }); | ||
17 | + | ||
18 | + $(document).on("mouseleave", "#img_display_help", function() { | ||
19 | + $('#img_display_help').attr('width','30px'); | ||
20 | + $('#img_display_help').attr('height','30px'); | ||
21 | +}); | ||
22 | + | ||
23 | + | ||
24 | +$(document).on('click','#img_display_help', function() { | ||
25 | + alert(help); | ||
26 | +}); | ||
27 | + | ||
28 | + | ||
29 | +/** | ||
30 | + This function detete the childs of command_form after the child nยฐ start_position | ||
31 | +**/ | ||
32 | + | ||
33 | +function delete_childs_after(start_position) | ||
34 | +{ | ||
35 | + var form = $("#command_form"); | ||
36 | + var length = form.children().length; | ||
37 | + | ||
38 | + for (var i = start_position; i < length; i++) { | ||
39 | + form.children().last().remove(); | ||
40 | + } | ||
41 | +} | ||
42 | + | ||
43 | +/** | ||
44 | + This function create the select item with the commands in grammar.json | ||
45 | +**/ | ||
46 | +function init_first_param(corresponding_data) | ||
47 | +{ | ||
48 | + var sel = $('<select>', {name: "first_param", id:"id_first_param"}).appendTo('#command_form'); | ||
49 | + sel.append($("<option>").attr('value', "Choose Value").text("Choose Value: ")); | ||
50 | + for (var tmp in corresponding_data) | ||
51 | + { | ||
52 | + sel.append($("<option>").attr('value', corresponding_data[tmp]["name"]).text(corresponding_data[tmp]["name"])); | ||
53 | + } | ||
54 | + sel.css("font-size", "20px"); | ||
55 | +} | ||
56 | + | ||
57 | +/** | ||
58 | + This event watcher is triggered when the first_param (second submit element) is changed, it creates the inputs fields, desc, help and the submit button | ||
59 | + with the corresponding values in grammar.json with current_command previously defined | ||
60 | +**/ | ||
61 | + | ||
62 | + $(document).on('change','#id_first_param', function() { | ||
63 | + delete_childs_after(4); | ||
64 | + var form = $("#command_form"); | ||
65 | + var selected_command = $("#id_first_param").find(":selected").val(); | ||
66 | + var input = null; | ||
67 | + var label = null; | ||
68 | + for (var tmp in current_command)ย | ||
69 | + { | ||
70 | + if (current_command[tmp]["name"] === selected_command) | ||
71 | + { | ||
72 | + input = current_command[tmp]["input_label"][0]; | ||
73 | + help = current_command[tmp]["help"]; | ||
74 | + label = current_command[tmp]["label"]; | ||
75 | + } | ||
76 | + } | ||
77 | + | ||
78 | + var number = 0; | ||
79 | + for (var input_field in input) | ||
80 | + { | ||
81 | + var maxlength = input[input_field][0]; | ||
82 | + var type_input = input[input_field][1]; | ||
83 | + var desc = input[input_field][2]; | ||
84 | + var id = "input_number_" + number; | ||
85 | + var name = "input_number_" + number; | ||
86 | + var title = desc + ". value type: " + type_input; | ||
87 | + number++; | ||
88 | + input_element = $("<label>" + input_field + " </label><input title=\"" + title + "\" type=\"text\" id=\"" + id + "\" name=\"" + id + "\" maxlength=\"" + maxlength + "\" size=\"10\" text=\"" + input_field + "\"/>"); | ||
89 | + form.append(input_element); | ||
90 | + } | ||
91 | + | ||
92 | + var img_display_help = document.createElement('img'); | ||
93 | + img_display_help.src = "/public/static/media/question-mark.png"; | ||
94 | + img_display_help.width = 30; | ||
95 | + img_display_help.height = 30; | ||
96 | + img_display_help.title = "Click to display help for this command"; | ||
97 | + img_display_help.id ="img_display_help"; | ||
98 | + img_display_help.alt="html5"; | ||
99 | + | ||
100 | + form.append(img_display_help); | ||
101 | + $("#img_display_help").css("margin-left", "10px"); | ||
102 | + form.append("<br><br><p id=\"command_label\">Command description: " + label + "</p>"); | ||
103 | + //$("#command_label").css("text-align", "center"); | ||
104 | + $("#command_label").css({ | ||
105 | + 'font-size' : '15px', | ||
106 | + 'text-align' : 'center', | ||
107 | + 'font-weight' : 'bold' | ||
108 | + }); | ||
109 | + form.append("<br>") | ||
110 | + $('<input>', {id:"submit_button", type:"submit", value:"SEND"}).appendTo(form); | ||
111 | + | ||
112 | + }); | ||
113 | + | ||
114 | + | ||
115 | + /** | ||
116 | + This event watcher is triggered when the first select element is changed, it set the json current_command to SET, GET or DO, it | ||
117 | + calls init_first_param | ||
118 | + **/ | ||
119 | + $("#id_first_command").change(function() { | ||
120 | + delete_childs_after(3); | ||
121 | + var selected_command = $("#id_first_command").find(":selected").val(); | ||
122 | + if (selected_command !== "Command") | ||
123 | + { | ||
124 | + current_command = data["CameraNIR"][selected_command.toLowerCase()]; | ||
125 | + init_first_param(data["CameraNIR"][selected_command.toLowerCase()]); | ||
126 | + } | ||
127 | + }); | ||
128 | + | ||
129 | + | ||
130 | + /** | ||
131 | + This event watcher is triggered when the expert mode is activated, it generates the corresponding input field and submit_button | ||
132 | + **/ | ||
133 | + | ||
134 | +$("#expert_mode").click(function(){ | ||
135 | + if (!expert_mode) | ||
136 | + { | ||
137 | + expert_mode = true; | ||
138 | + $("#command_form_expert").append("<input id='input_command_expert' type='text' name='commande_expert'>"); | ||
139 | + $('<input>', {id:"submit_button_expert", type:"submit", value:"SEND"}).appendTo('#command_form_expert'); | ||
140 | + } | ||
141 | + else { | ||
142 | + $("#input_command_expert").remove(); | ||
143 | + $("#submit_button_expert").remove(); | ||
144 | + expert_mode = false; | ||
145 | + } | ||
146 | + //$("#command_form").remove(); | ||
147 | +}); | ||
148 | + | ||
149 | +/** | ||
150 | + This event watcher is triggered when the expert form is submitted, it's and AJAX POST request, the response is displayed in the console | ||
151 | +**/ | ||
152 | + | ||
153 | +$("#command_form_expert").submit(function(event){ | ||
154 | + | ||
155 | + event.preventDefault(); | ||
156 | + $.post('observation_status/send_command_to_cameraNIR/submit_expert', $(this).serialize(), function(data){ | ||
157 | + var obj = JSON.parse(data); | ||
158 | + console.log(obj.message); | ||
159 | + console.log(obj.response); | ||
160 | + if (obj.response === "KO: Unknown command") | ||
161 | + alert("Unknown command"); | ||
162 | + else if (obj.response.startsWith("KO")) | ||
163 | + alert(obj.response); | ||
164 | + }) | ||
165 | + .fail(function() { | ||
166 | + alert( "An error occured" ); | ||
167 | + }) | ||
168 | + }); | ||
169 | + | ||
170 | + | ||
171 | +/** | ||
172 | + This AJAX refreshed request is a get retrieving the Logs of the telescope | ||
173 | +**/ | ||
174 | + | ||
175 | + interval_camera = setInterval(function() {ajax_request();}, LOGS_REFRESH_FREQUENCE); | ||
176 | + | ||
177 | + function ajax_request(){ | ||
178 | + var camera_url ="/devices/update_cagire_logs"; | ||
179 | + $.ajax({ | ||
180 | + url: camera_url, | ||
181 | + type: 'get', | ||
182 | + dataType: 'text', | ||
183 | + success: function(data) | ||
184 | + { | ||
185 | + var obj = JSON.parse(data); | ||
186 | + if (obj) { | ||
187 | + var listDiv = document.getElementById('cagire_logs'); | ||
188 | + listDiv.innerHTML = ''; | ||
189 | + for (var tmp in obj) { | ||
190 | + var li = document.createElement('li'); | ||
191 | + li.innerHTML = obj[tmp]['fields']['created'] + ": " + obj[tmp]['fields']['message']; // Use innerHTML to set the text | ||
192 | + listDiv.appendChild(li); | ||
193 | + } | ||
194 | + } | ||
195 | + }, | ||
196 | + error: function() | ||
197 | + { | ||
198 | + console.log('Ajax error: GET request failed\n'); | ||
199 | + } | ||
200 | + | ||
201 | + }); | ||
202 | + } | ||
203 | +}); |