Line data Source code
1 : /*------------------------------------------------------------------------------
2 : -- Solar Orbiter's Low Frequency Receiver Flight Software (LFR FSW),
3 : -- This file is a part of the LFR FSW
4 : -- Copyright (C) 2012-2018, Plasma Physics Laboratory - CNRS
5 : --
6 : -- This program is free software; you can redistribute it and/or modify
7 : -- it under the terms of the GNU General Public License as published by
8 : -- the Free Software Foundation; either version 2 of the License, or
9 : -- (at your option) any later version.
10 : --
11 : -- This program is distributed in the hope that it will be useful,
12 : -- but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : -- GNU General Public License for more details.
15 : --
16 : -- You should have received a copy of the GNU General Public License
17 : -- along with this program; if not, write to the Free Software
18 : -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 : -------------------------------------------------------------------------------*/
20 : /*-- Author : Paul Leroy
21 : -- Contact : Alexis Jeandet
22 : -- Mail : alexis.jeandet@lpp.polytechnique.fr
23 : ----------------------------------------------------------------------------*/
24 :
25 : /** General usage functions and RTEMS tasks.
26 : *
27 : * @file
28 : * @author P. LEROY
29 : *
30 : */
31 :
32 : #include "fsw_misc.h"
33 : #include "fsw_compile_warnings.h"
34 : #include "fsw_debug.h"
35 : #include "fsw_globals.h"
36 : #include "fsw_housekeeping.h"
37 : #include "fsw_watchdog.h"
38 : #include "processing/iir_filter.h"
39 : #include "tc_tm/tc_handler.h"
40 : #include <stdlib.h>
41 :
42 : int16_t hk_lfr_sc_v_f3 = 0;
43 : int16_t hk_lfr_sc_e1_f3 = 0;
44 : int16_t hk_lfr_sc_e2_f3 = 0;
45 :
46 : /**
47 : * @brief load_task starts and keeps the watchdog alive.
48 : * @param argument
49 : * @return
50 : */
51 :
52 1 : LFR_NO_RETURN rtems_task load_task(rtems_task_argument argument)
53 : {
54 : IGNORE_UNUSED_PARAMETER(argument);
55 :
56 : BOOT_PRINTF("in LOAD *** \n");
57 :
58 : rtems_status_code status;
59 : unsigned int i;
60 : unsigned int j;
61 : rtems_name name_watchdog_rate_monotonic; // name of the watchdog rate monotonic
62 : rtems_id watchdog_period_id; // id of the watchdog rate monotonic period
63 :
64 1 : watchdog_period_id = RTEMS_ID_NONE;
65 :
66 1 : name_watchdog_rate_monotonic = rtems_build_name('L', 'O', 'A', 'D');
67 :
68 1 : status = rtems_rate_monotonic_create(name_watchdog_rate_monotonic, &watchdog_period_id);
69 1 : if (status != RTEMS_SUCCESSFUL)
70 : {
71 : LFR_PRINTF("in LOAD *** rtems_rate_monotonic_create failed with status of %d\n", status);
72 : }
73 :
74 1 : i = 0;
75 1 : j = 0;
76 :
77 1 : watchdog_configure();
78 :
79 1 : watchdog_start();
80 :
81 1 : set_sy_lfr_watchdog_enabled(true);
82 :
83 : while (1)
84 : {
85 288 : DEBUG_CHECK_STATUS(rtems_rate_monotonic_period(watchdog_period_id, WATCHDOG_PERIOD));
86 287 : watchdog_reload();
87 287 : i = i + 1;
88 287 : if (i == WATCHDOG_LOOP_PRINTF)
89 : {
90 28 : i = 0;
91 28 : j = j + 1;
92 : LFR_PRINTF("%d\n", j);
93 : }
94 : #ifdef DEBUG_WATCHDOG
95 : if (j == WATCHDOG_LOOP_DEBUG)
96 : {
97 : status = rtems_task_delete(RTEMS_SELF);
98 : }
99 : #endif
100 : }
101 : }
102 :
103 : /**
104 : * @brief hous_task produces and sends HK each seconds
105 : * @param argument
106 : * @return
107 : */
108 1 : LFR_NO_RETURN rtems_task hous_task(rtems_task_argument argument)
109 : {
110 : IGNORE_UNUSED_PARAMETER(argument);
111 :
112 : rtems_status_code status;
113 : rtems_id queue_id;
114 : rtems_rate_monotonic_period_status period_status;
115 : bool isSynchronized;
116 :
117 1 : queue_id = RTEMS_ID_NONE;
118 1 : memset(&period_status, 0, sizeof(rtems_rate_monotonic_period_status));
119 1 : isSynchronized = false;
120 :
121 1 : status = get_message_queue_id_send(&queue_id);
122 1 : if (status != RTEMS_SUCCESSFUL)
123 : {
124 : LFR_PRINTF("in HOUS *** ERR get_message_queue_id_send %d\n", status);
125 : }
126 :
127 : BOOT_PRINTF("in HOUS ***\n");
128 :
129 1 : if (rtems_rate_monotonic_ident(name_hk_rate_monotonic, &HK_id) != RTEMS_SUCCESSFUL)
130 : {
131 1 : status = rtems_rate_monotonic_create(name_hk_rate_monotonic, &HK_id);
132 1 : if (status != RTEMS_SUCCESSFUL)
133 : {
134 : LFR_PRINTF("rtems_rate_monotonic_create failed with status of %d\n", status);
135 : }
136 : }
137 :
138 1 : status = rtems_rate_monotonic_cancel(HK_id);
139 1 : if (status != RTEMS_SUCCESSFUL)
140 : {
141 : LFR_PRINTF("ERR *** in HOUS *** rtems_rate_monotonic_cancel(HK_id) ***code: %d\n", status);
142 : }
143 : else
144 : {
145 : DEBUG_PRINTF("OK *** in HOUS *** rtems_rate_monotonic_cancel(HK_id)\n");
146 : }
147 :
148 : // startup phase
149 1 : DEBUG_CHECK_STATUS(rtems_rate_monotonic_period(HK_id, SY_LFR_TIME_SYN_TIMEOUT_in_ticks));
150 1 : DEBUG_CHECK_STATUS(rtems_rate_monotonic_get_status(HK_id, &period_status));
151 : DEBUG_PRINTF("startup HK, HK_id status = %d\n", period_status.state);
152 44 : while ((period_status.state != RATE_MONOTONIC_EXPIRED)
153 21 : && (isSynchronized == false)) // after SY_LFR_TIME_SYN_TIMEOUT ms, starts HK anyway
154 : {
155 21 : if ((time_management_regs->coarse_time & VAL_LFR_SYNCHRONIZED)
156 : == INT32_ALL_0) // check time synchronization
157 : {
158 0 : isSynchronized = true;
159 : }
160 : else
161 : {
162 21 : DEBUG_CHECK_STATUS(rtems_rate_monotonic_get_status(HK_id, &period_status));
163 : // wait HK_SYNCH_WAIT 100 ms = 10 * 10 ms
164 21 : DEBUG_CHECK_STATUS(rtems_task_wake_after(HK_SYNC_WAIT));
165 : }
166 : }
167 1 : DEBUG_CHECK_STATUS(rtems_rate_monotonic_cancel(HK_id));
168 : DEBUG_PRINTF("startup HK, HK_id status = %d\n", period_status.state);
169 :
170 1 : set_hk_lfr_reset_cause(POWER_ON);
171 :
172 : while (1)
173 : { // launch the rate monotonic task
174 286 : status = rtems_rate_monotonic_period(HK_id, HK_PERIOD);
175 285 : if (status != RTEMS_SUCCESSFUL)
176 : {
177 : LFR_PRINTF("in HOUS *** ERR period: %d\n", status);
178 : DEBUG_CHECK_STATUS(send_event_dumb_task(RTEMS_EVENT_6));
179 : }
180 : else
181 : {
182 285 : housekeeping_packet.packetSequenceControl[BYTE_0]
183 285 : = (unsigned char)(sequenceCounterHK >> SHIFT_1_BYTE);
184 285 : housekeeping_packet.packetSequenceControl[BYTE_1] = (unsigned char)(sequenceCounterHK);
185 285 : increment_seq_counter(&sequenceCounterHK);
186 :
187 285 : housekeeping_packet.time[BYTE_0]
188 285 : = (unsigned char)(time_management_regs->coarse_time >> SHIFT_3_BYTES);
189 285 : housekeeping_packet.time[BYTE_1]
190 285 : = (unsigned char)(time_management_regs->coarse_time >> SHIFT_2_BYTES);
191 285 : housekeeping_packet.time[BYTE_2]
192 285 : = (unsigned char)(time_management_regs->coarse_time >> SHIFT_1_BYTE);
193 285 : housekeeping_packet.time[BYTE_3] = (unsigned char)(time_management_regs->coarse_time);
194 285 : housekeeping_packet.time[BYTE_4]
195 285 : = (unsigned char)(time_management_regs->fine_time >> SHIFT_1_BYTE);
196 285 : housekeeping_packet.time[BYTE_5] = (unsigned char)(time_management_regs->fine_time);
197 :
198 285 : spacewire_update_hk_lfr_link_state(&housekeeping_packet.lfr_status_word[0]);
199 :
200 285 : spacewire_read_statistics();
201 :
202 285 : update_hk_with_grspw_stats();
203 :
204 285 : set_hk_lfr_time_not_synchro();
205 :
206 285 : housekeeping_packet.hk_lfr_q_sd_fifo_size_max = hk_lfr_q_sd_fifo_size_max;
207 285 : housekeeping_packet.hk_lfr_q_rv_fifo_size_max = hk_lfr_q_rv_fifo_size_max;
208 285 : housekeeping_packet.hk_lfr_q_p0_fifo_size_max = hk_lfr_q_p0_fifo_size_max;
209 285 : housekeeping_packet.hk_lfr_q_p1_fifo_size_max = hk_lfr_q_p1_fifo_size_max;
210 285 : housekeeping_packet.hk_lfr_q_p2_fifo_size_max = hk_lfr_q_p2_fifo_size_max;
211 :
212 285 : housekeeping_packet.sy_lfr_common_parameters_spare
213 285 : = parameter_dump_packet.sy_lfr_common_parameters_spare;
214 285 : housekeeping_packet.sy_lfr_common_parameters
215 285 : = parameter_dump_packet.sy_lfr_common_parameters;
216 : encode_temperatures(&housekeeping_packet);
217 285 : encode_f3_E_field(
218 : hk_lfr_sc_v_f3, hk_lfr_sc_e1_f3, hk_lfr_sc_e2_f3, &housekeeping_packet);
219 285 : encode_cpu_load(&housekeeping_packet);
220 :
221 285 : hk_lfr_le_me_he_update();
222 :
223 : // SEND PACKET
224 285 : status = rtems_message_queue_send(queue_id, &housekeeping_packet,
225 : PACKET_LENGTH_HK + CCSDS_TC_TM_PACKET_OFFSET + CCSDS_PROTOCOLE_EXTRA_BYTES);
226 285 : if (status != RTEMS_SUCCESSFUL)
227 : {
228 : LFR_PRINTF("in HOUS *** ERR send: %d\n", status);
229 : }
230 : }
231 : }
232 :
233 : LFR_PRINTF("in HOUS *** deleting task\n");
234 :
235 : DEBUG_CHECK_STATUS(rtems_task_delete(RTEMS_SELF)); // should not return
236 : }
237 :
238 :
239 : /**
240 : * @brief avgv_task pruduces HK rate elctrical field from F3 data
241 : * @param argument
242 : * @return
243 : */
244 1 : LFR_NO_RETURN rtems_task avgv_task(rtems_task_argument argument)
245 : {
246 : IGNORE_UNUSED_PARAMETER(argument);
247 :
248 : static int old_v = 0;
249 : static int old_e1 = 0;
250 : static int old_e2 = 0;
251 1 : int32_t current_v = 0;
252 1 : int32_t current_e1 = 0;
253 1 : int32_t current_e2 = 0;
254 1 : int32_t average_v = 0;
255 1 : int32_t average_e1 = 0;
256 1 : int32_t average_e2 = 0;
257 :
258 : static filter_ctx ctx_v = { { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } };
259 : static filter_ctx ctx_e1 = { { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } };
260 : static filter_ctx ctx_e2 = { { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } };
261 :
262 : BOOT_PRINTF("in AVGV ***\n");
263 :
264 1 : if (rtems_rate_monotonic_ident(name_avgv_rate_monotonic, &AVGV_id) != RTEMS_SUCCESSFUL)
265 : {
266 1 : DEBUG_CHECK_STATUS(rtems_rate_monotonic_create(name_avgv_rate_monotonic, &AVGV_id));
267 : }
268 :
269 1 : DEBUG_CHECK_STATUS(rtems_rate_monotonic_cancel(AVGV_id));
270 :
271 : while (1)
272 : {
273 : // launch the rate monotonic task
274 4770 : DEBUG_CHECK_STATUS(rtems_rate_monotonic_period(AVGV_id, AVGV_PERIOD));
275 4769 : current_v = waveform_picker_regs->v;
276 4769 : current_e1 = waveform_picker_regs->e1;
277 4769 : current_e2 = waveform_picker_regs->e2;
278 : // this tests is weak but the only way to detect a new sample
279 : // it assumes that there is enough noise to flip at least one bit on v, E1 or E2
280 4769 : if ((current_v != old_v) || (current_e1 != old_e1) || (current_e2 != old_e2))
281 : {
282 4054 : average_v = filter(current_v, &ctx_v);
283 4054 : average_e1 = filter(current_e1, &ctx_e1);
284 4054 : average_e2 = filter(current_e2, &ctx_e2);
285 :
286 : // update int16 values
287 4054 : hk_lfr_sc_v_f3 = (int16_t)average_v;
288 4054 : hk_lfr_sc_e1_f3 = (int16_t)average_e1;
289 4054 : hk_lfr_sc_e2_f3 = (int16_t)average_e2;
290 : }
291 4769 : old_v = current_v;
292 4769 : old_e1 = current_e1;
293 4769 : old_e2 = current_e2;
294 4769 : }
295 :
296 : LFR_PRINTF("in AVGV *** deleting task\n");
297 :
298 : DEBUG_CHECK_STATUS(rtems_task_delete(RTEMS_SELF)); // should not return
299 : }
300 :
301 1 : LFR_NO_RETURN rtems_task dumb_task(rtems_task_argument unused)
302 : {
303 : /** This RTEMS taks is used to print messages without affecting the general behaviour of the
304 : * software.
305 : *
306 : * @param unused is the starting argument of the RTEMS task
307 : *
308 : * The DUMB taks waits for RTEMS events and print messages depending on the incoming events.
309 : *
310 : */
311 :
312 : IGNORE_UNUSED_PARAMETER(unused);
313 :
314 1 : unsigned int intEventOut = EVENT_SETS_NONE_PENDING;
315 : rtems_event_set event_out;
316 :
317 : BOOT_PRINTF("in DUMB *** \n");
318 :
319 : while (1)
320 : {
321 107 : rtems_event_receive(RTEMS_EVENT_0 | RTEMS_EVENT_1 | RTEMS_EVENT_2 | RTEMS_EVENT_3
322 : | RTEMS_EVENT_4 | RTEMS_EVENT_5 | RTEMS_EVENT_6 | RTEMS_EVENT_7 | RTEMS_EVENT_8
323 : | RTEMS_EVENT_9 | RTEMS_EVENT_12 | RTEMS_EVENT_13 | RTEMS_EVENT_14,
324 : RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &event_out); // wait for an RTEMS_EVENT
325 106 : intEventOut = (unsigned int)event_out;
326 3498 : for (unsigned int i = 0; i < NB_RTEMS_EVENTS; i++)
327 : {
328 3392 : if (((intEventOut >> i) & 1) != 0)
329 : {
330 106 : switch (i)
331 : {
332 : case EVENT_12:
333 : LFR_PRINTF("%s\n", DUMB_MESSAGE_12);
334 0 : break;
335 : case EVENT_13:
336 : LFR_PRINTF("%s\n", DUMB_MESSAGE_13);
337 106 : break;
338 : case EVENT_14:
339 : LFR_PRINTF("%s\n", DUMB_MESSAGE_1);
340 : break;
341 : default:
342 : break;
343 : }
344 : }
345 : }
346 : }
347 : }
348 :
349 0 : LFR_NO_RETURN rtems_task scrubbing_task(rtems_task_argument unused)
350 : {
351 : /** This RTEMS taks is used to avoid entering IDLE task and also scrub memory to increase
352 : * scubbing frequency.
353 : *
354 : * @param unused is the starting argument of the RTEMS task
355 : *
356 : * The scrubbing reads continuously memory when no other tasks are ready.
357 : *
358 : */
359 : IGNORE_UNUSED_PARAMETER(unused);
360 :
361 : BOOT_PRINTF("in SCRUBBING *** \n");
362 0 : volatile int i = 0;
363 0 : volatile float valuef = 1.;
364 0 : const volatile uint32_t* const RAM = (uint32_t*)0x40000000;
365 :
366 : #ifdef ENABLE_SCRUBBING_COUNTER
367 : housekeeping_packet.lfr_fpga_version[BYTE_0] = 0;
368 : #endif
369 : while (1)
370 : {
371 0 : i = (i + 1) % (1024 * 1024);
372 0 : valuef += 10.f * (float)RAM[i];
373 : #ifdef ENABLE_SCRUBBING_COUNTER
374 : if (i == 0)
375 : {
376 : housekeeping_packet.lfr_fpga_version[BYTE_0] += 1;
377 : }
378 : #endif
379 0 : }
380 : }
381 :
382 1 : LFR_NO_RETURN rtems_task calibration_sweep_task(rtems_task_argument unused)
383 : {
384 : /** This RTEMS taks is used to change calibration signal smapling frequency between snapshots.
385 : *
386 : * @param unused is the starting argument of the RTEMS task
387 : *
388 : * If calibration is enabled, this task will divide by two the calibration signal smapling
389 : * frequency between snapshots. When minimum sampling frequency is reach it will jump to maximum
390 : * sampling frequency to loop indefinitely.
391 : *
392 : */
393 :
394 : IGNORE_UNUSED_PARAMETER(unused);
395 :
396 : rtems_event_set event_out;
397 : BOOT_PRINTF("in calibration sweep *** \n");
398 1 : rtems_interval ticks_per_seconds = rtems_clock_get_ticks_per_second();
399 : while (1)
400 : {
401 : // Waiting for next F0 snapshot
402 1 : rtems_event_receive(RTEMS_EVENT_CAL_SWEEP_WAKE, RTEMS_WAIT, RTEMS_NO_TIMEOUT, &event_out);
403 0 : if (time_management_regs->calDACCtrl & BIT_CAL_ENABLE)
404 : {
405 : unsigned int delta_snapshot;
406 0 : delta_snapshot = (parameter_dump_packet.sy_lfr_n_swf_p[0] * CONST_256)
407 0 : + parameter_dump_packet.sy_lfr_n_swf_p[1];
408 : // We are woken almost in the center of a snapshot -> let's wait for sy_lfr_n_swf_p / 2
409 0 : rtems_task_wake_after(ticks_per_seconds * delta_snapshot / 2);
410 0 : if (time_management_regs->calDivisor >= CAL_F_DIVISOR_MAX)
411 : {
412 0 : time_management_regs->calDivisor = CAL_F_DIVISOR_MIN;
413 : }
414 : else
415 : {
416 0 : time_management_regs->calDivisor *= 2;
417 : }
418 : }
419 : }
420 : }
421 :
422 :
423 : //*****************************
424 : // init housekeeping parameters
|