Linking different include files in the same project

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Linking different include files in the same project

4,230 Views
Andrey
Contributor III
    I've written code for a microcontroller that controls some things. We have deployed three systems. Later some hardware was changed and the sensor values are just a bit different.

I have my sensor values as global variables in the include file and can modify them before I compile the project. However we don't want to have a separate CodeWarrior project for every customer. How do I link different include files in the same project. The estimated number of systems to be deployed and maintained is 30.

Any ideas appreciated,
Andrey
Labels (1)
0 Kudos
7 Replies

986 Views
Lundin
Senior Contributor IV
Another suggestion is to never allocate anything in a h-file. Allocating variables inside h-files is considered bad programming practice and is forbidden by well-known coding standards such as MISRA-C.

The main reason is to avoid spaghetti code, but there is also a very good practical reason for this: if you allocate a variable in a h-file and then include that h-file from several c-files, you will most likely get linker errors. This is true for Codewarrior and for many other linkers as well.

The quick and (just slightly less) dirty way is to set every variable in the h-file as extern, and then let the actual allocation be done in a corresponding c file.

The good, clean way is to declare the variables as static inside the c-file and then access them through functions, so called private encapsulation.

To answer the question, this is what I would do:

/* h-file */
#ifndef _MY_HEADER_H
#define _MY_HEADER_H

#define CUSTOMER_X
#define CUSTOMER_Y
#define CUSTOMER_Z
...

#define CURRENT_CUSTOMER CUSTOMER_X
/* this is the compiler switch, it is the only thing you will need to change */


void init (void);

int get_some_data (void);

#endif /*  _MY_HEADER_H */


/* c-file */
#include "my_header.h"

static int some_data;
static int some_other_data;
...


void init (void)
{
  #if CURRENT_CUSTOMER == CUSTOMER_X
    some_data = 123;
    some_other_data = 456;
  #elif CURRENT_CUSTOMER == CUSTOMER_Y
    some_data = 111;
    some_other_data = 222;
  #elif ... /* and so on for each customer */

  #else
    some_data = default_value;
    some_other_data = default_value;
  #endif
}


int get_some_data (void)
{
  return some_data;
}



/* main.c, identical no matter customer */
#include "my_header.h"

int main()
{
  int x;

  init();
  x = get_some_data();
  do_things_with(x);
}


Message Edited by Lundin on 2008-04-01 11:14 AM
0 Kudos

986 Views
Andrey
Contributor III
Thanks. I wanted the maintanance process to be low. I was even considering writing a one time calibration values into the flash memory when the system is first set up and then accessing them from the main program.
0 Kudos

986 Views
mke_et
Contributor IV
If you're going to embed diag or debug calibration values, consider putting them in a 'packet' or a 'frame' that is scanned for. That way they can easily be overwritten.
Just put a 'tag' at the front of your 'packet' to say "I'm Valid!" kind of thing. Then in your program have it walk the area where you put your frames. If you find an FF as the tag, you know the frame is unused, and if you got there it means there's nothing saved. If you find a 'tag' value, then use the data in the frame. If you find a 00, then you know that the data in the frame was invalidated and to keep looking. That way in debug/development, you can put data you can easily remove, or invalidate and add new to, without having to go back and rebuild/reflash. The limitation is how much room you want to put in your flash for this capability.
0 Kudos

986 Views
mke_et
Contributor IV
Just include the files...

For example, in my main page, I have something similar to the following code

rtc_build equ 1 ; Set to 1 if factory built with rtc option
Exp_reset equ 0 ; Set if special hardware conditions

include_super equ 1 ; Set to include the 'generic' main
include_wx equ 1 ; Set to include the wx package
include_comp equ 1 ; Set to include Comp package
include_sim equ 0 ; Set to include Sim package

And so on... I also used the same scheme to inclued 'dummy data' to preload my build so that I can easily debug software instead of making the unit get it from live testing.

; This can make a dummy calibration for the WX Simulator
; as well as make a number of 'test' data frames
devel equ 1 ; Set to 0 means no debug data
; Set to 1 means include simulator calibration data
; Set to 2 also includes debug info and dummy data

Then in my routines, I can conditional test and put includes of whole file structures int the code. The only thing to be careful of is if you leave something OUT of a build, it must be benign. That is, you can't have unreferenced stubs. With most dependencies, I set it up so that they install for items that are 'tested' to install, so if they are not present, then the software won't try to use them. Other times, I will use an if/else scheme to either install a small module with dummy but valid stubs vs true definitions with jumps or variables.

Sometimes it was easiest to make a simple if xxx install 'xxx.inc' endif block, and then in the xxx.inc file have it do all it's includes, that way I have a simple and single statement for a whole slew of code. Then in the mcp of Codewarrior, I created a 'tree' where I could put all the include modules for each function under a branch of the tree to keep things straight.

Remember, these are NOT setting program variables, they are setting build variables, so don't try to use them in your program!
0 Kudos

986 Views
Andrey
Contributor III
Thanks to averyone for advices. I'll see which fits my situation best.
0 Kudos

986 Views
allawtterb
Contributor IV
The way I understand it you have some global variables that are initialized in a .h file but you need different initialization values for different customers.  If this is the case how about doing something like this:
 
In your current header file/files initialize the variable to a predefined value:
Code:
...#include "sensor_inits.h"...unsigned char Sensor_Value1 = SENSOR_VALUE1_INIT;

 
Then in sensor_inits.h the initialization value are defined and selected by a define at the top of the header file:
Code:
#define CUSTOMER_BOB...#ifdef CUSTOMER_BOB   SENSOR_VALUE1_INIT   1234   ...#endif#ifdef CUSTOMER_JIM   SENSOR_VALUE1_INIT   1246   ...#endif

 This way you can keep this ugly table of init's in one header file incase multiple header files need to access it.  Obvisouly you will still have to have seperate binaries for each customer, not sure if this is the sort of thing you were looking for. 

 
0 Kudos

986 Views
J2MEJediMaster
Specialist I
Some suggestions:

1) Have a header file that includes the other header files, and use conditional compilation flags so that only one of the header files is included when you do the build.

2) In CodeWarrior, make a build target for every product. A build target should be named for the product whose code that it generates. Each build target will draw on the same source files but then use only of the the many separate header files you have. To do a build for a particular product, pick its name from the build targets list and have at it. The separate build targets also allow you to tweak other build settings, and have CW build an ELF or S19 output file with a unique name.

---Tom

0 Kudos