GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/fsw_misc.c Lines: 335 402 83.3 %
Date: 2018-10-22 12:27:55 Branches: 33 55 60.0 %

Line Branch Exec Source
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
34
int16_t hk_lfr_sc_v_f3_as_int16 = 0;
35
int16_t hk_lfr_sc_e1_f3_as_int16 = 0;
36
int16_t hk_lfr_sc_e2_f3_as_int16 = 0;
37
38
1
void timer_configure(unsigned char timer, unsigned int clock_divider,
39
                    unsigned char interrupt_level, rtems_isr (*timer_isr)() )
40
{
41
    /** This function configures a GPTIMER timer instantiated in the VHDL design.
42
     *
43
     * @param gptimer_regs points to the APB registers of the GPTIMER IP core.
44
     * @param timer is the number of the timer in the IP core (several timers can be instantiated).
45
     * @param clock_divider is the divider of the 1 MHz clock that will be configured.
46
     * @param interrupt_level is the interrupt level that the timer drives.
47
     * @param timer_isr is the interrupt subroutine that will be attached to the IRQ driven by the timer.
48
     *
49
     * Interrupt levels are described in the SPARC documentation sparcv8.pdf p.76
50
     *
51
     */
52
53
    rtems_status_code status;
54
    rtems_isr_entry old_isr_handler;
55
56
1
    old_isr_handler = NULL;
57
58
1
    gptimer_regs->timer[timer].ctrl = INIT_CHAR;  // reset the control register
59
60
1
    status = rtems_interrupt_catch( timer_isr, interrupt_level, &old_isr_handler) ; // see sparcv8.pdf p.76 for interrupt levels
61
    if (status!=RTEMS_SUCCESSFUL)
62
    {
63
        PRINTF("in configure_timer *** ERR rtems_interrupt_catch\n")
64
    }
65
66
1
    timer_set_clock_divider( timer, clock_divider);
67
1
}
68
69
void timer_start(unsigned char timer)
70
{
71
    /** This function starts a GPTIMER timer.
72
     *
73
     * @param gptimer_regs points to the APB registers of the GPTIMER IP core.
74
     * @param timer is the number of the timer in the IP core (several timers can be instantiated).
75
     *
76
     */
77
78
    gptimer_regs->timer[timer].ctrl = gptimer_regs->timer[timer].ctrl | GPTIMER_CLEAR_IRQ;
79
    gptimer_regs->timer[timer].ctrl = gptimer_regs->timer[timer].ctrl | GPTIMER_LD;
80
    gptimer_regs->timer[timer].ctrl = gptimer_regs->timer[timer].ctrl | GPTIMER_EN;
81
    gptimer_regs->timer[timer].ctrl = gptimer_regs->timer[timer].ctrl | GPTIMER_RS;
82
    gptimer_regs->timer[timer].ctrl = gptimer_regs->timer[timer].ctrl | GPTIMER_IE;
83
}
84
85
void timer_stop(unsigned char timer)
86
{
87
    /** This function stops a GPTIMER timer.
88
     *
89
     * @param gptimer_regs points to the APB registers of the GPTIMER IP core.
90
     * @param timer is the number of the timer in the IP core (several timers can be instantiated).
91
     *
92
     */
93
94
    gptimer_regs->timer[timer].ctrl = gptimer_regs->timer[timer].ctrl & GPTIMER_EN_MASK;
95
    gptimer_regs->timer[timer].ctrl = gptimer_regs->timer[timer].ctrl & GPTIMER_IE_MASK;
96
    gptimer_regs->timer[timer].ctrl = gptimer_regs->timer[timer].ctrl | GPTIMER_CLEAR_IRQ;
97
}
98
99
1
void timer_set_clock_divider(unsigned char timer, unsigned int clock_divider)
100
{
101
    /** This function sets the clock divider of a GPTIMER timer.
102
     *
103
     * @param gptimer_regs points to the APB registers of the GPTIMER IP core.
104
     * @param timer is the number of the timer in the IP core (several timers can be instantiated).
105
     * @param clock_divider is the divider of the 1 MHz clock that will be configured.
106
     *
107
     */
108
109
1
    gptimer_regs->timer[timer].reload = clock_divider; // base clock frequency is 1 MHz
110
1
}
111
112
// WATCHDOG, this ISR should never be triggered.
113
114
rtems_isr watchdog_isr( rtems_vector_number vector )
115
{
116
    rtems_status_code status_code;
117
118
    status_code = rtems_event_send( Task_id[TASKID_DUMB], RTEMS_EVENT_12 );
119
120
    PRINTF("watchdog_isr *** this is the end, exit(0)\n");
121
122
    exit(0);
123
}
124
125
1
void watchdog_configure(void)
126
{
127
    /** This function configure the watchdog.
128
     *
129
     * @param gptimer_regs points to the APB registers of the GPTIMER IP core.
130
     * @param timer is the number of the timer in the IP core (several timers can be instantiated).
131
     *
132
     * The watchdog is a timer provided by the GPTIMER IP core of the GRLIB.
133
     *
134
     */
135
136
1
    LEON_Mask_interrupt( IRQ_GPTIMER_WATCHDOG );    // mask gptimer/watchdog interrupt during configuration
137
138
1
    timer_configure( TIMER_WATCHDOG, CLKDIV_WATCHDOG, IRQ_SPARC_GPTIMER_WATCHDOG, watchdog_isr );
139
140
1
    LEON_Clear_interrupt( IRQ_GPTIMER_WATCHDOG );   // clear gptimer/watchdog interrupt
141
1
}
142
143
void watchdog_stop(void)
144
{
145
    LEON_Mask_interrupt( IRQ_GPTIMER_WATCHDOG );                  // mask gptimer/watchdog interrupt line
146
    timer_stop( TIMER_WATCHDOG );
147
    LEON_Clear_interrupt( IRQ_GPTIMER_WATCHDOG );                 // clear gptimer/watchdog interrupt
148
}
149
150
45
void watchdog_reload(void)
151
{
152
    /** This function reloads the watchdog timer counter with the timer reload value.
153
     *
154
     * @param void
155
     *
156
     * @return void
157
     *
158
     */
159
160
45
    gptimer_regs->timer[TIMER_WATCHDOG].ctrl = gptimer_regs->timer[TIMER_WATCHDOG].ctrl | GPTIMER_LD;
161
45
}
162
163
1
void watchdog_start(void)
164
{
165
    /** This function starts the watchdog timer.
166
     *
167
     * @param gptimer_regs points to the APB registers of the GPTIMER IP core.
168
     * @param timer is the number of the timer in the IP core (several timers can be instantiated).
169
     *
170
     */
171
172
1
    LEON_Clear_interrupt( IRQ_GPTIMER_WATCHDOG );
173
174
1
    gptimer_regs->timer[TIMER_WATCHDOG].ctrl = gptimer_regs->timer[TIMER_WATCHDOG].ctrl | GPTIMER_CLEAR_IRQ;
175
1
    gptimer_regs->timer[TIMER_WATCHDOG].ctrl = gptimer_regs->timer[TIMER_WATCHDOG].ctrl | GPTIMER_LD;
176
1
    gptimer_regs->timer[TIMER_WATCHDOG].ctrl = gptimer_regs->timer[TIMER_WATCHDOG].ctrl | GPTIMER_EN;
177
1
    gptimer_regs->timer[TIMER_WATCHDOG].ctrl = gptimer_regs->timer[TIMER_WATCHDOG].ctrl | GPTIMER_IE;
178
179
1
    LEON_Unmask_interrupt( IRQ_GPTIMER_WATCHDOG );
180
181
1
}
182
183
1
int enable_apbuart_transmitter( void )  // set the bit 1, TE Transmitter Enable to 1 in the APBUART control register
184
{
185
1
    struct apbuart_regs_str *apbuart_regs = (struct apbuart_regs_str *) REGS_ADDR_APBUART;
186
187
1
    apbuart_regs->ctrl = APBUART_CTRL_REG_MASK_TE;
188
189
1
    return 0;
190
}
191
192
1
void set_apbuart_scaler_reload_register(unsigned int regs, unsigned int value)
193
{
194
    /** This function sets the scaler reload register of the apbuart module
195
     *
196
     * @param regs is the address of the apbuart registers in memory
197
     * @param value is the value that will be stored in the scaler register
198
     *
199
     * The value shall be set by the software to get data on the serial interface.
200
     *
201
     */
202
203
1
    struct apbuart_regs_str *apbuart_regs = (struct apbuart_regs_str *) regs;
204
205
1
    apbuart_regs->scaler = value;
206
207
    BOOT_PRINTF1("OK  *** apbuart port scaler reload register set to 0x%x\n", value)
208
1
}
209
210
/**
211
 * @brief load_task starts and keeps the watchdog alive.
212
 * @param argument
213
 * @return
214
 */
215
216
1
rtems_task load_task(rtems_task_argument argument)
217
{
218
    BOOT_PRINTF("in LOAD *** \n")
219
220
    rtems_status_code status;
221
    unsigned int i;
222
    unsigned int j;
223
    rtems_name name_watchdog_rate_monotonic;  // name of the watchdog rate monotonic
224
    rtems_id watchdog_period_id;              // id of the watchdog rate monotonic period
225
226
1
    watchdog_period_id = RTEMS_ID_NONE;
227
228
1
    name_watchdog_rate_monotonic = rtems_build_name( 'L', 'O', 'A', 'D' );
229
230
1
    status = rtems_rate_monotonic_create( name_watchdog_rate_monotonic, &watchdog_period_id );
231
    if( status != RTEMS_SUCCESSFUL ) {
232
        PRINTF1( "in LOAD *** rtems_rate_monotonic_create failed with status of %d\n", status )
233
    }
234
235
1
    i = 0;
236
1
    j = 0;
237
238
1
    watchdog_configure();
239
240
1
    watchdog_start();
241
242
1
    set_sy_lfr_watchdog_enabled( true );
243
244
    while(1){
245
46
        status = rtems_rate_monotonic_period( watchdog_period_id, WATCHDOG_PERIOD );
246
45
        watchdog_reload();
247
45
        i = i + 1;
248
45
        if ( i == WATCHDOG_LOOP_PRINTF )
249
        {
250
4
            i = 0;
251
4
            j = j + 1;
252
            PRINTF1("%d\n", j)
253
        }
254
#ifdef DEBUG_WATCHDOG
255
        if (j == WATCHDOG_LOOP_DEBUG )
256
        {
257
            status = rtems_task_delete(RTEMS_SELF);
258
        }
259
#endif
260
    }
261
}
262
263
/**
264
 * @brief hous_task produces and sends HK each seconds
265
 * @param argument
266
 * @return
267
 */
268
1
rtems_task hous_task(rtems_task_argument argument)
269
{
270
    rtems_status_code status;
271
    rtems_status_code spare_status;
272
    rtems_id queue_id;
273
    rtems_rate_monotonic_period_status period_status;
274
    bool isSynchronized;
275
276
1
    queue_id = RTEMS_ID_NONE;
277
1
    memset(&period_status, 0, sizeof(rtems_rate_monotonic_period_status));
278
1
    isSynchronized = false;
279
280
1
    status =  get_message_queue_id_send( &queue_id );
281
    if (status != RTEMS_SUCCESSFUL)
282
    {
283
        PRINTF1("in HOUS *** ERR get_message_queue_id_send %d\n", status)
284
    }
285
286
    BOOT_PRINTF("in HOUS ***\n");
287
288
1
    if (rtems_rate_monotonic_ident( name_hk_rate_monotonic, &HK_id) != RTEMS_SUCCESSFUL) {
289
1
        status = rtems_rate_monotonic_create( name_hk_rate_monotonic, &HK_id );
290
        if( status != RTEMS_SUCCESSFUL ) {
291
            PRINTF1( "rtems_rate_monotonic_create failed with status of %d\n", status );
292
        }
293
    }
294
295
1
    status = rtems_rate_monotonic_cancel(HK_id);
296
    if( status != RTEMS_SUCCESSFUL ) {
297
        PRINTF1( "ERR *** in HOUS *** rtems_rate_monotonic_cancel(HK_id) ***code: %d\n", status );
298
    }
299
    else {
300
        DEBUG_PRINTF("OK  *** in HOUS *** rtems_rate_monotonic_cancel(HK_id)\n");
301
    }
302
303
    // startup phase
304
1
    status = rtems_rate_monotonic_period( HK_id, SY_LFR_TIME_SYN_TIMEOUT_in_ticks );
305
1
    status = rtems_rate_monotonic_get_status( HK_id, &period_status );
306
    DEBUG_PRINTF1("startup HK, HK_id status = %d\n", period_status.state)
307

44
    while( (period_status.state != RATE_MONOTONIC_EXPIRED)
308
21
           && (isSynchronized == false) )   // after SY_LFR_TIME_SYN_TIMEOUT ms, starts HK anyway
309
    {
310
21
        if ((time_management_regs->coarse_time & VAL_LFR_SYNCHRONIZED) == INT32_ALL_0) // check time synchronization
311
        {
312
            isSynchronized = true;
313
        }
314
        else
315
        {
316
21
            status = rtems_rate_monotonic_get_status( HK_id, &period_status );
317
318
21
            status = rtems_task_wake_after( HK_SYNC_WAIT );        // wait HK_SYNCH_WAIT 100 ms = 10 * 10 ms
319
        }
320
    }
321
1
    status = rtems_rate_monotonic_cancel(HK_id);
322
    DEBUG_PRINTF1("startup HK, HK_id status = %d\n", period_status.state)
323
324
1
    set_hk_lfr_reset_cause( POWER_ON );
325
326
    while(1){ // launch the rate monotonic task
327
44
        status = rtems_rate_monotonic_period( HK_id, HK_PERIOD );
328
43
        if ( status != RTEMS_SUCCESSFUL ) {
329
            PRINTF1( "in HOUS *** ERR period: %d\n", status);
330
            spare_status = rtems_event_send( Task_id[TASKID_DUMB], RTEMS_EVENT_6 );
331
        }
332
        else {
333
43
            housekeeping_packet.packetSequenceControl[BYTE_0] = (unsigned char) (sequenceCounterHK >> SHIFT_1_BYTE);
334
43
            housekeeping_packet.packetSequenceControl[BYTE_1] = (unsigned char) (sequenceCounterHK     );
335
43
            increment_seq_counter( &sequenceCounterHK );
336
337
43
            housekeeping_packet.time[BYTE_0] = (unsigned char) (time_management_regs->coarse_time >> SHIFT_3_BYTES);
338
43
            housekeeping_packet.time[BYTE_1] = (unsigned char) (time_management_regs->coarse_time >> SHIFT_2_BYTES);
339
43
            housekeeping_packet.time[BYTE_2] = (unsigned char) (time_management_regs->coarse_time >> SHIFT_1_BYTE);
340
43
            housekeeping_packet.time[BYTE_3] = (unsigned char) (time_management_regs->coarse_time);
341
43
            housekeeping_packet.time[BYTE_4] = (unsigned char) (time_management_regs->fine_time >> SHIFT_1_BYTE);
342
43
            housekeeping_packet.time[BYTE_5] = (unsigned char) (time_management_regs->fine_time);
343
344
43
            spacewire_update_hk_lfr_link_state( &housekeeping_packet.lfr_status_word[0] );
345
346
43
            spacewire_read_statistics();
347
348
43
            update_hk_with_grspw_stats();
349
350
43
            set_hk_lfr_time_not_synchro();
351
352
43
            housekeeping_packet.hk_lfr_q_sd_fifo_size_max = hk_lfr_q_sd_fifo_size_max;
353
43
            housekeeping_packet.hk_lfr_q_rv_fifo_size_max = hk_lfr_q_rv_fifo_size_max;
354
43
            housekeeping_packet.hk_lfr_q_p0_fifo_size_max = hk_lfr_q_p0_fifo_size_max;
355
43
            housekeeping_packet.hk_lfr_q_p1_fifo_size_max = hk_lfr_q_p1_fifo_size_max;
356
43
            housekeeping_packet.hk_lfr_q_p2_fifo_size_max = hk_lfr_q_p2_fifo_size_max;
357
358
43
            housekeeping_packet.sy_lfr_common_parameters_spare  = parameter_dump_packet.sy_lfr_common_parameters_spare;
359
43
            housekeeping_packet.sy_lfr_common_parameters        = parameter_dump_packet.sy_lfr_common_parameters;
360
43
            get_temperatures( housekeeping_packet.hk_lfr_temp_scm );
361
43
            get_v_e1_e2_f3(   housekeeping_packet.hk_lfr_sc_v_f3  );
362
43
            get_cpu_load( (unsigned char *) &housekeeping_packet.hk_lfr_cpu_load );
363
364
43
            hk_lfr_le_me_he_update();
365
366
            // SEND PACKET
367
43
            status =  rtems_message_queue_send( queue_id, &housekeeping_packet,
368
                                                PACKET_LENGTH_HK + CCSDS_TC_TM_PACKET_OFFSET + CCSDS_PROTOCOLE_EXTRA_BYTES);
369
            if (status != RTEMS_SUCCESSFUL) {
370
                PRINTF1("in HOUS *** ERR send: %d\n", status)
371
            }
372
        }
373
    }
374
375
    PRINTF("in HOUS *** deleting task\n")
376
377
    status = rtems_task_delete( RTEMS_SELF ); // should not return
378
379
    return;
380
}
381
382
/**
383
 * @brief filter is a Direct-Form-II filter implementation, mostly used to filter electric field for HK
384
 * @param x, new sample
385
 * @param ctx, filter context, used to store previous input and output samples
386
 * @return a new filtered sample
387
 */
388
2088
int filter( int x, filter_ctx* ctx )
389
{
390
    static const int b[NB_COEFFS][NB_COEFFS]={ {B00, B01, B02}, {B10, B11, B12}, {B20, B21, B22} };
391
    static const int a[NB_COEFFS][NB_COEFFS]={ {A00, A01, A02}, {A10, A11, A12}, {A20, A21, A22} };
392
    static const int b_gain[NB_COEFFS]={GAIN_B0, GAIN_B1, GAIN_B2};
393
    static const int a_gain[NB_COEFFS]={GAIN_A0, GAIN_A1, GAIN_A2};
394
395
    int_fast32_t W;
396
    int i;
397
398
2088
    W = INIT_INT;
399
2088
    i = INIT_INT;
400
401
    //Direct-Form-II
402
8352
    for ( i = 0; i < NB_COEFFS; i++ )
403
    {
404
6264
        x = x << a_gain[i];
405
18792
        W = (x - ( a[i][COEFF1] * ctx->W[i][COEFF0] )
406
12528
               - ( a[i][COEFF2] * ctx->W[i][COEFF1] ) ) >> a_gain[i];
407
12528
        x = ( b[i][COEFF0] * W )
408
6264
                + ( b[i][COEFF1] * ctx->W[i][COEFF0] )
409
12528
                + ( b[i][COEFF2] * ctx->W[i][COEFF1] );
410
6264
        x = x >> b_gain[i];
411
6264
        ctx->W[i][1] = ctx->W[i][0];
412
6264
        ctx->W[i][0] = W;
413
    }
414
2088
    return x;
415
}
416
417
/**
418
 * @brief avgv_task pruduces HK rate elctrical field from F3 data
419
 * @param argument
420
 * @return
421
 */
422
1
rtems_task avgv_task(rtems_task_argument argument)
423
{
424
#define MOVING_AVERAGE 16
425
    rtems_status_code status;
426
    static int32_t v[MOVING_AVERAGE] = {0};
427
    static int32_t e1[MOVING_AVERAGE] = {0};
428
    static int32_t e2[MOVING_AVERAGE] = {0};
429
    static int old_v = 0;
430
    static int old_e1 = 0;
431
    static int old_e2 = 0;
432
    int32_t current_v;
433
    int32_t current_e1;
434
    int32_t current_e2;
435
    int32_t average_v;
436
    int32_t average_e1;
437
    int32_t average_e2;
438
    int32_t newValue_v;
439
    int32_t newValue_e1;
440
    int32_t newValue_e2;
441
    unsigned char k;
442
    unsigned char indexOfOldValue;
443
444
    static filter_ctx ctx_v = { { {0,0,0}, {0,0,0}, {0,0,0} } };
445
    static filter_ctx ctx_e1 = { { {0,0,0}, {0,0,0}, {0,0,0} } };
446
    static filter_ctx ctx_e2 = { { {0,0,0}, {0,0,0}, {0,0,0} } };
447
448
    BOOT_PRINTF("in AVGV ***\n");
449
450
1
    if (rtems_rate_monotonic_ident( name_avgv_rate_monotonic, &AVGV_id) != RTEMS_SUCCESSFUL) {
451
1
        status = rtems_rate_monotonic_create( name_avgv_rate_monotonic, &AVGV_id );
452
        if( status != RTEMS_SUCCESSFUL ) {
453
            PRINTF1( "rtems_rate_monotonic_create failed with status of %d\n", status );
454
        }
455
    }
456
457
1
    status = rtems_rate_monotonic_cancel(AVGV_id);
458
    if( status != RTEMS_SUCCESSFUL ) {
459
        PRINTF1( "ERR *** in AVGV *** rtems_rate_monotonic_cancel(AVGV_id) ***code: %d\n", status );
460
    }
461
    else {
462
        DEBUG_PRINTF("OK  *** in AVGV *** rtems_rate_monotonic_cancel(AVGV_id)\n");
463
    }
464
465
    // initialize values
466
1
    indexOfOldValue = MOVING_AVERAGE - 1;
467
1
    current_v = 0;
468
1
    current_e1 = 0;
469
1
    current_e2 = 0;
470
1
    average_v   = 0;
471
1
    average_e1  = 0;
472
1
    average_e2  = 0;
473
1
    newValue_v  = 0;
474
1
    newValue_e1 = 0;
475
1
    newValue_e2 = 0;
476
477
1
    k = INIT_CHAR;
478
479
    while(1)
480
    { // launch the rate monotonic task
481
751
        status = rtems_rate_monotonic_period( AVGV_id, AVGV_PERIOD );
482
750
        if ( status != RTEMS_SUCCESSFUL )
483
        {
484
            PRINTF1( "in AVGV *** ERR period: %d\n", status);
485
        }
486
        else
487
        {
488
750
            current_v = waveform_picker_regs->v;
489
750
            current_e1 = waveform_picker_regs->e1;
490
750
            current_e2 = waveform_picker_regs->e2;
491

985
            if ( (current_v != old_v)
492
154
                 || (current_e1 != old_e1)
493
81
                 || (current_e2 != old_e2))
494
            {
495
696
                average_v = filter( current_v, &ctx_v );
496
696
                average_e1 = filter( current_e1, &ctx_e1 );
497
696
                average_e2 = filter( current_e2, &ctx_e2 );
498
499
                //update int16 values
500
696
                hk_lfr_sc_v_f3_as_int16 =  (int16_t) average_v;
501
696
                hk_lfr_sc_e1_f3_as_int16 = (int16_t) average_e1;
502
696
                hk_lfr_sc_e2_f3_as_int16 = (int16_t) average_e2;
503
            }
504
750
            old_v = current_v;
505
750
            old_e1 = current_e1;
506
750
            old_e2 = current_e2;
507
        }
508
    }
509
510
    PRINTF("in AVGV *** deleting task\n");
511
512
    status = rtems_task_delete( RTEMS_SELF ); // should not return
513
514
    return;
515
}
516
517
1
rtems_task dumb_task( rtems_task_argument unused )
518
{
519
    /** This RTEMS taks is used to print messages without affecting the general behaviour of the software.
520
     *
521
     * @param unused is the starting argument of the RTEMS task
522
     *
523
     * The DUMB taks waits for RTEMS events and print messages depending on the incoming events.
524
     *
525
     */
526
527
    unsigned int i;
528
    unsigned int intEventOut;
529
1
    unsigned int coarse_time = 0;
530
1
    unsigned int fine_time = 0;
531
    rtems_event_set event_out;
532
533
1
    event_out = EVENT_SETS_NONE_PENDING;
534
535
    BOOT_PRINTF("in DUMB *** \n")
536
537
    while(1){
538
2
        rtems_event_receive(RTEMS_EVENT_0 | RTEMS_EVENT_1 | RTEMS_EVENT_2 | RTEMS_EVENT_3
539
                            | RTEMS_EVENT_4 | RTEMS_EVENT_5 | RTEMS_EVENT_6 | RTEMS_EVENT_7
540
                            | RTEMS_EVENT_8 | RTEMS_EVENT_9 | RTEMS_EVENT_12 | RTEMS_EVENT_13
541
                            | RTEMS_EVENT_14,
542
                            RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &event_out); // wait for an RTEMS_EVENT
543
1
        intEventOut =  (unsigned int) event_out;
544
33
        for ( i=0; i<NB_RTEMS_EVENTS; i++)
545
        {
546
32
            if ( ((intEventOut >> i) & 1) != 0)
547
            {
548
1
                coarse_time = time_management_regs->coarse_time;
549
1
                fine_time = time_management_regs->fine_time;
550
                if (i==EVENT_12)
551
                {
552
                    PRINTF1("%s\n", DUMB_MESSAGE_12)
553
                }
554
                if (i==EVENT_13)
555
                {
556
                    PRINTF1("%s\n", DUMB_MESSAGE_13)
557
                }
558
                if (i==EVENT_14)
559
                {
560
                    PRINTF1("%s\n", DUMB_MESSAGE_1)
561
                }
562
            }
563
        }
564
    }
565
}
566
567
rtems_task scrubbing_task( rtems_task_argument unused )
568
{
569
    /** This RTEMS taks is used to avoid entering IDLE task and also scrub memory to increase scubbing frequency.
570
     *
571
     * @param unused is the starting argument of the RTEMS task
572
     *
573
     * The scrubbing reads continuously memory when no other tasks are ready.
574
     *
575
     */
576
577
    BOOT_PRINTF("in SCRUBBING *** \n");
578
    volatile int i=0;
579
    volatile float valuef = 1.;
580
    volatile uint32_t* RAM=(uint32_t*)0x40000000;
581
    volatile uint32_t value;
582
#ifdef ENABLE_SCRUBBING_COUNTER
583
    housekeeping_packet.lfr_fpga_version[BYTE_0] = 0;
584
#endif
585
    while(1){
586
        i=(i+1)%(1024*1024);
587
        valuef += 10.f*(float)RAM[i];
588
#ifdef ENABLE_SCRUBBING_COUNTER
589
        if(i==0)
590
        {
591
            housekeeping_packet.lfr_fpga_version[BYTE_0] += 1;
592
        }
593
#endif
594
    }
595
}
596
597
1
rtems_task calibration_sweep_task( rtems_task_argument unused )
598
{
599
    /** This RTEMS taks is used to change calibration signal smapling frequency between snapshots.
600
     *
601
     * @param unused is the starting argument of the RTEMS task
602
     *
603
     * If calibration is enabled, this task will divide by two the calibration signal smapling frequency between snapshots.
604
     * When minimum sampling frequency is reach it will jump to maximum sampling frequency to loop indefinitely.
605
     *
606
     */
607
    rtems_event_set event_out;
608
    BOOT_PRINTF("in calibration sweep *** \n");
609
1
    rtems_interval ticks_per_seconds = rtems_clock_get_ticks_per_second();
610
    while(1){
611
        // Waiting for next F0 snapshot
612
1
        rtems_event_receive(RTEMS_EVENT_CAL_SWEEP_WAKE, RTEMS_WAIT, RTEMS_NO_TIMEOUT, &event_out);
613
        if(time_management_regs->calDACCtrl & BIT_CAL_ENABLE)
614
        {
615
            unsigned int delta_snapshot;
616
            delta_snapshot = (parameter_dump_packet.sy_lfr_n_swf_p[0] * CONST_256)
617
                    + parameter_dump_packet.sy_lfr_n_swf_p[1];
618
            // We are woken almost in the center of a snapshot -> let's wait for sy_lfr_n_swf_p / 2
619
            rtems_task_wake_after( ticks_per_seconds * delta_snapshot / 2);
620
            if(time_management_regs->calDivisor >= CAL_F_DIVISOR_MAX){
621
                time_management_regs->calDivisor = CAL_F_DIVISOR_MIN;
622
            }
623
            else{
624
                time_management_regs->calDivisor *= 2;
625
            }
626
        }
627
628
629
630
    }
631
632
}
633
634
635
//*****************************
636
// init housekeeping parameters
637
638
1
void init_housekeeping_parameters( void )
639
{
640
    /** This function initialize the housekeeping_packet global variable with default values.
641
     *
642
     */
643
644
1
    unsigned int i = 0;
645
    unsigned char *parameters;
646
    unsigned char sizeOfHK;
647
648
1
    sizeOfHK = sizeof( Packet_TM_LFR_HK_t );
649
650
1
    parameters = (unsigned char*) &housekeeping_packet;
651
652
141
    for(i = 0; i< sizeOfHK; i++)
653
    {
654
140
        parameters[i] = INIT_CHAR;
655
    }
656
657
1
    housekeeping_packet.targetLogicalAddress = CCSDS_DESTINATION_ID;
658
1
    housekeeping_packet.protocolIdentifier = CCSDS_PROTOCOLE_ID;
659
1
    housekeeping_packet.reserved = DEFAULT_RESERVED;
660
1
    housekeeping_packet.userApplication = CCSDS_USER_APP;
661
1
    housekeeping_packet.packetID[0] = (unsigned char) (APID_TM_HK >> SHIFT_1_BYTE);
662
1
    housekeeping_packet.packetID[1] = (unsigned char) (APID_TM_HK);
663
1
    housekeeping_packet.packetSequenceControl[0] = TM_PACKET_SEQ_CTRL_STANDALONE;
664
1
    housekeeping_packet.packetSequenceControl[1] = TM_PACKET_SEQ_CNT_DEFAULT;
665
1
    housekeeping_packet.packetLength[0] = (unsigned char) (PACKET_LENGTH_HK >> SHIFT_1_BYTE);
666
1
    housekeeping_packet.packetLength[1] = (unsigned char) (PACKET_LENGTH_HK     );
667
1
    housekeeping_packet.spare1_pusVersion_spare2 = DEFAULT_SPARE1_PUSVERSION_SPARE2;
668
1
    housekeeping_packet.serviceType = TM_TYPE_HK;
669
1
    housekeeping_packet.serviceSubType = TM_SUBTYPE_HK;
670
1
    housekeeping_packet.destinationID = TM_DESTINATION_ID_GROUND;
671
1
    housekeeping_packet.sid = SID_HK;
672
673
    // init status word
674
1
    housekeeping_packet.lfr_status_word[0] = DEFAULT_STATUS_WORD_BYTE0;
675
1
    housekeeping_packet.lfr_status_word[1] = DEFAULT_STATUS_WORD_BYTE1;
676
    // init software version
677
1
    housekeeping_packet.lfr_sw_version[0] = SW_VERSION_N1;
678
1
    housekeeping_packet.lfr_sw_version[1] = SW_VERSION_N2;
679
1
    housekeeping_packet.lfr_sw_version[BYTE_2] = SW_VERSION_N3;
680
1
    housekeeping_packet.lfr_sw_version[BYTE_3] = SW_VERSION_N4;
681
    // init fpga version
682
1
    parameters = (unsigned char *) (REGS_ADDR_VHDL_VERSION);
683
1
    housekeeping_packet.lfr_fpga_version[BYTE_0] = parameters[BYTE_1]; // n1
684
1
    housekeeping_packet.lfr_fpga_version[BYTE_1] = parameters[BYTE_2]; // n2
685
1
    housekeeping_packet.lfr_fpga_version[BYTE_2] = parameters[BYTE_3]; // n3
686
687
1
    housekeeping_packet.hk_lfr_q_sd_fifo_size = MSG_QUEUE_COUNT_SEND;
688
1
    housekeeping_packet.hk_lfr_q_rv_fifo_size = MSG_QUEUE_COUNT_RECV;
689
1
    housekeeping_packet.hk_lfr_q_p0_fifo_size = MSG_QUEUE_COUNT_PRC0;
690
1
    housekeeping_packet.hk_lfr_q_p1_fifo_size = MSG_QUEUE_COUNT_PRC1;
691
1
    housekeeping_packet.hk_lfr_q_p2_fifo_size = MSG_QUEUE_COUNT_PRC2;
692
1
}
693
694
43
void increment_seq_counter( unsigned short *packetSequenceControl )
695
{
696
    /** This function increment the sequence counter passes in argument.
697
     *
698
     * The increment does not affect the grouping flag. In case of an overflow, the counter is reset to 0.
699
     *
700
     */
701
702
    unsigned short segmentation_grouping_flag;
703
    unsigned short sequence_cnt;
704
705
43
    segmentation_grouping_flag  = TM_PACKET_SEQ_CTRL_STANDALONE << SHIFT_1_BYTE;   // keep bits 7 downto 6
706
43
    sequence_cnt                = (*packetSequenceControl) & SEQ_CNT_MASK;    // [0011 1111 1111 1111]
707
708
43
    if ( sequence_cnt < SEQ_CNT_MAX)
709
    {
710
43
        sequence_cnt = sequence_cnt + 1;
711
    }
712
    else
713
    {
714
        sequence_cnt = 0;
715
    }
716
717
43
    *packetSequenceControl = segmentation_grouping_flag | sequence_cnt ;
718
43
}
719
720
1
void getTime( unsigned char *time)
721
{
722
    /** This function write the current local time in the time buffer passed in argument.
723
     *
724
     */
725
726
1
    time[0] = (unsigned char) (time_management_regs->coarse_time>>SHIFT_3_BYTES);
727
1
    time[1] = (unsigned char) (time_management_regs->coarse_time>>SHIFT_2_BYTES);
728
1
    time[2] = (unsigned char) (time_management_regs->coarse_time>>SHIFT_1_BYTE);
729
1
    time[3] = (unsigned char) (time_management_regs->coarse_time);
730
1
    time[4] = (unsigned char) (time_management_regs->fine_time>>SHIFT_1_BYTE);
731
1
    time[5] = (unsigned char) (time_management_regs->fine_time);
732
1
}
733
734
unsigned long long int getTimeAsUnsignedLongLongInt( )
735
{
736
    /** This function write the current local time in the time buffer passed in argument.
737
     *
738
     */
739
    unsigned long long int time;
740
741
    time = ( (unsigned long long int) (time_management_regs->coarse_time & COARSE_TIME_MASK) << SHIFT_2_BYTES )
742
            + time_management_regs->fine_time;
743
744
    return time;
745
}
746
747
43
void get_temperatures( unsigned char *temperatures )
748
{
749
    unsigned char* temp_scm_ptr;
750
    unsigned char* temp_pcb_ptr;
751
    unsigned char* temp_fpga_ptr;
752
753
    // SEL1 SEL0
754
    // 0    0       => PCB
755
    // 0    1       => FPGA
756
    // 1    0       => SCM
757
758
43
    temp_scm_ptr  = (unsigned char *) &time_management_regs->temp_scm;
759
43
    temp_pcb_ptr =  (unsigned char *) &time_management_regs->temp_pcb;
760
43
    temp_fpga_ptr = (unsigned char *) &time_management_regs->temp_fpga;
761
762
43
    temperatures[ BYTE_0 ] = temp_scm_ptr[ BYTE_2 ];
763
43
    temperatures[ BYTE_1 ] = temp_scm_ptr[ BYTE_3 ];
764
43
    temperatures[ BYTE_2 ] = temp_pcb_ptr[ BYTE_2 ];
765
43
    temperatures[ BYTE_3 ] = temp_pcb_ptr[ BYTE_3 ];
766
43
    temperatures[ BYTE_4 ] = temp_fpga_ptr[ BYTE_2 ];
767
43
    temperatures[ BYTE_5 ] = temp_fpga_ptr[ BYTE_3 ];
768
43
}
769
770
43
void get_v_e1_e2_f3( unsigned char *spacecraft_potential )
771
{
772
    unsigned char* v_ptr;
773
    unsigned char* e1_ptr;
774
    unsigned char* e2_ptr;
775
776
43
    v_ptr  = (unsigned char *) &hk_lfr_sc_v_f3_as_int16;
777
43
    e1_ptr = (unsigned char *) &hk_lfr_sc_e1_f3_as_int16;
778
43
    e2_ptr = (unsigned char *) &hk_lfr_sc_e2_f3_as_int16;
779
780
43
    spacecraft_potential[BYTE_0] = v_ptr[0];
781
43
    spacecraft_potential[BYTE_1] = v_ptr[1];
782
43
    spacecraft_potential[BYTE_2] = e1_ptr[0];
783
43
    spacecraft_potential[BYTE_3] = e1_ptr[1];
784
43
    spacecraft_potential[BYTE_4] = e2_ptr[0];
785
43
    spacecraft_potential[BYTE_5] = e2_ptr[1];
786
43
}
787
788
/**
789
 * @brief get_cpu_load, computes CPU load, CPU load average and CPU load max
790
 * @param resource_statistics stores:
791
 *          - CPU load at index 0
792
 *          - CPU load max at index 1
793
 *          - CPU load average at index 2
794
 *
795
 * The CPU load average is computed on the last 60 values with a simple moving average.
796
 */
797
43
void get_cpu_load( unsigned char *resource_statistics )
798
{
799
#define LOAD_AVG_SIZE 60
800
    static unsigned char cpu_load_hist[LOAD_AVG_SIZE]={0};
801
    static char old_avg_pos=0;
802
    static unsigned int cpu_load_avg;
803
    unsigned char cpu_load;
804
805
43
    cpu_load = lfr_rtems_cpu_usage_report();
806
807
    // HK_LFR_CPU_LOAD
808
43
    resource_statistics[BYTE_0] = cpu_load;
809
810
    // HK_LFR_CPU_LOAD_MAX
811
43
    if (cpu_load > resource_statistics[BYTE_1])
812
    {
813
1
         resource_statistics[BYTE_1] = cpu_load;
814
    }
815
816
43
    cpu_load_avg = cpu_load_avg - (unsigned int)cpu_load_hist[(int)old_avg_pos] + (unsigned int)cpu_load;
817
43
    cpu_load_hist[(int)old_avg_pos] = cpu_load;
818
43
    old_avg_pos += 1;
819
43
    old_avg_pos %= LOAD_AVG_SIZE;
820
    // CPU_LOAD_AVE
821
43
    resource_statistics[BYTE_2] = (unsigned char)(cpu_load_avg / LOAD_AVG_SIZE);
822
// this will change the way LFR compute usage
823
#ifndef PRINT_TASK_STATISTICS
824
43
        rtems_cpu_usage_reset();
825
#endif
826
827
43
}
828
829
2
void set_hk_lfr_sc_potential_flag( bool state )
830
{
831
2
    if (state == true)
832
    {
833
2
        housekeeping_packet.lfr_status_word[1] =
834
2
                housekeeping_packet.lfr_status_word[1] | STATUS_WORD_SC_POTENTIAL_FLAG_BIT;   // [0100 0000]
835
    }
836
    else
837
    {
838
        housekeeping_packet.lfr_status_word[1] =
839
                housekeeping_packet.lfr_status_word[1] & STATUS_WORD_SC_POTENTIAL_FLAG_MASK;   // [1011 1111]
840
    }
841
2
}
842
843
void set_sy_lfr_pas_filter_enabled( bool state )
844
{
845
    if (state == true)
846
    {
847
        housekeeping_packet.lfr_status_word[1] =
848
                housekeeping_packet.lfr_status_word[1] | STATUS_WORD_PAS_FILTER_ENABLED_BIT;   // [0010 0000]
849
    }
850
    else
851
    {
852
        housekeeping_packet.lfr_status_word[1] =
853
                housekeeping_packet.lfr_status_word[1] & STATUS_WORD_PAS_FILTER_ENABLED_MASK;   // [1101 1111]
854
    }
855
}
856
857
1
void set_sy_lfr_watchdog_enabled( bool state )
858
{
859
1
    if (state == true)
860
    {
861
1
        housekeeping_packet.lfr_status_word[1] =
862
1
                housekeeping_packet.lfr_status_word[1] | STATUS_WORD_WATCHDOG_BIT;   // [0001 0000]
863
    }
864
    else
865
    {
866
        housekeeping_packet.lfr_status_word[1] =
867
                housekeeping_packet.lfr_status_word[1] & STATUS_WORD_WATCHDOG_MASK;   // [1110 1111]
868
    }
869
1
}
870
871
1
void set_hk_lfr_calib_enable( bool state )
872
{
873
1
    if (state == true)
874
    {
875
        housekeeping_packet.lfr_status_word[1] =
876
                housekeeping_packet.lfr_status_word[1] | STATUS_WORD_CALIB_BIT;   // [0000 1000]
877
    }
878
    else
879
    {
880
1
        housekeeping_packet.lfr_status_word[1] =
881
1
                housekeeping_packet.lfr_status_word[1] & STATUS_WORD_CALIB_MASK;   // [1111 0111]
882
    }
883
1
}
884
885
1
void set_hk_lfr_reset_cause( enum lfr_reset_cause_t lfr_reset_cause )
886
{
887
1
    housekeeping_packet.lfr_status_word[1] =
888
1
            housekeeping_packet.lfr_status_word[1] & STATUS_WORD_RESET_CAUSE_MASK; // [1111 1000]
889
890
1
    housekeeping_packet.lfr_status_word[1] = housekeeping_packet.lfr_status_word[1]
891
            | (lfr_reset_cause & STATUS_WORD_RESET_CAUSE_BITS );   // [0000 0111]
892
893
1
}
894
895
688
void increment_hk_counter( unsigned char newValue, unsigned char oldValue, unsigned int *counter )
896
{
897
    int delta;
898
899
688
    delta = 0;
900
901
688
    if (newValue >= oldValue)
902
    {
903
688
        delta = newValue - oldValue;
904
    }
905
    else
906
    {
907
        delta = (CONST_256 - oldValue) + newValue;
908
    }
909
910
688
    *counter = *counter + delta;
911
688
}
912
913
// Low severity error counters update
914
43
void hk_lfr_le_update( void )
915
{
916
    static hk_lfr_le_t old_hk_lfr_le = {0};
917
    hk_lfr_le_t new_hk_lfr_le;
918
    unsigned int counter;
919
920
43
    counter = (((unsigned int) housekeeping_packet.hk_lfr_le_cnt[0]) * CONST_256) + housekeeping_packet.hk_lfr_le_cnt[1];
921
922
    // DPU
923
43
    new_hk_lfr_le.dpu_spw_parity    = housekeeping_packet.hk_lfr_dpu_spw_parity;
924
43
    new_hk_lfr_le.dpu_spw_disconnect= housekeeping_packet.hk_lfr_dpu_spw_disconnect;
925
43
    new_hk_lfr_le.dpu_spw_escape    = housekeeping_packet.hk_lfr_dpu_spw_escape;
926
43
    new_hk_lfr_le.dpu_spw_credit    = housekeeping_packet.hk_lfr_dpu_spw_credit;
927
43
    new_hk_lfr_le.dpu_spw_write_sync= housekeeping_packet.hk_lfr_dpu_spw_write_sync;
928
    // TIMECODE
929
43
    new_hk_lfr_le.timecode_erroneous= housekeeping_packet.hk_lfr_timecode_erroneous;
930
43
    new_hk_lfr_le.timecode_missing  = housekeeping_packet.hk_lfr_timecode_missing;
931
43
    new_hk_lfr_le.timecode_invalid  = housekeeping_packet.hk_lfr_timecode_invalid;
932
    // TIME
933
43
    new_hk_lfr_le.time_timecode_it  = housekeeping_packet.hk_lfr_time_timecode_it;
934
43
    new_hk_lfr_le.time_not_synchro  = housekeeping_packet.hk_lfr_time_not_synchro;
935
43
    new_hk_lfr_le.time_timecode_ctr = housekeeping_packet.hk_lfr_time_timecode_ctr;
936
    //AHB
937
43
    new_hk_lfr_le.ahb_correctable   = housekeeping_packet.hk_lfr_ahb_correctable;
938
    // housekeeping_packet.hk_lfr_dpu_spw_rx_ahb => not handled by the grspw driver
939
    // housekeeping_packet.hk_lfr_dpu_spw_tx_ahb => not handled by the grspw driver
940
941
    // update the le counter
942
    // DPU
943
43
    increment_hk_counter( new_hk_lfr_le.dpu_spw_parity,    old_hk_lfr_le.dpu_spw_parity,       &counter );
944
43
    increment_hk_counter( new_hk_lfr_le.dpu_spw_disconnect,old_hk_lfr_le.dpu_spw_disconnect,   &counter );
945
43
    increment_hk_counter( new_hk_lfr_le.dpu_spw_escape,    old_hk_lfr_le.dpu_spw_escape,       &counter );
946
43
    increment_hk_counter( new_hk_lfr_le.dpu_spw_credit,    old_hk_lfr_le.dpu_spw_credit,       &counter );
947
43
    increment_hk_counter( new_hk_lfr_le.dpu_spw_write_sync,old_hk_lfr_le.dpu_spw_write_sync,   &counter );
948
    // TIMECODE
949
43
    increment_hk_counter( new_hk_lfr_le.timecode_erroneous,old_hk_lfr_le.timecode_erroneous,   &counter );
950
43
    increment_hk_counter( new_hk_lfr_le.timecode_missing,  old_hk_lfr_le.timecode_missing,     &counter );
951
43
    increment_hk_counter( new_hk_lfr_le.timecode_invalid,  old_hk_lfr_le.timecode_invalid,     &counter );
952
    // TIME
953
43
    increment_hk_counter( new_hk_lfr_le.time_timecode_it,  old_hk_lfr_le.time_timecode_it,     &counter );
954
43
    increment_hk_counter( new_hk_lfr_le.time_not_synchro,  old_hk_lfr_le.time_not_synchro,     &counter );
955
43
    increment_hk_counter( new_hk_lfr_le.time_timecode_ctr, old_hk_lfr_le.time_timecode_ctr,    &counter );
956
    // AHB
957
43
    increment_hk_counter( new_hk_lfr_le.ahb_correctable,   old_hk_lfr_le.ahb_correctable,      &counter );
958
959
    // DPU
960
43
    old_hk_lfr_le.dpu_spw_parity    = new_hk_lfr_le.dpu_spw_parity;
961
43
    old_hk_lfr_le.dpu_spw_disconnect= new_hk_lfr_le.dpu_spw_disconnect;
962
43
    old_hk_lfr_le.dpu_spw_escape    = new_hk_lfr_le.dpu_spw_escape;
963
43
    old_hk_lfr_le.dpu_spw_credit    = new_hk_lfr_le.dpu_spw_credit;
964
43
    old_hk_lfr_le.dpu_spw_write_sync= new_hk_lfr_le.dpu_spw_write_sync;
965
    // TIMECODE
966
43
    old_hk_lfr_le.timecode_erroneous= new_hk_lfr_le.timecode_erroneous;
967
43
    old_hk_lfr_le.timecode_missing  = new_hk_lfr_le.timecode_missing;
968
43
    old_hk_lfr_le.timecode_invalid  = new_hk_lfr_le.timecode_invalid;
969
    // TIME
970
43
    old_hk_lfr_le.time_timecode_it  = new_hk_lfr_le.time_timecode_it;
971
43
    old_hk_lfr_le.time_not_synchro  = new_hk_lfr_le.time_not_synchro;
972
43
    old_hk_lfr_le.time_timecode_ctr = new_hk_lfr_le.time_timecode_ctr;
973
    //AHB
974
43
    old_hk_lfr_le.ahb_correctable   = new_hk_lfr_le.ahb_correctable;
975
    // housekeeping_packet.hk_lfr_dpu_spw_rx_ahb => not handled by the grspw driver
976
    // housekeeping_packet.hk_lfr_dpu_spw_tx_ahb => not handled by the grspw driver
977
978
    // update housekeeping packet counters, convert unsigned int numbers in 2 bytes numbers
979
    // LE
980
43
    housekeeping_packet.hk_lfr_le_cnt[0] = (unsigned char) ((counter & BYTE0_MASK) >> SHIFT_1_BYTE);
981
43
    housekeeping_packet.hk_lfr_le_cnt[1] = (unsigned char)  (counter & BYTE1_MASK);
982
43
}
983
984
// Medium severity error counters update
985
43
void hk_lfr_me_update( void )
986
{
987
    static hk_lfr_me_t old_hk_lfr_me = {0};
988
    hk_lfr_me_t new_hk_lfr_me;
989
    unsigned int counter;
990
991
43
    counter = (((unsigned int) housekeeping_packet.hk_lfr_me_cnt[0]) * CONST_256) + housekeeping_packet.hk_lfr_me_cnt[1];
992
993
    // get the current values
994
43
    new_hk_lfr_me.dpu_spw_early_eop     = housekeeping_packet.hk_lfr_dpu_spw_early_eop;
995
43
    new_hk_lfr_me.dpu_spw_invalid_addr  = housekeeping_packet.hk_lfr_dpu_spw_invalid_addr;
996
43
    new_hk_lfr_me.dpu_spw_eep           = housekeeping_packet.hk_lfr_dpu_spw_eep;
997
43
    new_hk_lfr_me.dpu_spw_rx_too_big    = housekeeping_packet.hk_lfr_dpu_spw_rx_too_big;
998
999
    // update the me counter
1000
43
    increment_hk_counter( new_hk_lfr_me.dpu_spw_early_eop,      old_hk_lfr_me.dpu_spw_early_eop,    &counter );
1001
43
    increment_hk_counter( new_hk_lfr_me.dpu_spw_invalid_addr,   old_hk_lfr_me.dpu_spw_invalid_addr, &counter );
1002
43
    increment_hk_counter( new_hk_lfr_me.dpu_spw_eep,            old_hk_lfr_me.dpu_spw_eep,          &counter );
1003
43
    increment_hk_counter( new_hk_lfr_me.dpu_spw_rx_too_big,     old_hk_lfr_me.dpu_spw_rx_too_big,   &counter );
1004
1005
    // store the counters for the next time
1006
43
    old_hk_lfr_me.dpu_spw_early_eop     = new_hk_lfr_me.dpu_spw_early_eop;
1007
43
    old_hk_lfr_me.dpu_spw_invalid_addr  = new_hk_lfr_me.dpu_spw_invalid_addr;
1008
43
    old_hk_lfr_me.dpu_spw_eep           = new_hk_lfr_me.dpu_spw_eep;
1009
43
    old_hk_lfr_me.dpu_spw_rx_too_big    = new_hk_lfr_me.dpu_spw_rx_too_big;
1010
1011
    // update housekeeping packet counters, convert unsigned int numbers in 2 bytes numbers
1012
    // ME
1013
43
    housekeeping_packet.hk_lfr_me_cnt[0] = (unsigned char) ((counter & BYTE0_MASK) >> SHIFT_1_BYTE);
1014
43
    housekeeping_packet.hk_lfr_me_cnt[1] = (unsigned char)  (counter & BYTE1_MASK);
1015
43
}
1016
1017
// High severity error counters update
1018
43
void hk_lfr_le_me_he_update()
1019
{
1020
1021
    unsigned int hk_lfr_he_cnt;
1022
1023
43
    hk_lfr_he_cnt = (((unsigned int) housekeeping_packet.hk_lfr_he_cnt[0]) * 256) + housekeeping_packet.hk_lfr_he_cnt[1];
1024
1025
    //update the low severity error counter
1026
43
    hk_lfr_le_update( );
1027
1028
    //update the medium severity error counter
1029
43
    hk_lfr_me_update();
1030
1031
    //update the high severity error counter
1032
43
    hk_lfr_he_cnt = 0;
1033
1034
    // update housekeeping packet counters, convert unsigned int numbers in 2 bytes numbers
1035
    // HE
1036
43
    housekeeping_packet.hk_lfr_he_cnt[0] = (unsigned char) ((hk_lfr_he_cnt & BYTE0_MASK) >> SHIFT_1_BYTE);
1037
43
    housekeeping_packet.hk_lfr_he_cnt[1] = (unsigned char)  (hk_lfr_he_cnt & BYTE1_MASK);
1038
1039
43
}
1040
1041
43
void set_hk_lfr_time_not_synchro()
1042
{
1043
    static unsigned char synchroLost = 1;
1044
    int synchronizationBit;
1045
1046
    // get the synchronization bit
1047
43
    synchronizationBit =
1048
43
            (time_management_regs->coarse_time & VAL_LFR_SYNCHRONIZED) >> BIT_SYNCHRONIZATION;    // 1000 0000 0000 0000
1049
1050
43
    switch (synchronizationBit)
1051
    {
1052
    case 0:
1053
        if (synchroLost == 1)
1054
        {
1055
            synchroLost = 0;
1056
        }
1057
        break;
1058
    case 1:
1059
43
        if (synchroLost == 0 )
1060
        {
1061
            synchroLost = 1;
1062
            increase_unsigned_char_counter(&housekeeping_packet.hk_lfr_time_not_synchro);
1063
            update_hk_lfr_last_er_fields( RID_LE_LFR_TIME, CODE_NOT_SYNCHRO );
1064
        }
1065
        break;
1066
    default:
1067
        PRINTF1("in hk_lfr_time_not_synchro *** unexpected value for synchronizationBit = %d\n", synchronizationBit);
1068
        break;
1069
    }
1070
1071
43
}
1072
1073
void set_hk_lfr_ahb_correctable()   // CRITICITY L
1074
{
1075
    /** This function builds the error counter hk_lfr_ahb_correctable using the statistics provided
1076
     * by the Cache Control Register (ASI 2, offset 0) and in the Register Protection Control Register (ASR16) on the
1077
     * detected errors in the cache, in the integer unit and in the floating point unit.
1078
     *
1079
     * @param void
1080
     *
1081
     * @return void
1082
     *
1083
     * All errors are summed to set the value of the hk_lfr_ahb_correctable counter.
1084
     *
1085
    */
1086
1087
    unsigned int ahb_correctable;
1088
    unsigned int instructionErrorCounter;
1089
    unsigned int dataErrorCounter;
1090
    unsigned int fprfErrorCounter;
1091
    unsigned int iurfErrorCounter;
1092
1093
    instructionErrorCounter = 0;
1094
    dataErrorCounter = 0;
1095
    fprfErrorCounter = 0;
1096
    iurfErrorCounter = 0;
1097
1098
    CCR_getInstructionAndDataErrorCounters( &instructionErrorCounter, &dataErrorCounter);
1099
    ASR16_get_FPRF_IURF_ErrorCounters( &fprfErrorCounter, &iurfErrorCounter);
1100
1101
    ahb_correctable = instructionErrorCounter
1102
            + dataErrorCounter
1103
            + fprfErrorCounter
1104
            + iurfErrorCounter
1105
            + housekeeping_packet.hk_lfr_ahb_correctable;
1106
1107
    housekeeping_packet.hk_lfr_ahb_correctable = (unsigned char) (ahb_correctable & INT8_ALL_F);  // [1111 1111]
1108
1109
}