Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/slic3r/GUI/FlashForge/ComCommand.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,71 @@
#include "ComCommand.hpp"

#include <boost/log/trivial.hpp>
#include <nlohmann/json.hpp>

#include "slic3r/Utils/Http.hpp"

namespace Slic3r { namespace GUI {

int ComCommand::s_commandNum = ComInvalidCommandId + 1;

ComErrno ComCameraStreamCtrl::sendLanCameraStreamCtrl(const com_command_exec_data_t &data,
const std::string &action)
{
if (data.ip == nullptr || data.serialNumber == nullptr || data.checkCode == nullptr) {
return COM_ERROR;
}
// Same request shape the network library uses for the other LAN control
// commands (see fnet_ctrlLanDevLight): a POST to /control on the printer's
// local HTTP port, authenticated by serial number plus check code, wrapping
// the command and its arguments in a "payload" object.
nlohmann::json body;
body["serialNumber"] = data.serialNumber;
body["checkCode"] = data.checkCode;
body["payload"]["cmd"] = "streamCtrl_cmd";
body["payload"]["args"] = {{"action", action}};

std::string url = std::string("http://") + data.ip + ":" + std::to_string(data.port) + "/control";

ComErrno result = COM_ERROR;
// Deliberately not logging the body: it carries the serial number and check
// code, and these lines end up pasted into bug reports.
BOOST_LOG_TRIVIAL(info) << "sendLanCameraStreamCtrl: streamCtrl_cmd action=" << action;

Http::post(url)
.header("Content-Type", "application/json")
.timeout_connect(ComTimeoutLanA / 1000)
.timeout_max(ComTimeoutLanA / 1000)
.set_post_body(body.dump())
.on_complete([&result](std::string reply, unsigned status) {
if (status < 200 || status >= 300) {
BOOST_LOG_TRIVIAL(warning) << "sendLanCameraStreamCtrl: http status " << status;
return;
}
// The printer answers {"code":0,...} on success. Treat a missing or
// unparsable code as success so a firmware that only varies its
// reply shape does not disable the camera, since a 2xx already means
// the command was accepted.
try {
nlohmann::json json = nlohmann::json::parse(reply);
if (json.contains("code") && json["code"].is_number_integer() &&
json["code"].get<int>() != 0) {
BOOST_LOG_TRIVIAL(warning) << "sendLanCameraStreamCtrl: printer returned code "
<< json["code"].get<int>();
return;
}
} catch (const std::exception &) {
BOOST_LOG_TRIVIAL(debug) << "sendLanCameraStreamCtrl: reply was not json";
}
result = COM_OK;
})
.on_error([](std::string, std::string error, unsigned status) {
BOOST_LOG_TRIVIAL(warning) << "sendLanCameraStreamCtrl failed, status " << status
<< ", " << error;
})
.perform_sync();

return result;
}

}} // namespace Slic3r::GUI
38 changes: 36 additions & 2 deletions src/slic3r/GUI/FlashForge/ComCommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,26 @@ class ComGetDevProductDetail : public ComCommand
{
int ret;
if (data.connectMode == COM_CONNECT_LAN) {
return COM_UNSUPPORTED;
// The network library exposes LAN equivalents of the WAN
// product/detail call, and they are already used individually by
// ComGetDevProduct and ComGetDevDetail above. Fetch both here
// rather than reporting the whole command unsupported: while this
// returned COM_UNSUPPORTED, devProduct and devDetail stayed null on
// every LAN connection, so each capability the device page reads
// from them (camera, lightCtrlState, internalFanCtrlState, ...) was
// silently absent.
ret = data.networkIntfc->getLanDevProduct(data.ip, data.port, data.serialNumber,
data.checkCode, &m_devProduct, ComTimeoutLanA);
if (ret != FNET_OK) {
return MultiComUtils::fnetRet2ComErrno(ret);
}
ret = data.networkIntfc->getLanDevDetail(data.ip, data.port, data.serialNumber,
data.checkCode, &m_devDetail, ComTimeoutLanA);
if (ret != FNET_OK) {
// Don't leak the product that was just fetched.
data.networkIntfc->freeDevProduct(m_devProduct);
m_devProduct = nullptr;
}
} else {
ret = data.networkIntfc->getWanDevProductDetail(data.clientId, data.accessToken,
data.devId, &m_devProduct, &m_devDetail, ComTimeoutWanB);
Expand Down Expand Up @@ -762,13 +781,28 @@ class ComCameraStreamCtrl : public ComCommand
ComErrno exec(const com_command_exec_data_t &data)
{
if (data.connectMode == COM_CONNECT_LAN) {
return COM_UNSUPPORTED;
// The network library has no LAN camera entry point (there is no
// ctrlLanDev* counterpart to fnet_camera_stream_ctrl_t), so this
// previously returned COM_UNSUPPORTED. SingleDeviceState issues the
// "open" command precisely on a LAN connection, which meant the
// stream was never started and the device page showed no video on
// any locally connected printer.
//
// Post the command over the printer's local HTTP control endpoint
// instead. This is the same request the library performs for
// lightControl_cmd via fnet_ctrlLanDevLight, using the same
// ip/port/serialNumber/checkCode already carried in exec data.
return sendLanCameraStreamCtrl(data, m_action);
} else {
return ComWanConn::inst()->sendCameraStreamCtrl(data.devTopic, m_cameraStreamCtrl);
}
}

private:
// Implemented in ComCommand.cpp to keep the HTTP client out of this header.
static ComErrno sendLanCameraStreamCtrl(const com_command_exec_data_t &data,
const std::string &action);

std::string m_action;
fnet_camera_stream_ctrl_t m_cameraStreamCtrl;
};
Expand Down
21 changes: 19 additions & 2 deletions src/slic3r/GUI/FlashForge/SingleDeviceState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3348,6 +3348,13 @@ wxString SingleDeviceState::convertSecondsToHMS(int totalSeconds)

void SingleDeviceState::fillValue(const com_dev_data_t& data,bool wanDev)
{
// devDetail is filled in by ComGetDevProductDetail, which can legitimately
// fail or not have run yet. Every read below goes through it, so bail out
// instead of dereferencing null.
if (data.devDetail == nullptr) {
BOOST_LOG_TRIVIAL(debug) << "fillValue: devDetail not available yet";
return;
}
std::string state = data.devDetail->status; // 状态
if (wanDev) {
state = data.wanDevInfo.status;
Expand All @@ -3361,14 +3368,24 @@ void SingleDeviceState::fillValue(const com_dev_data_t& data,bool wanDev)
m_busy_lamp_bar->SetCameraState(false);
m_idle_lamp_bar->SetCameraState(false);
std::string stram_url = data.devDetail->cameraStreamUrl;
if (!stram_url.empty() && m_camera_stream_url != data.devDetail->cameraStreamUrl) {
if (stram_url.empty() && data.connectMode == COM_CONNECT_LAN &&
data.lanDevInfo.ip[0] != '\0') {
// Some firmware reports camera support without also reporting a stream
// URL on a LAN connection. The camera serves the usual MJPEG endpoint
// regardless, so fall back to the local address rather than leaving the
// panel with nothing to load.
constexpr unsigned short cameraStreamPort = 8080;
stram_url = std::string("http://") + data.lanDevInfo.ip + ":" +
std::to_string(cameraStreamPort) + "/?action=stream";
}
if (!stram_url.empty() && m_camera_stream_url != stram_url) {
if (0 == data.connectMode) {
// 通知设备开流
ComCameraStreamCtrl *cameraStreamCtrl = new ComCameraStreamCtrl(OPEN);
Slic3r::GUI::MultiComMgr::inst()->putCommand(m_cur_id, cameraStreamCtrl);
}

m_camera_stream_url = data.devDetail->cameraStreamUrl;
m_camera_stream_url = stram_url;
m_camera_panel->setStreamUrl(m_camera_stream_url);
} else if (stram_url.empty()) {
m_camera_panel->setOffline();
Expand Down