LCOV - code coverage report
Current view: top level - src - fsw_init.c (source / functions) Hit Total Coverage
Test: trace.info Lines: 258 264 97.7 %
Date: 2023-02-20 11:47:18 Functions: 14 16 87.5 %

          Line data    Source code
       1             : /*------------------------------------------------------------------------------
       2             : --  Solar Orbiter's Low Frequency Receiver Flight Software (LFR FSW),
       3             : --  This file is a part of the LFR FSW
       4             : --  Copyright (C) 2012-2018, Plasma Physics Laboratory - CNRS
       5             : --
       6             : --  This program is free software; you can redistribute it and/or modify
       7             : --  it under the terms of the GNU General Public License as published by
       8             : --  the Free Software Foundation; either version 2 of the License, or
       9             : --  (at your option) any later version.
      10             : --
      11             : --  This program is distributed in the hope that it will be useful,
      12             : --  but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : --  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : --  GNU General Public License for more details.
      15             : --
      16             : --  You should have received a copy of the GNU General Public License
      17             : --  along with this program; if not, write to the Free Software
      18             : --  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      19             : -------------------------------------------------------------------------------*/
      20             : /*--                  Author : Paul Leroy
      21             : --                   Contact : Alexis Jeandet
      22             : --                      Mail : alexis.jeandet@lpp.polytechnique.fr
      23             : ----------------------------------------------------------------------------*/
      24             : 
      25             : /** This is the RTEMS initialization module.
      26             :  *
      27             :  * @file
      28             :  * @author P. LEROY
      29             :  *
      30             :  * This module contains two very different information:
      31             :  * - specific instructions to configure the compilation of the RTEMS executive
      32             :  * - functions related to the fligth softwre initialization, especially the INIT RTEMS task
      33             :  *
      34             :  */
      35             : 
      36             : #include <rtems.h>
      37             : 
      38             : /* configuration information */
      39             : 
      40             : #define CONFIGURE_INIT
      41             : 
      42             : #include <bsp.h> /* for device driver prototypes */
      43             : 
      44             : /* configuration information */
      45             : 
      46             : #include <fsw_params.h>
      47             : 
      48             : #include <rtems/confdefs.h>
      49             : 
      50             : /* If --drvmgr was enabled during the configuration of the RTEMS kernel */
      51             : #ifdef RTEMS_DRVMGR_STARTUP
      52             :     #ifdef LEON3
      53             :     /* Add Timer and UART Driver */
      54             : 
      55             :         #ifdef CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
      56             :             #define CONFIGURE_DRIVER_AMBAPP_GAISLER_GPTIMER
      57             :         #endif
      58             : 
      59             :         #ifdef CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
      60             :             #define CONFIGURE_DRIVER_AMBAPP_GAISLER_APBUART
      61             :         #endif
      62             : 
      63             :     #endif
      64             :     #define CONFIGURE_DRIVER_AMBAPP_GAISLER_GRSPW /* GRSPW Driver */
      65             :     #include <drvmgr/drvmgr_confdefs.h>
      66             : #endif
      67             : 
      68             : #include "GscMemoryLPP.hpp"
      69             : #include "fsw_compile_warnings.h"
      70             : #include "fsw_config.c"
      71             : #include "fsw_debug.h"
      72             : #include "fsw_housekeeping.h"
      73             : #include "fsw_init.h"
      74             : #include "hw/lfr_regs.h"
      75             : #include "hw/uart.h"
      76             : #include "processing/ASM/spectralmatrices.h"
      77             : 
      78          18 : void initCache()
      79             : {
      80             :     // ASI 2 contains a few control registers that have not been assigned as ancillary state
      81             :     // registers. These should only be read and written using 32-bit LDA/STA instructions. All cache
      82             :     // registers are accessed through load/store operations to the alternate address space
      83             :     // (LDA/STA), using ASI = 2. The table below shows the register addresses:
      84             :     //      0x00 Cache control register
      85             :     //      0x04 Reserved
      86             :     //      0x08 Instruction cache configuration register
      87             :     //      0x0C Data cache configuration register
      88             : 
      89             :     // Cache Control Register Leon3 / Leon3FT
      90             :     // 31..30  29   28  27..24  23  22  21  20..19  18  17  16
      91             :     //         RFT  PS  TB      DS  FD  FI  FT          ST  IB
      92             :     // 15  14  13..12  11..10  9..8  7..6  5   4   3..2  1..0
      93             :     // IP  DP  ITE     IDE     DTE   DDE   DF  IF  DCS   ICS
      94             : 
      95             :     CCR_resetCacheControlRegister();
      96             :     ASR16_resetRegisterProtectionControlRegister();
      97             : 
      98             :     CCR_enableInstructionCache(); // ICS bits
      99             :     CCR_enableDataCache(); // DCS bits
     100             :     CCR_enableInstructionBurstFetch(); // IB  bit
     101             : 
     102          18 :     faultTolerantScheme();
     103          18 : }
     104             : 
     105             : rtems_task Init(rtems_task_argument ignored)
     106             : {
     107             :     /** This is the RTEMS INIT taks, it is the first task launched by the system.
     108             :      *
     109             :      * @param unused is the starting argument of the RTEMS task
     110             :      *
     111             :      * The INIT task create and run all other RTEMS tasks.
     112             :      *
     113             :      */
     114             :     IGNORE_UNUSED_PARAMETER(ignored);
     115             :     //***********
     116             :     // INIT CACHE
     117             : 
     118          18 :     const unsigned char* const vhdlVersion = (unsigned char*)(REGS_ADDR_VHDL_VERSION);
     119             : 
     120          18 :     reset_lfr();
     121             : 
     122             :     reset_local_time();
     123             : 
     124          18 :     rtems_cpu_usage_reset();
     125             : 
     126             :     rtems_status_code status_spw;
     127             :     rtems_isr_entry old_isr_handler;
     128             : 
     129          18 :     old_isr_handler = NULL;
     130             : 
     131             :     // UART settings
     132          18 :     enable_apbuart_transmitter();
     133          18 :     set_apbuart_scaler_reload_register(APBUART_SCALER_RELOAD_VALUE);
     134             : 
     135             :     DEBUG_PRINTF("\n\n\n\n\nIn INIT *** Now the console is on port COM1\n");
     136             : 
     137             : 
     138             :     LFR_PRINTF("\n\n\n\n\n");
     139             : 
     140          18 :     initCache();
     141             : 
     142             :     LFR_PRINTF("*************************\n");
     143             :     LFR_PRINTF("** LFR Flight Software **\n");
     144             : 
     145             :     LFR_PRINTF("** %d-", SW_VERSION_N1);
     146             :     LFR_PRINTF("%d-", SW_VERSION_N2);
     147             :     LFR_PRINTF("%d-", SW_VERSION_N3);
     148             :     LFR_PRINTF("%d             **\n", SW_VERSION_N4);
     149             : 
     150             :     LFR_PRINTF("** VHDL                **\n");
     151             :     LFR_PRINTF("** %d-", vhdlVersion[1]);
     152             :     LFR_PRINTF("%d-", vhdlVersion[2]);
     153             :     LFR_PRINTF("%d              **\n", vhdlVersion[3]);
     154             :     LFR_PRINTF("*************************\n");
     155             :     LFR_PRINTF("\n\n");
     156             : 
     157          18 :     init_parameter_dump();
     158          18 :     init_kcoefficients_dump();
     159             :     init_local_mode_parameters();
     160          18 :     init_housekeeping_parameters();
     161          18 :     pa_bia_status_info = INIT_CHAR;
     162             : 
     163             :     // initialize all reaction wheels frequencies to NaN
     164          18 :     rw_f.cp_rpw_sc_rw1_f1 = NAN;
     165          18 :     rw_f.cp_rpw_sc_rw1_f2 = NAN;
     166          18 :     rw_f.cp_rpw_sc_rw1_f3 = NAN;
     167          18 :     rw_f.cp_rpw_sc_rw1_f4 = NAN;
     168          18 :     rw_f.cp_rpw_sc_rw2_f1 = NAN;
     169          18 :     rw_f.cp_rpw_sc_rw2_f2 = NAN;
     170          18 :     rw_f.cp_rpw_sc_rw2_f3 = NAN;
     171          18 :     rw_f.cp_rpw_sc_rw2_f4 = NAN;
     172          18 :     rw_f.cp_rpw_sc_rw3_f1 = NAN;
     173          18 :     rw_f.cp_rpw_sc_rw3_f2 = NAN;
     174          18 :     rw_f.cp_rpw_sc_rw3_f3 = NAN;
     175          18 :     rw_f.cp_rpw_sc_rw3_f4 = NAN;
     176          18 :     rw_f.cp_rpw_sc_rw4_f1 = NAN;
     177          18 :     rw_f.cp_rpw_sc_rw4_f2 = NAN;
     178          18 :     rw_f.cp_rpw_sc_rw4_f3 = NAN;
     179          18 :     rw_f.cp_rpw_sc_rw4_f4 = NAN;
     180             : 
     181             :     // initialize filtering parameters
     182          18 :     filterPar.spare_sy_lfr_pas_filter_enabled = DEFAULT_SY_LFR_PAS_FILTER_ENABLED;
     183          18 :     filterPar.sy_lfr_sc_rw_delta_f = DEFAULT_SY_LFR_SC_RW_DELTA_F;
     184          18 :     filterPar.sy_lfr_pas_filter_tbad = DEFAULT_SY_LFR_PAS_FILTER_TBAD;
     185          18 :     filterPar.sy_lfr_pas_filter_shift = DEFAULT_SY_LFR_PAS_FILTER_SHIFT;
     186          18 :     filterPar.modulus_in_finetime = DEFAULT_MODULUS;
     187          18 :     filterPar.tbad_in_finetime = DEFAULT_TBAD;
     188          18 :     filterPar.offset_in_finetime = DEFAULT_OFFSET;
     189          18 :     filterPar.shift_in_finetime = DEFAULT_SHIFT;
     190          18 :     update_last_valid_transition_date(DEFAULT_LAST_VALID_TRANSITION_DATE);
     191             : 
     192             :     // waveform picker initialization
     193          18 :     WFP_init_rings();
     194          18 :     LEON_Clear_interrupt(IRQ_SPARC_GPTIMER_WATCHDOG); // initialize the waveform rings
     195          18 :     WFP_reset_current_ring_nodes();
     196          18 :     reset_waveform_picker_regs();
     197             : 
     198             :     // spectral matrices initialization
     199          18 :     SM_init_rings(); // initialize spectral matrices rings
     200          18 :     SM_reset_current_ring_nodes();
     201          18 :     reset_spectral_matrix_regs();
     202             : 
     203             :     // configure calibration
     204          18 :     configureCalibration();
     205             : 
     206          18 :     updateLFRCurrentMode(LFR_MODE_STANDBY);
     207             : 
     208             :     BOOT_PRINTF("in INIT *** lfrCurrentMode is %d\n", lfrCurrentMode);
     209             : 
     210          18 :     create_names(); // create all names
     211             : 
     212          18 :     DEBUG_CHECK_STATUS(create_timecode_timer()); // create the timer used by timecode_irq_handler
     213             : 
     214          18 :     DEBUG_CHECK_STATUS(create_message_queues()); // create message queues
     215             : 
     216          18 :     DEBUG_CHECK_STATUS(create_all_tasks()); // create all tasks
     217             : 
     218             :     // **************************
     219             :     // <SPACEWIRE INITIALIZATION>
     220          18 :     status_spw = spacewire_open_link(); // (1) open the link
     221             :     DEBUG_CHECK_STATUS(status_spw);
     222             : 
     223          18 :     if (status_spw == RTEMS_SUCCESSFUL) // (2) configure the link
     224             :     {
     225          18 :         status_spw = spacewire_configure_link(fdSPW);
     226             :         DEBUG_CHECK_STATUS(status_spw);
     227             :     }
     228             : 
     229          18 :     if (status_spw == RTEMS_SUCCESSFUL) // (3) start the link
     230             :     {
     231          18 :         status_spw = spacewire_start_link(fdSPW);
     232             :         DEBUG_CHECK_STATUS(status_spw);
     233             :     }
     234             :     // </SPACEWIRE INITIALIZATION>
     235             :     // ***************************
     236             : 
     237          18 :     DEBUG_CHECK_STATUS(start_all_tasks()); // start all tasks
     238             : 
     239             :     // start RECV and SEND *AFTER* SpaceWire Initialization, due to the timeout of the start call
     240             :     // during the initialization
     241          18 :     DEBUG_CHECK_STATUS(start_recv_send_tasks());
     242             : 
     243             :     // suspend science tasks, they will be restarted later depending on the mode
     244             :     // suspend science tasks (not done in stop_current_mode if
     245             :     //                           current mode = STANDBY)
     246          18 :     DEBUG_CHECK_STATUS(suspend_science_tasks());
     247             : 
     248             :     // configure IRQ handling for the waveform picker unit
     249          18 :     DEBUG_CHECK_STATUS(
     250             :         rtems_interrupt_catch(waveforms_isr, IRQ_SPARC_WAVEFORM_PICKER, &old_isr_handler));
     251             :     // configure IRQ handling for the spectral matrices unit
     252          18 :     DEBUG_CHECK_STATUS(
     253             :         rtems_interrupt_catch(spectral_matrices_isr, IRQ_SPARC_SPECTRAL_MATRIX, &old_isr_handler));
     254             : 
     255             :     // if the spacewire link is not up then send an event to the SPIQ task for link recovery
     256          18 :     if (status_spw != RTEMS_SUCCESSFUL)
     257             :     {
     258           0 :         DEBUG_CHECK_STATUS(rtems_event_send(Task_id[TASKID_SPIQ], SPW_LINKERR_EVENT));
     259             :     }
     260             : 
     261             :     BOOT_PRINTF("delete INIT\n");
     262             : 
     263          18 :     set_hk_lfr_sc_potential_flag(true);
     264             : 
     265             :     // start the timer to detect a missing spacewire timecode
     266             :     // the timeout is larger because the spw IP needs to receive several valid timecodes before
     267             :     // generating a tickout if a tickout is generated, the timer is restarted
     268          18 :     DEBUG_CHECK_STATUS(rtems_timer_fire_after(
     269             :         timecode_timer_id, TIMECODE_TIMER_TIMEOUT_INIT, timecode_timer_routine, NULL));
     270             : 
     271          18 :     grspw_timecode_callback = &timecode_irq_handler;
     272             : 
     273          18 :     DEBUG_CHECK_STATUS(rtems_task_delete(RTEMS_SELF));
     274           0 : }
     275             : 
     276           0 : void init_local_mode_parameters(void)
     277             : {
     278             :     /** This function initialize the param_local global variable with default values.
     279             :      *
     280             :      */
     281             : 
     282             :     // LOCAL PARAMETERS
     283             : 
     284             :     BOOT_PRINTF("local_sbm1_nb_cwf_max %d \n", param_local.local_sbm1_nb_cwf_max);
     285             :     BOOT_PRINTF("local_sbm2_nb_cwf_max %d \n", param_local.local_sbm2_nb_cwf_max);
     286             : 
     287             :     // init/clear sequence counters
     288             : 
     289         234 :     for (unsigned int i = 0; i < SEQ_CNT_NB_DEST_ID; i++)
     290             :     {
     291         216 :         sequenceCounters_TC_EXE[i] = 0;
     292         216 :         sequenceCounters_TM_DUMP[i] = 0;
     293             :     }
     294          18 :     sequenceCounters_SCIENCE_NORMAL_BURST = 0;
     295          18 :     sequenceCounters_SCIENCE_SBM1_SBM2 = 0;
     296          18 :     sequenceCounterHK = TM_PACKET_SEQ_CTRL_STANDALONE << TM_PACKET_SEQ_SHIFT;
     297           0 : }
     298             : 
     299           0 : void reset_local_time(void)
     300             : {
     301          18 :     time_management_regs->ctrl = time_management_regs->ctrl
     302             :         | VAL_SOFTWARE_RESET; // [0010] software reset, coarse time = 0x80000000
     303           0 : }
     304             : 
     305          18 : void create_names(void) // create all names for tasks and queues
     306             : {
     307             :     /** This function creates all RTEMS names used in the software for tasks and queues.
     308             :      *
     309             :      * @return RTEMS directive status codes:
     310             :      * - RTEMS_SUCCESSFUL - successful completion
     311             :      *
     312             :      */
     313             : 
     314             :     // task names
     315          18 :     Task_name[TASKID_AVGV] = rtems_build_name('A', 'V', 'G', 'V');
     316          18 :     Task_name[TASKID_RECV] = rtems_build_name('R', 'E', 'C', 'V');
     317          18 :     Task_name[TASKID_ACTN] = rtems_build_name('A', 'C', 'T', 'N');
     318          18 :     Task_name[TASKID_SPIQ] = rtems_build_name('S', 'P', 'I', 'Q');
     319          18 :     Task_name[TASKID_LOAD] = rtems_build_name('L', 'O', 'A', 'D');
     320          18 :     Task_name[TASKID_AVF0] = rtems_build_name('A', 'V', 'F', '0');
     321          18 :     Task_name[TASKID_SWBD] = rtems_build_name('S', 'W', 'B', 'D');
     322          18 :     Task_name[TASKID_WFRM] = rtems_build_name('W', 'F', 'R', 'M');
     323          18 :     Task_name[TASKID_DUMB] = rtems_build_name('D', 'U', 'M', 'B');
     324          18 :     Task_name[TASKID_HOUS] = rtems_build_name('H', 'O', 'U', 'S');
     325          18 :     Task_name[TASKID_PRC0] = rtems_build_name('P', 'R', 'C', '0');
     326          18 :     Task_name[TASKID_CWF3] = rtems_build_name('C', 'W', 'F', '3');
     327          18 :     Task_name[TASKID_CWF2] = rtems_build_name('C', 'W', 'F', '2');
     328          18 :     Task_name[TASKID_CWF1] = rtems_build_name('C', 'W', 'F', '1');
     329          18 :     Task_name[TASKID_SEND] = rtems_build_name('S', 'E', 'N', 'D');
     330          18 :     Task_name[TASKID_LINK] = rtems_build_name('L', 'I', 'N', 'K');
     331          18 :     Task_name[TASKID_AVF1] = rtems_build_name('A', 'V', 'F', '1');
     332          18 :     Task_name[TASKID_PRC1] = rtems_build_name('P', 'R', 'C', '1');
     333          18 :     Task_name[TASKID_AVF2] = rtems_build_name('A', 'V', 'F', '2');
     334          18 :     Task_name[TASKID_PRC2] = rtems_build_name('P', 'R', 'C', '2');
     335          18 :     Task_name[TASKID_SCRB] = rtems_build_name('S', 'C', 'R', 'B');
     336          18 :     Task_name[TASKID_CALI] = rtems_build_name('C', 'A', 'L', 'I');
     337             : 
     338             :     // rate monotonic period names
     339          18 :     name_hk_rate_monotonic = rtems_build_name('H', 'O', 'U', 'S');
     340          18 :     name_avgv_rate_monotonic = rtems_build_name('A', 'V', 'G', 'V');
     341             : 
     342          18 :     misc_name[QUEUE_RECV] = rtems_build_name('Q', '_', 'R', 'V');
     343          18 :     misc_name[QUEUE_SEND] = rtems_build_name('Q', '_', 'S', 'D');
     344          18 :     misc_name[QUEUE_PRC0] = rtems_build_name('Q', '_', 'P', '0');
     345          18 :     misc_name[QUEUE_PRC1] = rtems_build_name('Q', '_', 'P', '1');
     346          18 :     misc_name[QUEUE_PRC2] = rtems_build_name('Q', '_', 'P', '2');
     347             : 
     348          18 :     timecode_timer_name = rtems_build_name('S', 'P', 'T', 'C');
     349          18 : }
     350             : 
     351          18 : int create_all_tasks(void) // create all tasks which run in the software
     352             : {
     353             :     /** This function creates all RTEMS tasks used in the software.
     354             :      *
     355             :      * @return RTEMS directive status codes:
     356             :      * - RTEMS_SUCCESSFUL - task created successfully
     357             :      * - RTEMS_INVALID_ADDRESS - id is NULL
     358             :      * - RTEMS_INVALID_NAME - invalid task name
     359             :      * - RTEMS_INVALID_PRIORITY - invalid task priority
     360             :      * - RTEMS_MP_NOT_CONFIGURED - multiprocessing not configured
     361             :      * - RTEMS_TOO_MANY - too many tasks created
     362             :      * - RTEMS_UNSATISFIED - not enough memory for stack/FP context
     363             :      * - RTEMS_TOO_MANY - too many global objects
     364             :      *
     365             :      */
     366             : 
     367             :     rtems_status_code status;
     368             : 
     369             :     //**********
     370             :     // SPACEWIRE
     371             :     // RECV
     372          18 :     status = rtems_task_create(Task_name[TASKID_RECV], TASK_PRIORITY_RECV, RTEMS_MINIMUM_STACK_SIZE,
     373             :         RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &Task_id[TASKID_RECV]);
     374             :     DEBUG_CHECK_STATUS(status);
     375          18 :     if (status == RTEMS_SUCCESSFUL) // SEND
     376             :     {
     377          18 :         status = rtems_task_create(Task_name[TASKID_SEND], TASK_PRIORITY_SEND,
     378             :             RTEMS_MINIMUM_STACK_SIZE * STACK_SIZE_MULT, RTEMS_DEFAULT_MODES,
     379             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_SEND]);
     380             :         DEBUG_CHECK_STATUS(status);
     381             :     }
     382          18 :     if (status == RTEMS_SUCCESSFUL) // LINK
     383             :     {
     384          18 :         status = rtems_task_create(Task_name[TASKID_LINK], TASK_PRIORITY_LINK,
     385             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES,
     386             :             &Task_id[TASKID_LINK]);
     387             :         DEBUG_CHECK_STATUS(status);
     388             :     }
     389          18 :     if (status == RTEMS_SUCCESSFUL) // ACTN
     390             :     {
     391          18 :         status = rtems_task_create(Task_name[TASKID_ACTN], TASK_PRIORITY_ACTN,
     392             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
     393             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_ACTN]);
     394             :         DEBUG_CHECK_STATUS(status);
     395             :     }
     396          18 :     if (status == RTEMS_SUCCESSFUL) // SPIQ
     397             :     {
     398          18 :         status = rtems_task_create(Task_name[TASKID_SPIQ], TASK_PRIORITY_SPIQ,
     399             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
     400             :             RTEMS_DEFAULT_ATTRIBUTES, &Task_id[TASKID_SPIQ]);
     401             :         DEBUG_CHECK_STATUS(status);
     402             :     }
     403             : 
     404             :     //******************
     405             :     // SPECTRAL MATRICES
     406          18 :     if (status == RTEMS_SUCCESSFUL) // AVF0
     407             :     {
     408          18 :         status = rtems_task_create(Task_name[TASKID_AVF0], TASK_PRIORITY_AVF0,
     409             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     410             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_AVF0]);
     411             :         DEBUG_CHECK_STATUS(status);
     412             :     }
     413          18 :     if (status == RTEMS_SUCCESSFUL) // PRC0
     414             :     {
     415          18 :         status = rtems_task_create(Task_name[TASKID_PRC0], TASK_PRIORITY_PRC0,
     416             :             RTEMS_MINIMUM_STACK_SIZE * STACK_SIZE_MULT, RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
     417             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_PRC0]);
     418             :         DEBUG_CHECK_STATUS(status);
     419             :     }
     420          18 :     if (status == RTEMS_SUCCESSFUL) // AVF1
     421             :     {
     422          18 :         status = rtems_task_create(Task_name[TASKID_AVF1], TASK_PRIORITY_AVF1,
     423             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     424             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_AVF1]);
     425             :         DEBUG_CHECK_STATUS(status);
     426             :     }
     427          18 :     if (status == RTEMS_SUCCESSFUL) // PRC1
     428             :     {
     429          18 :         status = rtems_task_create(Task_name[TASKID_PRC1], TASK_PRIORITY_PRC1,
     430             :             RTEMS_MINIMUM_STACK_SIZE * STACK_SIZE_MULT, RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
     431             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_PRC1]);
     432             :         DEBUG_CHECK_STATUS(status);
     433             :     }
     434          18 :     if (status == RTEMS_SUCCESSFUL) // AVF2
     435             :     {
     436          18 :         status = rtems_task_create(Task_name[TASKID_AVF2], TASK_PRIORITY_AVF2,
     437             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     438             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_AVF2]);
     439             :         DEBUG_CHECK_STATUS(status);
     440             :     }
     441          18 :     if (status == RTEMS_SUCCESSFUL) // PRC2
     442             :     {
     443          18 :         status = rtems_task_create(Task_name[TASKID_PRC2], TASK_PRIORITY_PRC2,
     444             :             RTEMS_MINIMUM_STACK_SIZE * STACK_SIZE_MULT, RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
     445             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_PRC2]);
     446             :         DEBUG_CHECK_STATUS(status);
     447             :     }
     448             : 
     449             :     //****************
     450             :     // WAVEFORM PICKER
     451          18 :     if (status == RTEMS_SUCCESSFUL) // WFRM
     452             :     {
     453          18 :         status = rtems_task_create(Task_name[TASKID_WFRM], TASK_PRIORITY_WFRM,
     454             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     455             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_WFRM]);
     456             :         DEBUG_CHECK_STATUS(status);
     457             :     }
     458          18 :     if (status == RTEMS_SUCCESSFUL) // CWF3
     459             :     {
     460          18 :         status = rtems_task_create(Task_name[TASKID_CWF3], TASK_PRIORITY_CWF3,
     461             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     462             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_CWF3]);
     463             :         DEBUG_CHECK_STATUS(status);
     464             :     }
     465          18 :     if (status == RTEMS_SUCCESSFUL) // CWF2
     466             :     {
     467          18 :         status = rtems_task_create(Task_name[TASKID_CWF2], TASK_PRIORITY_CWF2,
     468             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     469             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_CWF2]);
     470             :         DEBUG_CHECK_STATUS(status);
     471             :     }
     472          18 :     if (status == RTEMS_SUCCESSFUL) // CWF1
     473             :     {
     474          18 :         status = rtems_task_create(Task_name[TASKID_CWF1], TASK_PRIORITY_CWF1,
     475             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     476             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_CWF1]);
     477             :         DEBUG_CHECK_STATUS(status);
     478             :     }
     479          18 :     if (status == RTEMS_SUCCESSFUL) // SWBD
     480             :     {
     481          18 :         status = rtems_task_create(Task_name[TASKID_SWBD], TASK_PRIORITY_SWBD,
     482             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     483             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_SWBD]);
     484             :         DEBUG_CHECK_STATUS(status);
     485             :     }
     486             : 
     487             :     //*****
     488             :     // MISC
     489          18 :     if (status == RTEMS_SUCCESSFUL) // LOAD
     490             :     {
     491          18 :         status = rtems_task_create(Task_name[TASKID_LOAD], TASK_PRIORITY_LOAD,
     492             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES,
     493             :             &Task_id[TASKID_LOAD]);
     494             :         DEBUG_CHECK_STATUS(status);
     495             :     }
     496             : 
     497             : #ifdef DUMB_TASK_ENABLED
     498          18 :     if (status == RTEMS_SUCCESSFUL) // DUMB
     499             :     {
     500          18 :         status = rtems_task_create(Task_name[TASKID_DUMB], TASK_PRIORITY_DUMB,
     501             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES,
     502             :             &Task_id[TASKID_DUMB]);
     503             :         DEBUG_CHECK_STATUS(status);
     504             :     }
     505             : #endif
     506             : 
     507          18 :     if (status == RTEMS_SUCCESSFUL) // SCRUBBING TASK
     508             :     {
     509          18 :         status = rtems_task_create(Task_name[TASKID_SCRB], TASK_PRIORITY_SCRB,
     510             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     511             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_SCRB]);
     512             :         DEBUG_CHECK_STATUS(status);
     513             :     }
     514          18 :     if (status == RTEMS_SUCCESSFUL) // HOUS
     515             :     {
     516          18 :         status = rtems_task_create(Task_name[TASKID_HOUS], TASK_PRIORITY_HOUS,
     517             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     518             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_HOUS]);
     519             :         DEBUG_CHECK_STATUS(status);
     520             :     }
     521          18 :     if (status == RTEMS_SUCCESSFUL) // AVGV
     522             :     {
     523          18 :         status = rtems_task_create(Task_name[TASKID_AVGV], TASK_PRIORITY_AVGV,
     524             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     525             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_AVGV]);
     526             :         DEBUG_CHECK_STATUS(status);
     527             :     }
     528          18 :     if (status == RTEMS_SUCCESSFUL) // CALI
     529             :     {
     530          18 :         status = rtems_task_create(Task_name[TASKID_CALI], TASK_PRIORITY_CALI,
     531             :             RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
     532             :             RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT, &Task_id[TASKID_CALI]);
     533             :         DEBUG_CHECK_STATUS(status);
     534             :     }
     535             : 
     536          18 :     return status;
     537             : }
     538             : 
     539          18 : int start_recv_send_tasks(void)
     540             : {
     541             :     rtems_status_code status;
     542             : 
     543          18 :     status = rtems_task_start(Task_id[TASKID_RECV], recv_task, 1);
     544             :     DEBUG_CHECK_STATUS(status);
     545             : 
     546          18 :     if (status == RTEMS_SUCCESSFUL) // SEND
     547             :     {
     548          18 :         status = rtems_task_start(Task_id[TASKID_SEND], send_task, 1);
     549             :         DEBUG_CHECK_STATUS(status);
     550             :     }
     551             : 
     552          18 :     return status;
     553             : }
     554             : 
     555          18 : int start_all_tasks(void) // start all tasks except SEND RECV and HOUS
     556             : {
     557             :     /** This function starts all RTEMS tasks used in the software.
     558             :      *
     559             :      * @return RTEMS directive status codes:
     560             :      * - RTEMS_SUCCESSFUL - ask started successfully
     561             :      * - RTEMS_INVALID_ADDRESS - invalid task entry point
     562             :      * - RTEMS_INVALID_ID - invalid task id
     563             :      * - RTEMS_INCORRECT_STATE - task not in the dormant state
     564             :      * - RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task
     565             :      *
     566             :      */
     567             :     // starts all the tasks fot eh flight software
     568             : 
     569             :     rtems_status_code status;
     570             : 
     571             :     //**********
     572             :     // SPACEWIRE
     573          18 :     status = rtems_task_start(Task_id[TASKID_SPIQ], spiq_task, 1);
     574             :     DEBUG_CHECK_STATUS(status);
     575             : 
     576          18 :     if (status == RTEMS_SUCCESSFUL) // LINK
     577             :     {
     578          18 :         status = rtems_task_start(Task_id[TASKID_LINK], link_task, 1);
     579             :         DEBUG_CHECK_STATUS(status);
     580             :     }
     581             : 
     582          18 :     if (status == RTEMS_SUCCESSFUL) // ACTN
     583             :     {
     584          18 :         status = rtems_task_start(Task_id[TASKID_ACTN], actn_task, 1);
     585             :         DEBUG_CHECK_STATUS(status);
     586             :     }
     587             : 
     588             :     //******************
     589             :     // SPECTRAL MATRICES
     590          18 :     if (status == RTEMS_SUCCESSFUL) // AVF0
     591             :     {
     592          18 :         status = rtems_task_start(Task_id[TASKID_AVF0], avf0_task, LFR_MODE_STANDBY);
     593             :         DEBUG_CHECK_STATUS(status);
     594             :     }
     595          18 :     if (status == RTEMS_SUCCESSFUL) // PRC0
     596             :     {
     597          18 :         status = rtems_task_start(Task_id[TASKID_PRC0], prc0_task, LFR_MODE_STANDBY);
     598             :         DEBUG_CHECK_STATUS(status);
     599             :     }
     600          18 :     if (status == RTEMS_SUCCESSFUL) // AVF1
     601             :     {
     602          18 :         status = rtems_task_start(Task_id[TASKID_AVF1], avf1_task, LFR_MODE_STANDBY);
     603             :         DEBUG_CHECK_STATUS(status);
     604             :     }
     605          18 :     if (status == RTEMS_SUCCESSFUL) // PRC1
     606             :     {
     607          18 :         status = rtems_task_start(Task_id[TASKID_PRC1], prc1_task, LFR_MODE_STANDBY);
     608             :         DEBUG_CHECK_STATUS(status);
     609             :     }
     610          18 :     if (status == RTEMS_SUCCESSFUL) // AVF2
     611             :     {
     612          18 :         status = rtems_task_start(Task_id[TASKID_AVF2], avf2_task, 1);
     613             :         DEBUG_CHECK_STATUS(status);
     614             :     }
     615          18 :     if (status == RTEMS_SUCCESSFUL) // PRC2
     616             :     {
     617          18 :         status = rtems_task_start(Task_id[TASKID_PRC2], prc2_task, 1);
     618             :         DEBUG_CHECK_STATUS(status);
     619             :     }
     620             : 
     621             :     //****************
     622             :     // WAVEFORM PICKER
     623          18 :     if (status == RTEMS_SUCCESSFUL) // WFRM
     624             :     {
     625          18 :         status = rtems_task_start(Task_id[TASKID_WFRM], wfrm_task, 1);
     626             :         DEBUG_CHECK_STATUS(status);
     627             :     }
     628          18 :     if (status == RTEMS_SUCCESSFUL) // CWF3
     629             :     {
     630          18 :         status = rtems_task_start(Task_id[TASKID_CWF3], cwf3_task, 1);
     631             :         DEBUG_CHECK_STATUS(status);
     632             :     }
     633          18 :     if (status == RTEMS_SUCCESSFUL) // CWF2
     634             :     {
     635          18 :         status = rtems_task_start(Task_id[TASKID_CWF2], cwf2_task, 1);
     636             :         DEBUG_CHECK_STATUS(status);
     637             :     }
     638          18 :     if (status == RTEMS_SUCCESSFUL) // CWF1
     639             :     {
     640          18 :         status = rtems_task_start(Task_id[TASKID_CWF1], cwf1_task, 1);
     641             :         DEBUG_CHECK_STATUS(status);
     642             :     }
     643          18 :     if (status == RTEMS_SUCCESSFUL) // SWBD
     644             :     {
     645          18 :         status = rtems_task_start(Task_id[TASKID_SWBD], swbd_task, 1);
     646             :         DEBUG_CHECK_STATUS(status);
     647             :     }
     648             : 
     649             :     //*****
     650             :     // MISC
     651          18 :     if (status == RTEMS_SUCCESSFUL) // HOUS
     652             :     {
     653          18 :         status = rtems_task_start(Task_id[TASKID_HOUS], hous_task, 1);
     654             :         DEBUG_CHECK_STATUS(status);
     655             :     }
     656          18 :     if (status == RTEMS_SUCCESSFUL) // AVGV
     657             :     {
     658          18 :         status = rtems_task_start(Task_id[TASKID_AVGV], avgv_task, 1);
     659             :         DEBUG_CHECK_STATUS(status);
     660             :     }
     661             : 
     662             : #ifdef DUMB_TASK_ENABLED
     663          18 :     if (status == RTEMS_SUCCESSFUL) // DUMB
     664             :     {
     665          18 :         status = rtems_task_start(Task_id[TASKID_DUMB], dumb_task, 1);
     666             :         DEBUG_CHECK_STATUS(status);
     667             :     }
     668             : #endif
     669             : 
     670          18 :     if (status == RTEMS_SUCCESSFUL) // SCRUBBING
     671             :     {
     672          18 :         status = rtems_task_start(Task_id[TASKID_SCRB], scrubbing_task, 1);
     673             :         DEBUG_CHECK_STATUS(status);
     674             :     }
     675          18 :     if (status == RTEMS_SUCCESSFUL) // LOAD
     676             :     {
     677          18 :         status = rtems_task_start(Task_id[TASKID_LOAD], load_task, 1);
     678             :         DEBUG_CHECK_STATUS(status);
     679             :     }
     680          18 :     if (status == RTEMS_SUCCESSFUL) // CALI
     681             :     {
     682          18 :         status = rtems_task_start(Task_id[TASKID_CALI], calibration_sweep_task, 1);
     683             :         DEBUG_CHECK_STATUS(status);
     684             :     }
     685             : 
     686          18 :     return status;
     687             : }
     688             : 
     689          18 : rtems_status_code create_message_queues(void) // create the five message queues used in the software
     690             : {
     691          18 :     rtems_status_code status = RTEMS_SUCCESSFUL;
     692          18 :     rtems_status_code ret = RTEMS_SUCCESSFUL;
     693             :     rtems_id queue_id;
     694             : 
     695          18 :     ret = RTEMS_SUCCESSFUL;
     696          18 :     queue_id = RTEMS_ID_NONE;
     697             : 
     698             :     //****************************************
     699             :     // create the queue for handling valid TCs
     700          18 :     status = rtems_message_queue_create(misc_name[QUEUE_RECV], MSG_QUEUE_COUNT_RECV,
     701             :         CCSDS_TC_PKT_MAX_SIZE, RTEMS_FIFO | RTEMS_LOCAL, &queue_id);
     702             :     DEBUG_CHECK_STATUS(status);
     703          18 :     ret |= status;
     704             : 
     705             :     //************************************************
     706             :     // create the queue for handling TM packet sending
     707          18 :     status = rtems_message_queue_create(misc_name[QUEUE_SEND], MSG_QUEUE_COUNT_SEND,
     708             :         MSG_QUEUE_SIZE_SEND, RTEMS_FIFO | RTEMS_LOCAL, &queue_id);
     709             :     DEBUG_CHECK_STATUS(status);
     710          18 :     ret |= status;
     711             : 
     712             :     //*****************************************************************************
     713             :     // create the queue for handling averaged spectral matrices for processing @ f0
     714          18 :     status = rtems_message_queue_create(misc_name[QUEUE_PRC0], MSG_QUEUE_COUNT_PRC0,
     715             :         sizeof(asm_msg), RTEMS_FIFO | RTEMS_LOCAL, &queue_id);
     716             :     DEBUG_CHECK_STATUS(status);
     717          18 :     ret |= status;
     718             : 
     719             :     //*****************************************************************************
     720             :     // create the queue for handling averaged spectral matrices for processing @ f1
     721          18 :     status = rtems_message_queue_create(misc_name[QUEUE_PRC1], MSG_QUEUE_COUNT_PRC1,
     722             :         sizeof(asm_msg), RTEMS_FIFO | RTEMS_LOCAL, &queue_id);
     723             :     DEBUG_CHECK_STATUS(status);
     724          18 :     ret |= status;
     725             : 
     726             :     //*****************************************************************************
     727             :     // create the queue for handling averaged spectral matrices for processing @ f2
     728          18 :     status = rtems_message_queue_create(misc_name[QUEUE_PRC2], MSG_QUEUE_COUNT_PRC2,
     729             :         sizeof(asm_msg), RTEMS_FIFO | RTEMS_LOCAL, &queue_id);
     730             :     DEBUG_CHECK_STATUS(status);
     731          18 :     ret |= status;
     732             : 
     733          18 :     return ret;
     734             : }
     735             : 
     736          18 : rtems_status_code create_timecode_timer(void)
     737             : {
     738             :     rtems_status_code status;
     739             : 
     740          18 :     status = rtems_timer_create(timecode_timer_name, &timecode_timer_id);
     741             :     DEBUG_CHECK_STATUS(status);
     742             : 
     743          18 :     return status;
     744             : }
     745             : 
     746        1346 : rtems_status_code get_message_queue_id_send(rtems_id* queue_id)
     747             : {
     748             :     rtems_status_code status;
     749             :     rtems_name queue_name;
     750             : 
     751        1346 :     queue_name = rtems_build_name('Q', '_', 'S', 'D');
     752             : 
     753        1346 :     status = rtems_message_queue_ident(queue_name, 0, queue_id);
     754             :     DEBUG_CHECK_STATUS(status);
     755             : 
     756        1346 :     return status;
     757             : }
     758             : 
     759          36 : rtems_status_code get_message_queue_id_recv(rtems_id* queue_id)
     760             : {
     761             :     rtems_status_code status;
     762             :     rtems_name queue_name;
     763             : 
     764          36 :     queue_name = rtems_build_name('Q', '_', 'R', 'V');
     765             : 
     766          36 :     status = rtems_message_queue_ident(queue_name, 0, queue_id);
     767             :     DEBUG_CHECK_STATUS(status);
     768             : 
     769          36 :     return status;
     770             : }
     771             : 
     772         436 : rtems_status_code get_message_queue_id_prc0(rtems_id* queue_id)
     773             : {
     774             :     rtems_status_code status;
     775             :     rtems_name queue_name;
     776             : 
     777         436 :     queue_name = rtems_build_name('Q', '_', 'P', '0');
     778             : 
     779         436 :     status = rtems_message_queue_ident(queue_name, 0, queue_id);
     780             :     DEBUG_CHECK_STATUS(status);
     781             : 
     782         436 :     return status;
     783             : }
     784             : 
     785         436 : rtems_status_code get_message_queue_id_prc1(rtems_id* queue_id)
     786             : {
     787             :     rtems_status_code status;
     788             :     rtems_name queue_name;
     789             : 
     790         436 :     queue_name = rtems_build_name('Q', '_', 'P', '1');
     791             : 
     792         436 :     status = rtems_message_queue_ident(queue_name, 0, queue_id);
     793             :     DEBUG_CHECK_STATUS(status);
     794             : 
     795         436 :     return status;
     796             : }
     797             : 
     798         436 : rtems_status_code get_message_queue_id_prc2(rtems_id* queue_id)
     799             : {
     800             :     rtems_status_code status;
     801             :     rtems_name queue_name;
     802             : 
     803         436 :     queue_name = rtems_build_name('Q', '_', 'P', '2');
     804             : 
     805         436 :     status = rtems_message_queue_ident(queue_name, 0, queue_id);
     806             :     DEBUG_CHECK_STATUS(status);
     807             : 
     808         436 :     return status;
     809             : }
     810             : 
     811             : /**
     812             :  * @brief update_queue_max_count returns max(fifo_size_max, pending_messages + 1)
     813             :  * @param queue_id
     814             :  * @param fifo_size_max
     815             :  */
     816       32108 : void update_queue_max_count(rtems_id queue_id, unsigned char* fifo_size_max)
     817             : {
     818             :     DEBUG_CHECK_PTR(fifo_size_max);
     819             :     uint32_t count;
     820             :     rtems_status_code status;
     821             : 
     822       32108 :     count = 0;
     823             : 
     824       32108 :     status = rtems_message_queue_get_number_pending(queue_id, &count);
     825             :     DEBUG_CHECK_STATUS(status);
     826             : 
     827       32108 :     count = count + 1;
     828             : 
     829       32108 :     if (status != RTEMS_SUCCESSFUL)
     830             :     {
     831             :         LFR_PRINTF("in update_queue_max_count *** ERR = %d\n", status);
     832             :     }
     833             :     else
     834             :     {
     835       32108 :         if (count > *fifo_size_max)
     836             :         {
     837         122 :             *fifo_size_max = count;
     838             :         }
     839             :     }
     840       32108 : }
     841             : 
     842             : /**
     843             :  * @brief init_ring initializes given ring buffer
     844             :  * @param ring array of nodes to initialize
     845             :  * @param nbNodes number of node in the ring buffer
     846             :  * @param buffer memory space given to the ring buffer
     847             :  * @param bufferSize size of the whole ring buffer memory space
     848             :  *
     849             :  * @details This function creates a circular buffer from a given number of nodes and a given memory
     850             :  * space. It first sets all nodes attributes to thier defaults values and associates a portion of
     851             :  * the given memory space with each node. Then it connects each nodes to build a circular buffer.
     852             :  *
     853             :  * Each node capacity will be bufferSize/nbNodes.
     854             :  *
     855             :  * https://en.wikipedia.org/wiki/Circular_buffer
     856             :  */
     857         780 : void init_ring(
     858             :     ring_node ring[], unsigned char nbNodes, volatile int buffer[], unsigned int bufferSize)
     859             : {
     860             :     DEBUG_CHECK_PTR(ring);
     861             :     DEBUG_CHECK_PTR(buffer);
     862             :     unsigned char i;
     863             : 
     864             :     //***************
     865             :     // BUFFER ADDRESS
     866        3696 :     for (i = 0; i < nbNodes; i++)
     867             :     {
     868        2916 :         ring[i].coarseTime = INT32_ALL_F;
     869        2916 :         ring[i].fineTime = INT32_ALL_F;
     870        2916 :         ring[i].packet_id = INIT_CHAR;
     871        2916 :         ring[i].status = INIT_CHAR;
     872        2916 :         ring[i].buffer_address = (volatile void*)&(buffer[i * bufferSize]);
     873             :     }
     874             : 
     875             :     //*****
     876             :     // NEXT
     877         780 :     ring[nbNodes - 1].next = &ring[0];
     878        2916 :     for (i = 0; i < nbNodes - 1; i++)
     879             :     {
     880        2136 :         ring[i].next = &ring[i + 1];
     881             :     }
     882             : 
     883             :     //*********
     884             :     // PREVIOUS
     885         780 :     ring[0].previous = &ring[nbNodes - 1];
     886        2916 :     for (i = 1; i < nbNodes; i++)
     887             :     {
     888        2136 :         ring[i].previous = &ring[i - 1];
     889             :     }
     890         780 : }

Generated by: LCOV version 1.14