cancel
Showing results for 
Search instead for 
Did you mean: 

Communication between model and backend

CI_max
Associate II

Hello,

I am wondering what is a good way to tell TouchGFX with what objects of the backend to communicate. If for example my application has some backend object "Foo bar" that I want TouchGFX to communicate with, for now the only solution I see is to declare these objects with "extern Foo bar" in the model and essentially reference it as a global variable. For testing and simulation purposes it would be great to pass data (references/pointers) from the backend to the model, e.g., to the constructor. Is there an easy way to do this?

Cheers, Max

8 REPLIES 8
Karl Yamashita
Lead III

Look into Message Queue

https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__Message.html

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
Panchev68
Senior

The idea is the opposite.
in Model::tick() you check for data change and call the appropriate modelListener callback

see  : Propagating Data to UI 

There is no way to control the creation of the model instance. So the parameters in the constructor are not useful. But the model can inherit (or instantiate) your own classes that handle communication with your backend object.

Sure, I understand that in Model::tick() you check if some state has changed and then pass it to the modelListener. But still, you need to make the model aware of what objects to communicate with. Even having a message queue from some RTOS requires both the model and some other task to refer to some common message queue object. If there is no way to either pass data to the model constructor or pass data to the model from the backend after creation then the only way is to use global variables, right? 

I can not understand the question !

The data is in the class in the instance of the class Foobar. right !?

example:

 

/// \file Project\Foo.hpp
#pragma once

class Foo
{
public:

    Foo ()         = default;
    ~Foo ()        = default;
    uint32_t Value = 0;
};

 

/// \file Project\Bar.cpp
#include "Project\Foo.hpp"

Foo bar;

 

/// \file Model.cpp
#include "Project\Foo.hpp"
extern Foo bar;

Model::Model ()
{}

void Model::tick ()
{
    static uint32_t bar_value =0;
	if (bar.Value!=bar_value)
    {
		bar_value = bar.Value;
        modelListener->notifyBarValueChanged(bar_value) ;
    }
}

 

 

 

Thank you for your demonstration! This precisely shows my problem, however. Referencing with "extern" (extern Foo bar;) is arguably not really considered a good practice any more. It makes testing and the reusability more difficult than with having a way to pass some data from the backend to the model upon instantiation or initialization.

ОК

See how it is for me:

In Project

/// \file Project\TouchGFX\Model\CModel1.hpp

#pragma once

class CModel1
{
public:

   class XListener;
   uint32_t Value;

   CModel1 ()  = default;
   ~CModel1 () = default;
   void tick (XListener * listener);

private:
};

class CModel1::XListener
{
public:

   XListener ()          = default;
   virtual ~XListener () = default;

   virtual void notifyValue1Changed (uint32_t) {}
};

inline void CModel1::tick (XListener * listener)
{
   static uint32_t value;
   if (Value != value)
  {
       value = Value;
       listener->notifyValue1Changed (value);
  }
}
/// \file Project\TouchGFX\Model\CModel2.hpp

#pragma once

class CModel2
{
public:

   class XListener;
   uint32_t Value;

   CModel2 ()  = default;
   ~CModel2 () = default;
   void tick (XListener * listener);

private:
};

class CModel2::XListener
{
public:

   XListener ()          = default;
   virtual ~XListener () = default;

   virtual void notifyValue2Changed (uint32_t) {}
};

inline void CModel2::tick (XListener * listener)
{
   static uint32_t value;
   if (value != Value)
  {
       value != Value;
       listener->notifyValue2Changed (value);
  }
}

In TouchGFX

/// \file TouchGFX\gui\include\gui\model\Model.hpp

#ifndef MODEL_HPP
#define MODEL_HPP

#include "Project\TouchGFX\Model\CModel1.hpp"
#include "Project\TouchGFX\Model\CModel2.hpp"

class ModelListener;

class Model
{
public:

   CModel1 Model1;
   CModel2 Model2;

   Model ();

   void bind (ModelListener * listener)
  {
       modelListener = listener;
  }

   void tick ()
  {
       Model1.tick (modelListener);
       Model2.tick (modelListener);
  }

protected:

   ModelListener * modelListener;
};

#endif        // MODEL_HPP
/// \file TouchGFX\gui\include\gui\model\ModelListener.hpp

#ifndef MODELLISTENER_HPP
#define MODELLISTENER_HPP

#include <gui/model/Model.hpp>

class ModelListener : public CModel1::XListener, public CModel2::XListener
{
public:
   ModelListener () : model (0) {}
   virtual ~ModelListener () {}
   void bind (Model * m)
  {
       model = m;
  }

protected:
   Model * model;
};

#endif        // MODELLISTENER_HPP

Personally, I like this approach. We hope it will be useful for you too

ОК

See how it is for me:

In Project

Project\TouchGFX\Model\CModel1.hpp

 

/// \file Project\TouchGFX\Model\CModel1.hpp

#pragma once

class CModel1
{
public:

    class XListener;
    uint32_t Value;

    CModel1 ()  = default;
    ~CModel1 () = default;
    void tick (XListener * listener);

private:
};

class CModel1::XListener
{
public:

    XListener ()          = default;
    virtual ~XListener () = default;

    virtual void notifyValue1Changed (uint32_t) {}
};

inline void CModel1::tick (XListener * listener)
{
    static uint32_t value;
    if (Value != value)
    {
        value = Value;
        listener->notifyValue1Changed (value);
    }
}

 

Project\TouchGFX\Model\CModel2.hpp

/// \file Project\TouchGFX\Model\CModel2.hpp

#pragma once

class CModel2
{
public:

    class XListener;
    uint32_t Value;

    CModel2 ()  = default;
    ~CModel2 () = default;
    void tick (XListener * listener);

private:
};

class CModel2::XListener
{
public:

    XListener ()          = default;
    virtual ~XListener () = default;

    virtual void notifyValue2Changed (uint32_t) {}
};

inline void CModel2::tick (XListener * listener)
{
    static uint32_t value;
    if (value != Value)
    {
        value != Value;
        listener->notifyValue2Changed (value);
    }
}

 

In TouchGFX

TouchGFX\gui\include\gui\model\Model.hpp

 

/// \file TouchGFX\gui\include\gui\model\Model.hpp

#ifndef MODEL_HPP
#define MODEL_HPP

#include "Project\TouchGFX\Model\CModel1.hpp"
#include "Project\TouchGFX\Model\CModel2.hpp"

class ModelListener;

class Model
{
public:

    CModel1 Model1;
    CModel2 Model2;

    Model ();

    void bind (ModelListener * listener)
    {
        modelListener = listener;
    }

    void tick ()
    {
        Model1.tick (modelListener);
        Model2.tick (modelListener);
    }

protected:

    ModelListener * modelListener;
};

#endif        // MODEL_HPP

 

TouchGFX\gui\include\gui\model\ModelListener.hpp

/// \file TouchGFX\gui\include\gui\model\ModelListener.hpp

#ifndef MODELLISTENER_HPP
#define MODELLISTENER_HPP

#include <gui/model/Model.hpp>

class ModelListener : public CModel1::XListener, public CModel2::XListener
{
public:
    ModelListener () : model (0) {}
    virtual ~ModelListener () {}
    void bind (Model * m)
    {
        model = m;
    }

protected:
    Model * model;
};

#endif        // MODELLISTENER_HPP

Personally, I like this approach. We hope it will be useful for you too

Hi CI_max,

interested to hear if you solved this problem, or came up with a neat 'best-case' workaround. Facing the same design problem and currently considering whether using dependency injection on a static class reference is the better option - but hoping there's a nice solution.