4

I have a se of embedded C for a TI processor that need to be unit tested.
For target compilation IAR is used but i am running the tests on a Win7 machine using MinGW GCC.

In the C code there are functions containing state machines that sometimes need to be reset between tests. These state machines often keep their state variable locally static, making that task difficult if not impossible.

I'm not very C++ class savvy but i had an idea about "importing" the C functions into a wrapping C++ class as memberfunctions making it possible to just create a new object whenever a reset i needed. The code below is non functional but it illustrates my idea.

in main.cpp:

    #include "statemachine.h"

    using namespace std;

    class stateMachineWrapper {
    public:
        extern void stateMachine(void);
    };

    int main() {
        stateMachineWrapper myObject;

        myObject.stateMachine();

        myObject.stateMachine();

        stateMachineWrapper myNewObject;

        myNewObject.stateMachine();

        myNewObject.stateMachine();

        return 0;
    }

in statemachine.h:

    void stateMachine(void);

in statemachine.c:

    #include <stdio.h>

    void stateMachine(void)
    {
      static int myState = 0;

      switch(myState)
      {
      case 0:
      {
        printf("Init State");
        myState = 1;
        break;
      }
      case 1:
      {
        printf("Second state");
        break;
      }
      default:
      {
        printf("Default");
        break;
      }
      }
    }

Alterations to the statemachine.c/.h is not encouraged since it can be considered "legacy".
Any other solutions is of course welcome as well!

Enok82
  • 163
  • 1
  • 13

2 Answers2

2

The wrapping won't help. The C++ code has no way of reaching the internal static variable inside the state machine written in C.

One solution is to use dynamic code loading for the C parts, that will make the early initialization code and clear the static variable.

You could also split the tests into multiple executables, that has the same effect but probably larger overhead (=tests will run more slowly).

unwind
  • 391,730
  • 64
  • 469
  • 606
  • What i was hoping to achieve was not access to the `static` variable but rather a way to create a new, fresh instance of the statemachine. Yes the multiple executives way has occured to me but as you say it will take magnitudes of extra time versus just performing another run on a new object. – Enok82 Nov 04 '15 at 11:26
  • @Enok82 But there is no concept of an "instance" with this kind of C code. A global variable is a global variable, forever. It will be initialized by the startup code (before `main()` runs in a normal program) and that can't be called again later. – unwind Nov 04 '15 at 11:40
  • Success... your pointer to dynamic code loading sent me down a path that led to something quite useful. I will post my solution here in a minute or two! Thanks! – Enok82 Nov 04 '15 at 14:00
1

@unwind sent me looking at dynamic code loading!
Reading these: Dynamically load a function from a DLL and http://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/ gave me enough to concoct the following solution.

in statemachine.h:

    void stateMachine(void);

in statemachine.c:

    #include <stdio.h>

    void stateMachine(void)
    {
      static int myState = 0;

      switch(myState)
      {
      case 0:
      {
        printf("Init State");
        myState = 1;
        break;
      }
      case 1:
      {
        printf("Second state");
        break;
      }
      default:
      {
        printf("Default");
        break;
      }
      }
    }

in statemachinelib.c:

    #include "statemachine.h"

    __declspec(dllexport) void __cdecl statemachineWrap()
    {
      stateMachine();
    }

in main.c:

    #include <windows.h>
    #include <stdlib.h>
    #include <stdio.h>

    typedef int (__stdcall *f_funci)();

    int main(int argc, char **argv)
    {
      HINSTANCE hGetProcIDDLL = LoadLibrary("statemachinelib.dll");

      f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "statemachineWrap");

      funci();

      funci();

      funci();

      FreeLibrary(hGetProcIDDLL);  //Windows detects that no one is using this library anymore and unloads it from memory, giving the new LoadLibrary a fresh instance

      hGetProcIDDLL = LoadLibrary("statemachinelib.dll");

      funci = (f_funci)GetProcAddress(hGetProcIDDLL, "statemachineWrap");

      funci();

      funci();

      funci();

      return 0;
    }

In this code i have omitted a lot of safety statements such as checking if the DLL could be loaded, if the function is found, whether we want too dllexport or dllimport and so on only to make it easier to grasp what is going on. If you are going to implement this in any real project you should at least read both of the resources i mentioned above.

compilation of the DLL using MinGW:

>gcc -c statemachine.c statemachinelib.c
>gcc -o statemachinelib.dll -s -shared statemachinelib.o statemachine.o -Wl,--subsystem,windows

compilation of the executable, also MinGW:

>gcc -o main.exe main.c

execution yields:

>main.exe
Init State
Second state
Second state
Init State
Second state
Second state

I'll just leave this here for a few days and if no one objects i will mark this as my accepted answer!

Edit: I have elaborated a bit and there's another (solved) question from me here with just a slight tweak Exporting a function, cast into a pointer through a DLL

Community
  • 1
  • 1
Enok82
  • 163
  • 1
  • 13