I'm trying to integrate a firmware upgrade functionality inside a Witty application.
The application communicate with an external device by using /dev/ttyUSB0
, the same port is used for firmware upgrade, when doing so, the application release the port and call an external command line application via popen()
.
The main issue is that it is perfectly working when executed in the main, but it is not when executed from an event example :
m_pUploadButton->clicked().connect(std::bind([=] () {
pComputer->firmwareUpgrade();
}));
Here are the definitions of relevant functions :
bool ComputerV2::upgradeFirmware()
{
m_oMutex.lock();
std::string sFile = "/home/alextown/MPLABXProjects/ordinateur_V2/dist/default/production/ordinateur_V2.production.hex";
std::string sResult = "";
std::string sCommand = "/home/alextown/QtProjects/build-pic32ubl-qt-qt5-Release/pic32ubl-qt --headless --port=/dev/" + m_sPort + " --file=" + sFile + " --erase --program --verify --jump-application";
std::cout << sCommand << std::endl;
int nResult = exec(sCommand,sResult);
std::cout << sResult << std::endl;
m_oMutex.unlock();
return nResult == 0;
}
int exec(std::string p_sCommand, std::string &p_sResult)
{
FILE *pipe = popen(p_sCommand.c_str(),"r");
p_sResult = "";
if(!pipe) return -1;
char buffer[128];
while(!feof(pipe))
{
if(fgets(buffer,128,pipe) != NULL)
{
p_sResult += buffer;
}
}
return pclose(pipe);
}
From what I've observed, when running upgrade from main
, everything works perfectly (jump device in upgrade mode, upgrade and jump back in normal mode). When running from widget, data sent over the port /dev/ttyUSB0
is not the same, thus causing communication issue and upgrade failed.
From my comprehension, there is something different in thread ran for Witty widgets than thread ran for main application.
I would strongly recommend to do this update in an external thread or std::launch::async'ed
std::future`, since the Wt threads are indeed special.
Special means, they may be running in some sort of thread pool and also maybe are running in the context i.e. process of a webserver (although I guess you currently deployed it via the built in http-server, but imagine you want to reuse your code).
So does your USB-Driver has something process specific on it (globals, state, etc?) Then the best would be to do that upgrade in a fresh created process, aside from your web-application (some call this micro service approach, to make look this old technique more fancy).
Wt offers methods to synchronize with external events, if wanted.
See Wt::WApplication::bind
and Wt::Server::post
.
Separating this work also has the advantage, that your web application still responds while the upgrade takes place, which will probably take some time. Also if the upgrade causes some major troubles, it's a lot easier for your web app to deliver diagnostic messages or take over better issue an action.