2024-02-07 09:13 PM - last edited on 2024-02-08 02:20 AM by Osman SOYKURT
Hi everyone,
I've setup a project in TouchGFX4.18.1 and STM32H747i Disco, which consist of 4-5 screens. One screen is for motor control. In this motor control screen 3 buttons are used (low, medium, high) for changing the PWM. Simple but, the virtual function at the model (MVP) is calling the wrong Function.
The funny thing is, the order that a function is placed in the .HPP yields that the function to be called in model and it's not the correct function. I've used breakpoints throughout MVP, and all was validated as making the incorrect/correct call.
virtual void PWM_33(); (if PWM_33 is placed on the bottom, PWM_66 would be called for every button.)
virtual void PWM_66(); (same as the above)
virtual void PWM_75(); (same as the above)
This is the third time I've made the to change to the buttons that only yield the same results. Otherwise, each function call reverts to the order in .HPP. This area (stepping from VIEW, Presenter to Model not possible) seems to contain a possible reason for my virtual function call issue.
Do any of you knowledgeable people have an Idea of what I've done wrong?
What's taking place between the presenter to model?
//***************************************
Reference:
#include <gui/model/Model.hpp>
#include <gui/model/ModelListener.hpp>
#include "cmsis_os2.h" //added for osDelay();
#include "string.h"
#define SRAM3 0x38000000
//DEFAULT IS 33% DUTY CYCLE
int PwmCount = 0;
Model::Model() : modelListener(0)
{
}
void Model::tick()
{
}
//***************************************************************************************
//FROM THE DISPLAY(*.VIEW) WE COME TO THIS HERE (M7->M4). MY THINKING IS, MAKE THE SELECTION
// ON THE SCREEN FOR PWM, AND THEN SAVE TO SRAM. FROM SRAM WE'LL OPEN WITH M4 AND SEND
//VIA UART WIRELESSLY TO THE MTR CONTROLLER ON THE ROBOT.
//***************************************************************************************
void Model::PWM_33()
{
osDelay(3);
}
void Model::PWM_66()
{
osDelay(3);
}
void Model::PWM_75()
{
osDelay(3);
}
//***************************************
#ifndef MODEL_HPP
#define MODEL_HPP
class ModelListener;
class Model
{
public:
Model();
void bind(ModelListener* listener)
{
modelListener = listener;
}
void tick();
virtual void PWM_33();
virtual void PWM_66();
virtual void PWM_75();
protected:
ModelListener* modelListener;
};
#endif // MODEL_HPP
2024-02-08 08:57 AM
Hello @Hiram Hyman ,
Thank you for your question.
Firstly, it is recommended to work with the latest version of TouchGFX and Designer.
1) Clarifications :
The funny thing is, the order that a function is placed in the .HPP yields that the function to be called in model and it's not the correct function.
To be clear, you mean that the function that is first declared (the smallest line number) is called and never the 2 others?
Otherwise, each function call reverts to the order in .HPP. This area (stepping from VIEW, Presenter to Model not possible) seems to contain a possible reason for my virtual function call issue.
I am sorry, I do not understand this sentence.
Furthermore, where are your PWM functions defined?
Can you share more of your project?
2) How to interact with the model view presenter?
I guess that you have a motorControl.c file where you have all the logic for the motor control. You could have a variable in this file referring to the speed of the motor (for instance an int that represent the % of speed like 33, 66 or 75).
It is easy to modify a variable from the model.
All you have to do is to include the file containing the variable to modify and then you can access the variable.
Now, you also need to call a specific function based on which button you press.
To do so, you can add a button on your screen, then add an interaction called when the button is pressed and then send the information to the model.
To do so, you need to call a function from the screen that will call a function in the presenter and then in the model.
I made an example that you can find attached with this answer.
Furthermore, you can find examples and documentation for the model, view presenter here :
Hope this helps.
Don’t hesitate to give us a feedback or give more precisions and tell us if the issue is solved! :smiling_face_with_smiling_eyes:
2024-02-08 05:13 PM
The funny thing is, the order that a function is placed in the .HPP yields that the function to be called in model and it's not the correct function.
To be clear, you mean that the function that is first declared (the smallest line number) is called and never the 2 others?
(This is correct. In Model.hpp, only the first function of line 10 is called. If I switch 10 with 11/12, only line 10 of that function is called. Line 11/12 function still aren't called. Both functions work but, only when at Line 10.
Otherwise, each function call reverts to the order in .HPP. This area (stepping from VIEW, Presenter to Model not possible) seems to contain a possible reason for my virtual function call issue.
I am sorry, I do not understand this sentence. As I step through the call of the virtual functions, I'm able to do so until, Presenter to Model. Meaning something is taking place in between that I can't see what is taking place.
In reference to you the motor control, I have on a separate controller a motor controlled via analog Joysticks already. Which last night I thought, Until I receive an answer on how to fix this current issue, I could just set this to a fixed for PWM and use the joysticks to control the duty cycle for both AUGV and Submersible systems. From processor M7 (GUI) - M4 (UART Transceiver) to send Data (PWM for example) to the remote system.
A hand held system is to be used for both. (Below: UI for Hand Held Unit)
In conclusion, I will update TouchGFX to the latest version. I was hesitant to do so because I wanted to avoid the chance of loosing my Screens. If I do however, I would gain more knowledge. So, I would be satisfied from either.
I will come back and post the outcome. Hopefully, I've provided a better explanation for you.
Thanks again,
Hiram
2024-02-09 12:31 AM
Can you also share the code of the view and presenter? (both hpp and cpp).
That's were you can specify what should happen. From the presenter you can connect to the Model to call the correct method.
2024-02-09 02:56 AM - last edited on 2024-02-09 03:10 AM by GaetanGodart
Hi EmbDev,
Upon your request, the code follows: Same problem with the touchgfx upgrade (4.23.1). Also, I realized that the problem occurs from the presenter to model. FYI
View.hpp
#ifndef MTRVIEW_HPP
#define MTRVIEW_HPP
#include <gui_generated/mtr_screen/MTRViewBase.hpp>
#include <gui/mtr_screen/MTRPresenter.hpp>
class MTRView : public MTRViewBase
{
public:
virtual void DUTY_33();
virtual void DUTY_66();
virtual void DUTY_75();
MTRView();
virtual ~MTRView() {}
virtual void setupScreen();
virtual void tearDownScreen();
protected:
};
#endif // MTRVIEW_HPP
View.cpp
#include <gui/mtr_screen/MTRView.hpp>
MTRView::MTRView()
{
}
void MTRView::setupScreen()
{
MTRViewBase::setupScreen();
}
void MTRView::tearDownScreen()
{
MTRViewBase::tearDownScreen();
}
void MTRView::DUTY_33()
{
// Override and implement this function in MTR
presenter->DUTY_33();
}
void MTRView::DUTY_75()
{
presenter->DUTY_75();
// Override and implement this function in MTR
}
void MTRView::DUTY_66()
{
presenter->DUTY_66();
// Override and implement this function in MTR
}
Presenter.hpp
#ifndef MTRPRESENTER_HPP
#define MTRPRESENTER_HPP
#include <gui/model/ModelListener.hpp>
#include <mvp/Presenter.hpp>
using namespace touchgfx;
class MTRView;
class MTRPresenter : public touchgfx::Presenter, public ModelListener
{
public:
MTRPresenter(MTRView& v);
/**
* The activate function is called automatically when this screen is "switched in"
* (ie. made active). Initialization logic can be placed here.
*/
virtual void activate();
/**
* The deactivate function is called automatically when this screen is "switched out"
* (ie. made inactive). Teardown functionality can be placed here.
*/
virtual void deactivate();
virtual ~MTRPresenter() {}
virtual void DUTY_33();
virtual void DUTY_66();
virtual void DUTY_75();
private:
MTRPresenter();
MTRView& view;
};
#endif // MTRPRESENTER_HPP
Presenter.cpp
#include <gui/mtr_screen/MTRView.hpp>
#include <gui/mtr_screen/MTRPresenter.hpp>
MTRPresenter::MTRPresenter(MTRView& v)
: view(v)
{
}
void MTRPresenter::activate()
{
}
void MTRPresenter::deactivate()
{
}
void MTRPresenter::DUTY_33()
{
// Override and implement this function in MTR
model->DUTY_33();
}
void MTRPresenter::DUTY_66()
{
// Override and implement this function in MTR
model->DUTY_66();
}
void MTRPresenter::DUTY_75()
{
// Override and implement this function in MTR
model->DUTY_75();
}
Model.hpp
#ifndef MODEL_HPP
#define MODEL_HPP
class ModelListener;
class Model
{
public:
virtual void DUTY_75();
virtual void DUTY_33();
virtual void DUTY_66();
Model();
void bind(ModelListener* listener)
{
modelListener = listener;
}
void tick();
protected:
ModelListener* modelListener;
};
#endif // MODEL_HPP
Model.cpp
#include <gui/model/Model.hpp>
#include <gui/model/ModelListener.hpp>
#include "stm32h7xx_hal.h"
Model::Model() : modelListener(0)
{
}
void Model::tick()
{
}
void Model::DUTY_33()
{
// Override and implement this function in MTR
HAL_Delay(30); //USED FOR BREAK POINT
}
void Model::DUTY_66()
{
// Override and implement this function in MTR
HAL_Delay(30); //USED FOR BREAK POINT
}
void Model::DUTY_75()
{
// Override and implement this function in MTR
HAL_Delay(30); //USED FOR BREAK POINT
}
2024-02-09 03:20 AM
Hello @Hiram Hyman ,
1) Formatting
I reformatted you post.
When providing code, make sure to use the "Insert/edit sample code" button.
2) Function name and type
I have seen that you name all your function the same whether they are in view, presenter or model. Furthermore, they are all virtual so they can be overwritten. Finally, you say that you overwrite that function in another file. Therefore, every single one of those functions are overwritten.
3) What to do now
I would advise you to try to narrow down the issue and to follow best practices by creating a simple project from scratch where you try to add 3 buttons and print something from the model to make sure you are able to access all 3 functions.
From there you can include your MTR file that you use to overwrite the functions and instead of overwriting them, you can just call those functions from the model since you included the file.
2024-02-09 06:32 PM
Hi,
Thanks for the "Insert/edit sample code" information. I'll implement this in my post.
I made a simple 3 button screen. Same result so far. I made sure to only make one virtual function in the view and not including virtual in the presenter and model. Thanks!
The function makes it through for all buttons except for when it reaches model like before. At the model the same (highest declaration in model.hpp of the function) is called for all three buttons.
2024-02-09 08:20 PM
Hi,
For all that have been involved thus far on resolving this issue, I've removed all previous projects from CubeIDE and just designed a 3 button(H,M and L) screen. This screen is the only that exist. This yields the same results. That is from Presenter to the model, the wrong function is called in the model. In model.hpp, the order of the coded functions will only execute the lowest (coded) line function. I'm at the end of this trail. I will try and reinstall STM32CubeIDE.
2024-02-09 09:10 PM
Okay, after installing CubeIDE to 1.7.0 from STs homepage, the results are the same. I've spent to much time on this project. I'll perhaps try and find a solution afterwards.
Thanks for your help everybody!
Hiram
2024-02-11 11:34 PM
As you now created a separate project with just a single screen, can you share the complete project as an attachment? With the complete project it shouldn't be too hard to find the problem.