简体   繁体   中英

Multiple Source Files in C

I'm currently working on a program that is implementing multiple C source files. This is the first project where I'm doing this and have had a lot of questions. So sorry for all of the recent questions, but I truly appreciate the help!

I have a main source file with a main function. Within this main function, I have an operating loop that calls 'high-level' functions which are essentially subroutines. For example, I have a function called ReadInputs() that is found within 'ReadInputs.c'. I have broken it down this way strictly for organizational purposes.

I have a couple questions:

I heard that it is good practice to have header files associated with each source file. Because of this, I could have file titled 'ReadInputs.h' which contains the prototype for the ReadInputs() function found in 'ReadInputs.c' My first question, is it necessary to have such a simple small header file? As of now, 'ReadInputs.h' only includes a single prototype. Is it possible to include this prototype in an overall header file? In my case, I have an overall header file titled 'Definitions.h' which includes the prototype ReadInputs.

Question 2: Because I want to share variables between each source file, I am using the following method:

I declare a variable in 'main.c' called Var. In the 'Definitions.h' header file, I extern Var. In every other source file, I #include Definitions.h. I believe this will allow the variable to be shared globally. Is this a correct assumption?

Sorry for the wall of text. Any help is appreciated!

For your first question, yes, this happens frequently.

For example, consider a set of files implementing a balanced tree, with different C source files for insert, delete find and so on. This is often done for better build processes, such as only having to recompile the insert file if that's the only thing you've changed.

However, you want the users of your code to only have to include a single btree.h so you just lump all the function prototypes (and other things) into there.

So you'll end up with something like:

btree.h            - public stuff
btree_priv.h       - private stuff
btreeInsert.c      - individual functions
btreeDelete.c
btreeFind.c
btreeRebalance.c
btreeIterate.c

with the btree_priv.h file holding enough information, above and beyond the user header btree.h , to allow the individual functions in their own source files to know about each other and the "hidden" data structures.

You would then usually package all the compiled "individual function" object files into a library, then distribute the library and public header.

And yes for the second question as well, but with a slight caveat. The extern will explicitly declare the variable so that other translation units (source files) know about it. But it's the act of (for example) declaring it at file level as a non-static that will make it visible at link time, to all files you link with.

  1. Prototype, structure etc should be in header file . Its a good practice and industry follows this rule. as your code base increases you will add different functions your header file will also grows, so you need not to worry about that.

  2. Yes you are correct.

three files are included below
first the top level makefile
then the bottom level makefile
then an example source file

Note: the makefiles are using 'sed' for
      the creation of the dependency files
      however, the gcc compiler has 
      appropriate parameters that
      can make the operation much simplier

in general, the way to use this is:
-- in the top level directory
   make -f makefile -dDEBUG > make.out
   then examine the file make.out to search for any compile/link errors

Note: I do not know why some lines are being displayed in large/bold font

--- file: makefile.mak
SHELL = /bin/sh


#  note: this makefile.mak needs to be run from the ./src directory
# of the GOT4 directory tree


SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)


MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      :=  mv

LDFLAGS :=  -L/usr/local/lib -L/usr/lib -L/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -W

#CPPFLAGS += =MD

LIBS    :=  -lssl -ldl -lrt -lz -lc -lm



.PHONY: AllDirectories
# the following statement needs to be edited as 
# subdirectories are added/deleted/re-named
#AllDirectories := \
#    Command_Configuration \
#    Communication \
#    Main_Scheduler \
#    Retrieve_CDS_Log \
#    Retrieve_EventRecorder_Log \
#    Retrieve_GPS \
#    Retrieve_QES_Alarm_Log \
#    Retrieve_QES_RealTime \
#    Write_CDS_Log

AllDirectories :=  \
    Main_Scheduler \
    Communication  \
    Retrieve_GPS   \
    Test_Communication_Dev 



.PHONY: all
#all: $(OBJ) $(AllDirectories)
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak name=Tsk_$d all ); )

all: $(OBJ) $(AllDirectories)
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d all ); )



#
# create dependancy files
#
%.d: %.c
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



#
# compile the .c file into .o files using the compiler flags
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
#clean: $(AllDirectories)
#   # ========== start clean activities ==========
#   rm -f *.o
#   rm -f $(name).map
#   rm -f $(name)
#   rm -f *.d
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak clean ); )
#   # ========== end clean activities ==========

clean: $(AllDirectories)
    # ========== start clean activities ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    rm -f ../bin/Tsk_*
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d clean ); )
    # ========== end clean activities ==========



.PHONY: install
#install: $(AllDirectories)
#   # ========== start install activities ==========
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak clean ); )
#   # ========== end install activities ==========

install: $(AllDirectories)
    # ========== start install activities ==========
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d install ); )
    # ========== end install activities ==========



# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif

then the makefile (located in the top level directory)
that creates each of the sub directory executables

one at a time, as it is invoked by the top level makefile

-- file: makefile.bot
SHELL = /bin/sh


BINDIR  :=  /home/user/bin


.PHONY: all
all : $(BINDIR)/$(name) ../makefile.mak ../makefile.bot


#
# macro of all *.c files 
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c 
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)


COMMON_OBJ := $(wildcard ../*.o)
#COMMON_SRC := $(wildcard ../*.c)
#COMMON_OBJ := $(COMMON_SRC:.c=.o)
#COMMON_DEP := $(COMMON_SRC:.c=.d)
#COMMON_INC := $(COMMON_SRC:.c=.h)

MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      := mv

LDFLAGS :=  -L/usr/local/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -W

#CPPFLAGS += =MD

#LIBS    :=  -lidn -lssl -ldl -lrt -lz -lc -lm
LIBS    :=   -lssl -ldl -lrt -lz -lc -lm



#
# link the .o files into the executable 
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ) $(COMMON_OBJ) ../makefile.mak ../makefile.bot
    #
    # ======= $(name) Link Start =========
    $(CC) $(LDFLAGS) -o $@ $(OBJ) $(COMMON_OBJ) $(LIBS)
    # ======= $(name) Link Done ==========
    #



# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
    #
    # ======= $(name) Copy Start =========
    sudo $(CP) $(name) $(BINDIR)/.
    # ======= $(name) Copy Done ==========
    #



#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c 
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



# 
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
clean: 
    # ========== CLEANING UP ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    # ========== DONE ==========



.PHONY: install
install: all

# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif

and finally, a typical file, showing the many local and system headers used
note: although the usage was trivial in this file, 
      the doxygen documentation utility
      was used in the process of automatic document creation

which is where the '@' lines were used.

-- file: Main_Scheduler.c
/**
    @file   Main_Scheduler.c
    @brief  contains functions to control 'deleted'
    @author Richard Williams
    @date   June 27, 2012
*/


/*  SIRT issues applied to this file:
    SIRT issue ### -

*/


/* *************** Included files ************************************* */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>    // for system() and itoa() utilities
#include <stdarg.h>    // for va_list(), etc
#include <string.h>    // string handling utilities
#include <semaphore.h> // semaphores handling utilities

#include <fcntl.h>     // symbolic definitions for flags bits
#include <sys/types.h> // contains definitions of data types used in system calls
#include <sys/socket.h>// type definitions (I.E. struct sockaddr_in)
#include <sys/stat.h>  // symbolic definitions for permission bits and open()
#include <sys/ipc.h>   // ipc interface utilities

#include <sys/shm.h>   // shared memory utilities
#include <arpa/inet.h> // defines INADDR_ANY, etc

#include <errno.h>     // for accessing errno and related functions
#include <stdbool.h>   // define true, false, bool
#include <time.h>      // prototypes for time() and related functions


    // contains common data type definitions
#include "../GOT4_Types.h"

    // contains data definitions for ON and OFF
#include "../CdsDefines.h"

    // contains prototypes for Interprocess Communication
#include "../Common_Interprocess_Communication.h"

    // contains prototypes for UDP utility functions
#include "../Common_UDP_Utilities.h"

    // contains prototypes and enums for configuration operations
#include "../CommonConfiguration.h"

    // contains prototypes for writing to CDS Log file
#include "../CommonWriteCdsLog.h"

    // contains prototypes for handling stderr files
#include "../CommonDateFunctions.h"

    // contains prototypes and enums for watchdog operations
#include "Main_Scheduler_Watchdog.h"

    // contains prototypes and enums for command operations
#include "Main_Scheduler_Command.h"

    //contains prototypes for globally visible functions and data types in this file
#include "Main_Scheduler.h"



/* *************** File static functions ****************************** */
static enum enumReturnStatus Main_Scheduler_StartTask( INT32 taskSelector );
static enum enumReturnStatus Main_Scheduler_StopTask ( INT32 taskSelector );

static enum enumReturnStatus Main_Scheduler_Task__Initialize( void );
static enum enumReturnStatus Main_Scheduler_Config__Initialize( BOOL bFirstTime );



#define dMAX_IPC_PAYLOAD ( 256 )
#define dMAX_SYSTEM_BUF_LENGTH ( 256 )

/* *************** Global Variables *********************************** */



/* *************** File Static Variables ****************************** */
static BOOL   ActiveTaskTable[ eMaxTasks ] = { FALSE };


// used to format the payload of messages to write to IPC
//static char   inITC_payload[ dMAX_IPC_PAYLOAD ];
static char   outITC_payload[ dMAX_IPC_PAYLOAD ];

// used for executing commands in shell
static char   systemCommand[dMAX_SYSTEM_BUF_LENGTH] = {0x00};


// used to enable kicking the hardware watchdog
static BOOL   flgWatchdogKick = TRUE;



/* *************** Code *********************************************** */



/**
  @fn INT32 main(INT32 argc, char *argv[])
  @brief -
  @param [in] argc -
  @param [in] argv -
  @return INT32 -

  :

 */
INT32 main( INT32 argc __attribute__ ((unused)), char* argv[] )
{
    enum enumReturnStatus returnStatus;

    INT32  taskSelector; // loop counter
    INT32  CommandValue; // command to send to sub task

    struct structWriteIPC WriteIPC;

    struct timespec       timeout;  // timeout for interprocess communication call
    unsigned              priority; // message priority for sending messages, 5 is low, 10 is high

    char  *pBaseName =    gnu_basename( argv[ 0 ]); // get name of this file

    remove_all_IPC();  // Only done from Main Scheduler, clears out all external (OS) interprocess buffers

    Initialize_IPC();
    itc_payload_size_init();

    set_TaskSelector( eTask_Main_Scheduler );

    set_pTask_NameString( eTask_Main_Scheduler, pBaseName );

    // select initial file to receive stderr messages
    CommonDateFunctions_stderr( pBaseName );

    // initialize the logging subsystem, indicating not owner of resource
    CommonWriteCdsLog__Initialize();

    if( atexit( release_CommonConfiguration ) )
    { // then setting exit function failed

        CommonWriteCdsLog( eLL_Critical,
            get_pFormatString( eFormat_CFFL_string_string ),
            __FILE__, __LINE__,
            "LibFunc:atexit()",
            strerror(errno) );

        system( "sync; sync;" );
        exit( EXIT_FAILURE);
    }


    /*
     * ***************************************************************
     * implied else (atexit() successful)
     *****************************************************************
     */


    // read .config file and initialize database
    Main_Scheduler_Config__Initialize( TRUE ); // true=first time

    returnStatus = Main_Scheduler_Task__Initialize();


    // pass tracking message to CDS log file
    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_string ),
        __FILE__, __LINE__,
        "Entering main execution loop" );


    /*
    *********************************************************************
    * main operating loop starts here
    * *******************************************************************
    */


    flgWatchdogKick = true;
    while( flgWatchdogKick )
    {
        // step to next stderr file at midnight, otherwise do nothing
        CommonDateFunctions_stderr( pBaseName );

        // 11 kick the CPU watchdog
        Main_Scheduler_wd_kick();



        // 12) kick the external watchdog
        //todo:

        for( taskSelector=1; // step by main_scheduler task=(0)
             taskSelector<eMaxTasks ;
             taskSelector++ )
        {

            if( !ActiveTaskTable[  taskSelector ] )
            { // then selected task not configured to run

                continue; // step to next itteration of inner loop
            }


            /*
             *********************************************************************
             * implied else, task-of-interest ready to run
             * *******************************************************************
             */


            // throttle execution rate of sub tasks
            step_Interval_counter( taskSelector );

            if( is_Interval_expired( taskSelector) )
            { // then, kick related task

                reset_Interval_counter( taskSelector );

                // note: get_Task_command() handles all errors
                CommandValue = get_Task_command( taskSelector );


                if( eTask_Retrieve_GPS == taskSelector )
                {

                    CommandValue = eTaskCommand_GetGPSreport; // periodic event
                }


fprintf( stdout,"DEBUG:File:%s\n\t--> ATTEMPTING TO KICK cmd#:%d TASK# %d\n", __FILE__, CommandValue, taskSelector );
fflush( stdout );

fprintf( stdout,"DEBUG:File:%s\n\t--> task:%d, command;%d\n\n", __FILE__, taskSelector, CommandValue );
fflush( stdout );

                memset( outITC_payload, 0x00, sizeof(outITC_payload) );
                ((struct structITC_Command*)outITC_payload)->ITC_Receiver = taskSelector;
                ((struct structITC_Command*)outITC_payload)->ITC_Command  = CommandValue;

                WriteIPC.TaskSelector    = taskSelector;
                WriteIPC.ITC_MsgType     = eITC_MsgType_Command;
                WriteIPC.ITC_PayLoadSize = 2*sizeof(INT32);
                WriteIPC.pITC_Payload    = outITC_payload;


fprintf( stdout,"DEBUG:File:%s\n\t--> calling write_ITC_Record_To_IPC() with taskSelector:%d\n\n", __FILE__, taskSelector );
fflush( stdout );


                clock_gettime(CLOCK_REALTIME, &timeout);   // gets current time
                timeout.tv_sec +=  1;                      // adds one second to current time for timeout
                priority        = 10;
                returnStatus    = write_ITC_Record_To_IPC( &WriteIPC, &timeout, priority );

fprintf( stdout,"DEBUG:File:%s\n\t--> returned from write_ITC_Record_To_IPC()\n\n", __FILE__ );
fflush(  stdout );

                if( eRS_Success == returnStatus )
                { // then. write successful

fprintf( stdout,"DEBUG:File:%s\n\t--> SUCCESFULLY SENT MSG TO TASK#%d\n", __FILE__, taskSelector );
fflush(  stdout );

                    // overwrite command so not executed again.
                    set_Task_command( taskSelector, eTaskCommand_DoNothing );
                }
else
{
fprintf( stdout,"DEBUG:File:%s\n\t--> FAILED TO SEND MSG TO TASK#%d   error is:%d\n", __FILE__, taskSelector, returnStatus );
fflush(  stdout );
}
            } // endif( is interval expired )
        } // end for( each task )

        // wait a second before going through the above again
        sleep(1);


        // 16) get any new commands
        // rkw: comment until ready to receive commands from CommandConfiguration task
        // Main_Scheduler_Command();
    } // end while( flgWatchdogKick )


    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_Exiting_Status ),
        __func__, __FILE__, EXIT_SUCCESS );

    return( EXIT_SUCCESS );
} // end main()



static enum enumReturnStatus Main_Scheduler_StartTask( INT32 taskSelector )
{
    char *pTask_NameString;
    int   systemReturn;


    if( is_taskSelector_Valid( taskSelector) )
    {

        // note: task_nameString is setup during call to Main_Scheduler_Config__Initialize()
        pTask_NameString = get_pTask_NameString( taskSelector );

        if( NULL != pTask_NameString )
        { // then get_pTask_NameString successful

            memset( systemCommand, 0x00, sizeof(systemCommand) );

            // set the command string
            // set to run in background so will get execution back
            sprintf( systemCommand, "%sTsk_%s &", dEXECUTION_DIR, pTask_NameString );

            // pass tracking message to CDS log file
            CommonWriteCdsLog( eLL_Critical, // Critical to assure will be written to log file
                get_pFormatString( eFormat_CFFL_string ),
                __FILE__, __LINE__,
                systemCommand );

fprintf( stdout,"DEBUG:File:%s\n\t--> starting subsytem: %s\n", __FILE__, systemCommand );
fflush( stdout );

            // run the command ( which starts the task )
            systemReturn = system( systemCommand );

            if (( 0 != systemReturn ) )
            {
                CommonWriteCdsLog( eLL_Critical,
                    get_pFormatString( eFormat_CFFL_digit_string ),
                    __FILE__, __LINE__, systemReturn,
                    "system() call failed." );

                system( "killall Tsk*" );
                system("sync;sync;");
                exit( EXIT_FAILURE );
            }

            return( eRS_Success ); // indicate operation successful
        }

        //else
        //{ // else, get_pTask_NameString() failed
          // which means the task is not configured in the .config file

        //    CommonWriteCdsLog( eLL_Error,
        //        get_pFormatString( eFormat_EFFL_digit_string ),
        //        __FILE__, __LINE__,
        //        taskSelector,
        //        "=taskSelector: Function:get_pTask_NameString() failed" );
        //} // endif( got task name string )
    }

    else
    { // else, bad parameter

        CommonWriteCdsLog( eLL_Error,
            get_pFormatString( eFormat_EFFL_digit_string ),
            __FILE__, __LINE__,
            taskSelector,
            "=taskSelector: Parameter out of range" );
    }

    return( eRS_Failure ); // indicate error occurred
} // end Main_Scheduler_StartTask()



static enum enumReturnStatus Main_Scheduler_StopTask ( INT32 taskSelector )
{
    char systemCommand[ 256 ];
    char *pTask_NameString;



    if( is_taskSelector_Valid( taskSelector ) )
    {
        memset( systemCommand, 0x00, sizeof(systemCommand) );
        pTask_NameString = get_pTask_NameString( taskSelector );

        if( NULL != pTask_NameString )
        { // then, get_pTask_NameString successful

            sprintf( systemCommand, "killall %sTsk_%s", dEXECUTION_DIR, pTask_NameString );

            // pass tracking message to CDS log file
            CommonWriteCdsLog( eLL_Critical,
                get_pFormatString( eFormat_CFFL_string ),
                __FILE__, __LINE__,
                systemCommand );

            // run the command, which kills the task
            system( systemCommand );

            return( eRS_Success ); // indicate success
        }
    }

    else
    { // else, bad parameter

        CommonWriteCdsLog( eLL_Error,
            get_pFormatString( eFormat_EFFL_digit_string ),
            __FILE__, __LINE__,
            taskSelector,
            "=taskSelector: Parameter out of range" );
    }


    return( eRS_Failure ); // indicate problem occurred
} // end Main_Scheduler_StopTask()



static enum enumReturnStatus Main_Scheduler_Config__Initialize( BOOL bFirstTime )
{
    enum enumReturnStatus returnStatus = eRS_Success;


    // Note: check for first time avoids trying to 'free() un-initialized char pointers
    if( !bFirstTime )
    {
        release_CommonConfiguration();
    }

    clear_CommonConfiguration();

    acquire_CommonConfiguration( eDivision_Main_Scheduler );

    return( returnStatus );
} // end Main_Scheduler_Config__Initialize()



static enum enumReturnStatus Main_Scheduler_Task__Initialize( void )
{
    enum enumReturnStatus returnStatus = eRS_Success;

    INT32 taskSelector;



    // 2) reset the IOC card
    memset( systemCommand, 0x00, sizeof(systemCommand) );
    strcat( systemCommand, "/usr/bin/diag_client -s 172.20.100.17:23 'reset'" );
    //rkw for testing system( systemCommand );



    // 3) reset the DIO card
    memset( systemCommand, 0x00, sizeof(systemCommand) );
    strcat( systemCommand, "/usr/bin/diag_client -s 172.20.100.18:23 'reset'" );
    //rkw for testing system( systemCommand );



    /*
    *********************************************************************
    * start task execution
    * *******************************************************************
    */


    // pass tracking message to CDS log file
    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_string ),
        __FILE__, __LINE__,
        "kill any running Task" );

    for( taskSelector=1; // task 0 is Main_Scheduler (I.E. this task)
         eMaxTasks > taskSelector;
         taskSelector++ )
    {
        Main_Scheduler_StopTask( taskSelector );
    }


    // pass tracking message to CDS log file
    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_string ),
        __FILE__, __LINE__,
        "Entered: Start Task Execution Loop" );

    for( taskSelector=1; // task 0 is Main_Scheduler (I.E. this task)
         eMaxTasks > taskSelector;
         taskSelector++ )
    {

        returnStatus = Main_Scheduler_StartTask( taskSelector );

        if( eRS_Success == returnStatus )
        {
            ActiveTaskTable[ taskSelector ] = TRUE;
        }

        else
        { // else, task not configured

            ActiveTaskTable[ taskSelector ] = FALSE;
        }
    } // end for( each possible task )




    /*
    *********************************************************************
    * initialization loop
    * *******************************************************************
    */


    // 8) set task initializer command for each task

    for( taskSelector=1; // step by Main_Scheduler task=0
         taskSelector>=eMaxTasks;
         taskSelector++ );
    {

        set_Task_command( taskSelector, eTaskCommand_Initialize );
    } // end for( each task to initialize )



    /*
    *********************************************************************
    * initialze CPU card and external watchdog operations
    * *******************************************************************
    */


    // 9) initialize the CPU watchdog
    Main_Scheduler_wd_init();
    Main_Scheduler_wd_enable();

    // 9.1 set kickWatchdog flag to indicate watchdog is to be kicked
    flgWatchdogKick = TRUE;


    // 10) initialize throttle timers
    // pass tracking message to CDS log file
    CommonWriteCdsLog( eLL_Info,
        get_pFormatString( eFormat_IFFL_string ),
        __FILE__, __LINE__,
        "resetting all timers" );

    for( taskSelector=0;
         taskSelector<eMaxTasks ;
         taskSelector++ )
    {

        reset_Interval_counter( taskSelector );
    }

    return( returnStatus );
} // end Main_Scheduler_Task__Initialize()



/* ******************************************************************** **
** End of source file: Main_Scheduler.c
** ******************************************************************** */


I know the above examples contain the information that you need
for your project.  
But it may be a bit difficult  to decyper without knowing 
the makefile syntax and builtin calls
  1. Yes, it is better to use separate header files/.inc files for each source files. The industry follows the rule to either have a .h file or .inc file for each .c file. Function prototype , enums , macros , structures etc. should be declared in .h or .inc file.

  2. Yes , you are correct in using the way global variables should be used. Always declare global variables in .c file , avoid declaring global variables in any .h files because in some compilers it might lead to multiple definitions error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM