In most applications, the UI needs to be connected in some way to the rest of the system, and transmits and receives data. This may be a hardware peripheral device (sensor data, A / D conversion, serial communication) interfaces, may also be an interface with other software modules.

This article describes the recommended solution for implementing this connection.

The first method is a method of "quick and dirty" method is mainly used for prototyping, while the second method is reasonable to connect the UI with real-world applications of the remaining components in the architecture.

At the end of this article, we use the example links to both methods.

Model Class

All TouchGFX applications have a Model class, in addition to the UI state information is stored, is also intended to serve as an interface around your system. In this way, we not only refers to hardware peripherals, but also refers to other OS tasks in the system. Typically, other software modules or hardware to access each View class is not a good design.

Model class is placed in any suitable interface code such as:

  1. Model class has a tick () function, which will automatically call in each frame, and can be implemented to respond to find other sub-modules in the event and the event.
  2. Model class has a pointer to point to your current activity Presenter in order to enable the incoming event notifications UI.

Hardware interface

Method 1: sampling directly from the GUI task

The best way to interface with the hardware you need depends on the frequency of sampling, sampling time and the urgency of time. If you require more generous in these areas, then the easiest way is to direct the Model::tickfunctions of the hardware sampling   . If the sampling frequency of occurrence is lower than the frame rate (typically about 60Hz), a counter may be added, and only the N-th one sampling clock interval. After completing this way, your sampling operations must be faster (typically 1ms or less), or your frame rate will begin to be affected, because the sampling is done in the context of the GUI task, and will delay the drawing frame .

Method 2: Sampling from a secondary task

Or, if you do not want to interact with the hardware directly in the context of GUITask, you can create a new OS tasks to perform sampling. You can configure this task to the exact time required in a particular case interval running. In addition, depending on your needs, the priority of the new task can be lower or higher than the GUI task. If it has a higher priority, it can ensure that it runs exactly at the specified time, regardless of the GUI task is doing. The downside to this is that if this process is CPU occupancy, it may affect the frame rate of the UI. On the other hand, if the sample is not pressed for time, you can assign that task a lower priority than the GUI task, so UI will not be affected by the frame rate hardware samples.

If you use an auxiliary task method, we recommend that you take advantage of inter-tasking RTOS provides messaging system. Most (if not all) RTOS has a queue / Mail mechanism that lets you move the data (usually C user-defined structure, or a simple integer array of bytes) sent from one task to another. In order to transfer data to the new GUI task, provided tast of the UI mailbox or the message queue, and then use this messaging system to send data to GUI task. You can then Model::tickpoll the GUI task mailbox to check for new data arrives. Just in case, the read data and update the UI.

Propagating data to the UI

Whether you use Method 1 or Method 2, the Model::tickfunctions are GUITask know where you want the new data to be displayed in the UI. In addition to acting as an interface with the surrounding systems, but also rememberModel that class is also responsible for saving status data, and therefore may also need to update some state variables.

Let us consider a simple example, wherein the temperature sensor is connected to the system, and the current temperature will be displayed in the UI. In preparation, we will extend the Model class to support this:

Model.hpp:
class Model
{
public:
  // Function that allow your presenters to read current temperature.
  int getCurrentTemperature() const { return currentTemperature; }
// Called automatically by framework every tick. void tick(); ... private: // Variable storing last received temperature; int currentTemperature; ... };

By the above operation, you Presenters can ask the model to the current temperature, allowing the presenter to set this value in the UI (view) at the time of entering the temperature of the display screen. We now need to do is to update UI again when you receive a new temperature information. For this reason, we take advantage of the fact that the model has a point to your current activity pointer presenter. The pointer type is the interface (ModelListener ), you can modify it to reflect the appropriate application-specific events:

ModelListener.hpp:
class ModelListener
{
public:
  // Call this function to notify that temperature has changed.
  // Per default, use an empty implementation so that only those
// Presenters interested in this specific event need to
// override this function. virtual void notifyTemperatureChanged(int newTemperature) {} };

Now that we have connected this interface, the rest is incoming "new temperature" events actually sampled. Model::tick

Model.cpp
void Model::tick()
{
  // Pseudo-code for Method 1 or Method 2. Depends on your concrete Operating System
  if (OS_Poll(GuiTaskMBox))
  {
    // Here we assume that you have defined a "Message" struct containing type and data,
    // along with some event definitions. struct Message msg = OS_Read(GuiTaskMBox); if (msg.eventType == EVT_TEMP_CHANGED) { // We received information that temperature has changed. // First, update Model state variable currentTemperature = msg.data; // Second, notify the currently active presenter that temperature has changed.
// The modelListener pointer points to the currently active presenter. if (modelListener != 0) { modelListener->notifyTemperatureChanged(currentTemperature); } } } }

The above method can ensure two things:

  1. currentTemperature variable always up to date, so that you can get the current temperature of the Presenter at any time.
  2. Moderator will be notified immediately about changes in temperature, and may take appropriate measures.

One of the advantages is the MVP mode, you can process the notification based solely on the current screen is located. For example, assume that the temperature change event occurs when displaying a certain temperature regardless of the current setting menu (e.g., MainMenuPresenter / MainMenuView active).

Since notifyTemperatureChanged function has a default empty implementation, therefore MainMenuPresenter completely ignored this notice. On the other hand, if you have TemperatureControlPresenter, you can override this function notifyTemperatureChanged presenter and notifies View update its temperature should be displayed:

TemperatureControlPresenter.hpp:
class TemperatureControlPresenter : public ModelListener
{
public:
  // override the empty function.
  virtual void notifyTemperatureChanged(int newTemperature) {
view.setTemp(newTemperature);
} };
Of course, View class must implement setTemp TemperatureControlView method. 

The data transfer from the system to the surrounding UI

Data / events to the UI transmitted from the opposite direction around the system is carried out by the Model, the method is substantially the same. If you need to add functionality to configure a new set point (target temperature), and continued from the previous example, we will add the following models:

Model.hpp:
void setNewTargetTemperature(int newTargetTemp)
{
  // Pseudo-code for sending an event to a task responsible for controlling temperature.
  struct Message msg;
  msg.eventType = EVT_SET_TARGET_TEMP;
  msg.data = newTargetTemp;
  OS_Send(SystemTaskMBox, &msg);
}

If the user sets the new target temperature in the UI, the view may be notified Presenter, the Presenter Model object has a pointer pointing to, it is possible to call the   setNewTargetTemperaturefunction.

example

Method 1 - From the GUI task

This download link can be found working example STM32F746, the example demonstrates how to sample the button in the Model class and directly controls the LED. This example uses the MVP value transfer architecture between the two views and the event Model class. Model classes button sampled and updated to match the state LED applications.

This download link can be found working example STM32F429, showing how the buttons on Model class is sampled. This example uses the MVP architecture Transfer button to view the event.

Method 2 - from other tasks

This download link can be found working example STM32F469, the example shows how samples the analog input in a separate thread. This example uses the MVP architecture to transfer analog values to View.
 
A working example shows the inter-task communication and dissemination to and from the UI. This as inspiration for your own settings. The exemplary communication between the backend system implemented in C code and C ++ TouchGFX GUI. This example works on the board STM32F746G-DISCO FreeRTOS. 

Method 3 from a plurality of tasks (4.9.3)

The working example has been demonstrated in TouchGFX webinar held May 28, 2018 "Integration with Hardware".  

The application is designed STM32F769-DISCO plate, and LED, and the user interacts with the buttons, to show how to integrate C code and hardware peripherals TouchGFX to your application.  

Application Configuration button to GPIO mode. Behavior in the sampling state btntask.c button, if the button is pressed, the message is transmitted through the GUI message queue. This allows us to advance the animation by pressing the button in the application.

The application uses three FreeRTOS task. For a GUI, for each peripheral device (LED button and the user).

Method 4 and disconnected from an externally tasks (4.9.3)

The working example has been demonstrated in TouchGFX webinar held May 28, 2018 "Integration with Hardware".  

The application is designed STM32F769-DISCO plate, and LED, and the user interacts with the buttons, to show how to integrate C code and hardware peripherals TouchGFX to your application. 

The application mode button configured to EXTI (external interrupt 0). Behavior is to receive an interrupt button is pressed, then clear the interrupt. This does not allow the GPIO behavior in the same, but we will step through the animation, because only when an interrupt is received by gui message queue to send a message.

The application uses two FreeRTOS task. For a GUI, for a LED. (Method 3 in the Button task remains active in this application to illustrate the interaction code has been moved to the peripheral interrupt handler).

 

[ Original ]