GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/fsw_misc.c Lines: 334 399 83.7 %
Date: 2018-11-13 15:31:29 Branches: 31 57 54.4 %

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

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

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