从 Wt 小部件信号事件发出 运行 popen()
Issues running popen() from Wt widget signal event
我正在尝试将固件升级功能集成到 Witty 应用程序中。
应用程序通过/dev/ttyUSB0
与外部设备通信,固件升级使用同一个端口,此时应用程序释放端口并通过[=14=调用外部命令行应用程序].
主要问题是它在 main 中执行时完美运行,但在从事件示例中执行时却不是:
m_pUploadButton->clicked().connect(std::bind([=] () {
pComputer->firmwareUpgrade();
}));
相关函数的定义如下:
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);
}
据我观察,当 运行 从 main
升级时,一切正常(在升级模式下跳转设备,在正常模式下升级并跳回)。当运行来自widget时,通过端口/dev/ttyUSB0
发送的数据不相同,从而导致通信问题和升级失败。
根据我的理解,Witty 小部件的线程 运行 与主应用程序的线程 运行 有所不同。
我强烈建议在外部线程或 std::launch::async'ed
std::future` 中执行此更新,因为 Wt 线程确实 特殊.
特殊方式,它们可能是 运行 在某种线程池中,也可能是 运行 在上下文中,即网络服务器的进程(尽管我猜你目前通过内置的部署它在 http-server 中,但假设您想重用您的代码)。
那么你的 USB 驱动程序是否有特定的进程(全局、状态等?)那么最好的办法是在一个新创建的进程中进行升级,除了你的网络应用程序(有人称之为微服务方法,使这种旧技术看起来更花哨)。
如果需要,Wt 提供与外部事件同步的方法。
参见 Wt::WApplication::bind
和 Wt::Server::post
。
将这项工作分开还有一个好处,即您的 Web 应用程序在升级时仍会响应,这可能需要一些时间。此外,如果升级导致一些重大问题,您的网络应用程序可以更轻松地传递诊断消息或接管更好的问题。
我正在尝试将固件升级功能集成到 Witty 应用程序中。
应用程序通过/dev/ttyUSB0
与外部设备通信,固件升级使用同一个端口,此时应用程序释放端口并通过[=14=调用外部命令行应用程序].
主要问题是它在 main 中执行时完美运行,但在从事件示例中执行时却不是:
m_pUploadButton->clicked().connect(std::bind([=] () {
pComputer->firmwareUpgrade();
}));
相关函数的定义如下:
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);
}
据我观察,当 运行 从 main
升级时,一切正常(在升级模式下跳转设备,在正常模式下升级并跳回)。当运行来自widget时,通过端口/dev/ttyUSB0
发送的数据不相同,从而导致通信问题和升级失败。
根据我的理解,Witty 小部件的线程 运行 与主应用程序的线程 运行 有所不同。
我强烈建议在外部线程或 std::launch::async'ed
std::future` 中执行此更新,因为 Wt 线程确实 特殊.
特殊方式,它们可能是 运行 在某种线程池中,也可能是 运行 在上下文中,即网络服务器的进程(尽管我猜你目前通过内置的部署它在 http-server 中,但假设您想重用您的代码)。
那么你的 USB 驱动程序是否有特定的进程(全局、状态等?)那么最好的办法是在一个新创建的进程中进行升级,除了你的网络应用程序(有人称之为微服务方法,使这种旧技术看起来更花哨)。
如果需要,Wt 提供与外部事件同步的方法。
参见 Wt::WApplication::bind
和 Wt::Server::post
。
将这项工作分开还有一个好处,即您的 Web 应用程序在升级时仍会响应,这可能需要一些时间。此外,如果升级导致一些重大问题,您的网络应用程序可以更轻松地传递诊断消息或接管更好的问题。