mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-18 22:42:37 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91c6d1d3d5 | ||
|
|
b91f48141d | ||
|
|
467e249b3d | ||
|
|
bc03e3be2f | ||
|
|
5287fd0160 | ||
|
|
c441fd2fa4 | ||
|
|
f224b8e4a6 | ||
|
|
8b479c9af3 | ||
|
|
d8299c388e | ||
|
|
771d455d12 | ||
|
|
4d85b6627e |
Vendored
+1
-1
@@ -14,7 +14,7 @@ orcaslicer_add_cmake_project(DataChannel
|
||||
-DOPENSSL_ROOT_DIR:PATH=${DESTDIR}
|
||||
-DOPENSSL_USE_STATIC_LIBS=ON
|
||||
GIT_REPOSITORY https://github.com/paullouisageneau/libdatachannel.git
|
||||
GIT_TAG v0.22.2
|
||||
GIT_TAG v0.24.5
|
||||
GIT_SHALLOW ON
|
||||
GIT_SUBMODULES_RECURSE ON
|
||||
)
|
||||
|
||||
@@ -325,11 +325,10 @@ modules:
|
||||
sha256: deedcabe339165214a3637df4c86a507aef0d793cf8774ff68735f4737e8ddbc
|
||||
dest: external-packages/FFMPEG
|
||||
|
||||
# libdatachannel v0.22.2
|
||||
- type: git
|
||||
url: https://github.com/paullouisageneau/libdatachannel.git
|
||||
tag: v0.22.2
|
||||
commit: b3390b4e01e97071dd054684870c4bb5221794bf
|
||||
# libdatachannel v0.24.5
|
||||
- type: file
|
||||
url: https://github.com/paullouisageneau/libdatachannel/archive/refs/tags/v0.24.5.tar.gz
|
||||
sha256: 454537c3cd526bed935d847bb2dff4046f266eef84d43b2a5f2f2f293c0026f4
|
||||
dest: deps/build_flatpak/dep_DataChannel-prefix/src/dep_DataChannel
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -856,7 +856,7 @@ target_include_directories(libslic3r_gui PRIVATE Utils ${CMAKE_CURRENT_BINARY_DI
|
||||
|
||||
if (WIN32)
|
||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../deps/WebView2/include)
|
||||
target_link_libraries(libslic3r_gui Advapi32)
|
||||
target_link_libraries(libslic3r_gui Advapi32 Crypt32)
|
||||
endif()
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES})
|
||||
|
||||
@@ -583,7 +583,7 @@ namespace Slic3r
|
||||
<< " printer_agent_id=" << it->second->printer_agent_id
|
||||
<< " connection_type=" << it->second->connection_type()
|
||||
<< " dev_connection_type=" << it->second->dev_connection_type;
|
||||
} else {
|
||||
} else if (!dev_id.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: target machine was not found in the current agent's machine list";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1487,29 +1487,17 @@ int MachineObject::command_upgrade_module(std::string url, std::string module_ty
|
||||
|
||||
int MachineObject::command_xyz_abs()
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_xyz_abs(get_dev_id(), MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_xyz_abs(get_dev_id(), MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_auto_leveling()
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_auto_leveling(get_dev_id(), MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_auto_leveling(get_dev_id(), MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_go_home()
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_go_home(get_dev_id(), this->is_in_printing(), m_support_mqtt_homing, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_go_home(get_dev_id(), this->is_in_printing(), m_support_mqtt_homing, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_task_partskip(std::vector<int> part_ids)
|
||||
@@ -1631,20 +1619,12 @@ int MachineObject::command_stop_buzzer()
|
||||
|
||||
int MachineObject::command_set_bed(int temp)
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_set_bed(get_dev_id(), temp, m_support_mqtt_bet_ctrl, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_set_bed(get_dev_id(), temp, m_support_mqtt_bet_ctrl, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_set_nozzle(int temp)
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_set_nozzle(get_dev_id(), temp, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_set_nozzle(get_dev_id(), temp, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_set_nozzle_new(int nozzle_id, int temp)
|
||||
@@ -1749,11 +1729,7 @@ int MachineObject::command_ams_user_settings(bool start_read_opt, bool tray_read
|
||||
|
||||
int MachineObject::command_ams_calibrate(int ams_id)
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_ams_calibrate(get_dev_id(), ams_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_ams_calibrate(get_dev_id(), ams_id, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max)
|
||||
@@ -1791,11 +1767,7 @@ int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::s
|
||||
|
||||
int MachineObject::command_ams_refresh_rfid(std::string tray_id)
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_ams_refresh_rfid(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_ams_refresh_rfid(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_ams_refresh_rfid2(int ams_id, int slot_id)
|
||||
@@ -1817,11 +1789,7 @@ int MachineObject::command_start_camera()
|
||||
|
||||
int MachineObject::command_ams_select_tray(std::string tray_id)
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_ams_select_tray(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_ams_select_tray(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_ams_control(std::string action)
|
||||
@@ -1980,12 +1948,9 @@ int MachineObject::command_ams_air_print_detect(bool air_print_detect)
|
||||
|
||||
int MachineObject::command_axis_control(std::string axis, double unit, double input_val, int speed)
|
||||
{
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_axis_control(get_dev_id(), axis, unit, input_val, speed, is_core_xy(),
|
||||
m_support_mqtt_axis_control, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
return command_with_dialog(m_agent->command_axis_control(get_dev_id(), axis, unit, input_val, speed, is_core_xy(),
|
||||
m_support_mqtt_axis_control, MachineObject::m_sequence_id++,
|
||||
is_lan_mode_printer()));
|
||||
}
|
||||
|
||||
int MachineObject::command_extruder_control(int nozzle_id, double val)
|
||||
@@ -6045,6 +6010,15 @@ bool MachineObject::HasAms() const
|
||||
return m_fila_system->HasAms();
|
||||
}
|
||||
|
||||
int MachineObject::command_with_dialog(int cmd_result)
|
||||
{
|
||||
if (!m_agent)
|
||||
return -1;
|
||||
if (cmd_result == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || cmd_result == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(cmd_result);
|
||||
return cmd_result;
|
||||
}
|
||||
|
||||
void change_the_opacity(wxColour& colour)
|
||||
{
|
||||
if (colour.Alpha() == 255) {
|
||||
|
||||
@@ -976,7 +976,7 @@ public:
|
||||
void command_set_save_remote_print_file_to_storage(bool save);
|
||||
|
||||
private:
|
||||
|
||||
int command_with_dialog(int cmd_result);
|
||||
/* xcam door open check*/
|
||||
bool is_support_door_open_check = false;
|
||||
DoorOpenCheckState xcam_door_open_check = DoorOpenCheckState::DOOR_OPEN_CHECK_DISABLE;
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
#include <wx/mediactrl.h>
|
||||
#include <wx/uri.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <slic3r/Utils/IPrinterAgent.hpp>
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
class IMediaController
|
||||
@@ -16,13 +12,6 @@ public:
|
||||
|
||||
virtual void Load(wxURI url) = 0;
|
||||
|
||||
// The default keeps existing media controllers unaware of camera-specific modes.
|
||||
virtual void Load(wxURI url, CameraStreamMode mode)
|
||||
{
|
||||
(void) mode;
|
||||
Load(url);
|
||||
}
|
||||
|
||||
virtual void Play() = 0;
|
||||
|
||||
virtual void Stop() = 0;
|
||||
@@ -32,15 +21,6 @@ public:
|
||||
virtual int GetLastError() const { return {}; };
|
||||
|
||||
virtual wxSize GetVideoSize() const { return {}; };
|
||||
|
||||
virtual void StartSession(std::unique_ptr<ICameraSignalingChannel> channel)
|
||||
{
|
||||
(void) channel;
|
||||
}
|
||||
|
||||
virtual void StopSession() {}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
+188
-185
@@ -1,4 +1,6 @@
|
||||
#include "MediaPlayCtrl.h"
|
||||
#include "WebMediaController.hpp"
|
||||
#include "IPrinterAgent.hpp"
|
||||
#include "Widgets/Button.hpp"
|
||||
#include "Widgets/CheckBox.hpp"
|
||||
#include "Widgets/Label.hpp"
|
||||
@@ -24,6 +26,7 @@
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/nowide/utf8_codecvt.hpp>
|
||||
#include <slic3r/GUI/DeviceManager.hpp>
|
||||
#include <wx/mediactrl.h>
|
||||
#undef pid_t
|
||||
#include <boost/process.hpp>
|
||||
#ifdef __WIN32__
|
||||
@@ -52,6 +55,7 @@ namespace GUI {
|
||||
MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl3 *media_ctrl, const wxPoint &pos, const wxSize &size)
|
||||
: wxPanel(parent, wxID_ANY, pos, size)
|
||||
, m_media_ctrl(media_ctrl)
|
||||
, m_active_media_controller(media_ctrl)
|
||||
{
|
||||
SetLabel("MediaPlayCtrl");
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
@@ -98,7 +102,10 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl3 *media_ctrl, const w
|
||||
});
|
||||
|
||||
m_button_play->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto &e) { TogglePlay(); });
|
||||
m_button_play->Bind(wxEVT_RIGHT_UP, [this](auto & e) { m_media_ctrl->Play(); });
|
||||
m_button_play->Bind(wxEVT_RIGHT_UP, [this](auto & e) {
|
||||
if (m_active_media_controller)
|
||||
m_active_media_controller->Play();
|
||||
});
|
||||
// Orca: live-view FAQ link binding removed (vendor URL)
|
||||
|
||||
Bind(wxEVT_RIGHT_UP, [this](auto & e) {
|
||||
@@ -143,14 +150,12 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl3 *media_ctrl, const w
|
||||
|
||||
MediaPlayCtrl::~MediaPlayCtrl()
|
||||
{
|
||||
m_webrtc_stopping = true;
|
||||
if (m_webrtc_ctrl)
|
||||
m_webrtc_ctrl->StopSession();
|
||||
m_webrtc_ctrl->Stop();
|
||||
m_media_ctrl->EndExternalStream();
|
||||
m_webrtc_stopping = false;
|
||||
{
|
||||
boost::unique_lock lock(m_mutex);
|
||||
m_tasks.push_back("<exit>");
|
||||
m_tasks.push_back({"<exit>", nullptr});
|
||||
m_cond.notify_all();
|
||||
}
|
||||
while (!m_thread.try_join_for(boost::chrono::milliseconds(10))) {
|
||||
@@ -163,6 +168,33 @@ MediaPlayCtrl::~MediaPlayCtrl()
|
||||
void MediaPlayCtrl::SetWebMediaController(IMediaController *ctrl)
|
||||
{
|
||||
m_web_ctrl = ctrl;
|
||||
set_active_media_controller(current_mode());
|
||||
}
|
||||
|
||||
void MediaPlayCtrl::set_active_media_controller(CameraStreamMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case CameraStreamMode::http_snapshot:
|
||||
if (auto *web_ctrl = dynamic_cast<WebMediaController *>(m_web_ctrl))
|
||||
web_ctrl->set_mode(mode);
|
||||
m_active_media_controller = m_web_ctrl;
|
||||
break;
|
||||
case CameraStreamMode::webrtc:
|
||||
if (!m_webrtc_ctrl) {
|
||||
m_webrtc_ctrl = std::make_unique<WebRtcMediaController>(
|
||||
[this](const wxImage& image, wxSize size) { m_media_ctrl->SetExternalFrame(image, size); },
|
||||
[this, token = std::weak_ptr<int>(m_token)](WebRtcMediaController::Status status) {
|
||||
if (token.expired())
|
||||
return;
|
||||
CallAfter([this, status] { on_webrtc_status(status); });
|
||||
});
|
||||
}
|
||||
m_active_media_controller = m_webrtc_ctrl.get();
|
||||
break;
|
||||
default:
|
||||
m_active_media_controller = m_media_ctrl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CameraStreamMode MediaPlayCtrl::current_mode() const
|
||||
@@ -181,105 +213,96 @@ void MediaPlayCtrl::SetMachineObject(MachineObject* obj)
|
||||
}
|
||||
m_last_mode = mode;
|
||||
}
|
||||
set_active_media_controller(mode);
|
||||
|
||||
switch (mode) {
|
||||
case CameraStreamMode::http:
|
||||
case CameraStreamMode::https:
|
||||
case CameraStreamMode::http_snapshot:
|
||||
case CameraStreamMode::rtsp: {
|
||||
std::string machine = obj ? obj->get_dev_id() : "";
|
||||
const bool uses_local_camera_url = mode == CameraStreamMode::http || mode == CameraStreamMode::https ||
|
||||
mode == CameraStreamMode::http_snapshot || mode == CameraStreamMode::rtsp;
|
||||
const bool uses_webrtc = mode == CameraStreamMode::webrtc;
|
||||
const std::string machine = obj ? obj->get_dev_id() : "";
|
||||
bool changed = false;
|
||||
|
||||
if (uses_local_camera_url) {
|
||||
auto agent = wxGetApp().getAgent();
|
||||
std::string url = agent ? agent->get_local_camera_stream_url() : "";
|
||||
m_camera_exists = !url.empty();
|
||||
Enable(obj && m_camera_exists);
|
||||
bool changed = machine != m_machine || url != m_agent_camera_url;
|
||||
m_machine = machine;
|
||||
changed = machine != m_machine || url != m_agent_camera_url;
|
||||
m_agent_camera_url = url;
|
||||
m_url = from_u8(url);
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
// A genuine machine/URL switch: not a failure, so drop any pending
|
||||
// failure back-off before (re)starting on the new target.
|
||||
m_web_user_stopped = false;
|
||||
m_failed_code = 0;
|
||||
m_failed_retry = 0;
|
||||
m_next_retry = wxDateTime();
|
||||
if (m_last_state != MEDIASTATE_IDLE)
|
||||
Stop(" ");
|
||||
return;
|
||||
}
|
||||
case CameraStreamMode::webrtc: {
|
||||
std::string machine = obj ? obj->get_dev_id() : "";
|
||||
m_url = from_u8(url);
|
||||
} else if (uses_webrtc) {
|
||||
m_camera_exists = obj != nullptr;
|
||||
Enable(obj != nullptr);
|
||||
const bool changed = machine != m_machine;
|
||||
changed = machine != m_machine;
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::SetMachineObject webrtc: changed=" << changed
|
||||
<< " last_state=" << m_last_state << " web_user_stopped=" << m_web_user_stopped;
|
||||
m_machine = machine;
|
||||
m_url.clear();
|
||||
m_agent_camera_url.clear();
|
||||
if (!changed) {
|
||||
} else {
|
||||
if (obj) {
|
||||
m_camera_exists = obj->has_ipcam;
|
||||
m_dev_ver = obj->get_ota_version();
|
||||
m_lan_mode = obj->is_lan_mode_printer();
|
||||
m_lan_proto = obj->liveview_local;
|
||||
m_remote_proto = obj->get_liveview_remote();
|
||||
m_lan_ip = obj->get_dev_ip();
|
||||
m_lan_passwd = obj->get_access_code();
|
||||
m_device_busy = obj->is_camera_busy_off();
|
||||
m_tutk_state = obj->tutk_state;
|
||||
|
||||
if (DevPrinterConfigUtil::get_printer_series_str(obj->printer_type) == "series_o" && BBLNetworkPlugin::instance().use_legacy_network()) {
|
||||
// Legacy plugin cannot support remote play for H2D, force using local mode
|
||||
m_remote_proto = LiveviewRemote::LVR_None;
|
||||
}
|
||||
} else {
|
||||
m_camera_exists = false;
|
||||
m_lan_mode = false;
|
||||
m_lan_proto = LiveviewLocal::LVL_None;
|
||||
m_lan_ip.clear();
|
||||
m_lan_passwd.clear();
|
||||
m_dev_ver.clear();
|
||||
m_tutk_state.clear();
|
||||
m_remote_proto = 0;
|
||||
m_device_busy = false;
|
||||
}
|
||||
Enable(obj && obj->is_info_ready() && obj->m_push_count > 0);
|
||||
if (machine == m_machine)
|
||||
return;
|
||||
|
||||
m_machine = machine;
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl switch machine: " << m_machine;
|
||||
m_disable_lan = false;
|
||||
m_failed_retry = 0;
|
||||
m_last_failed_codes.clear();
|
||||
m_last_user_play = wxDateTime::Now();
|
||||
std::string stream_url;
|
||||
if (get_stream_url(&stream_url)) {
|
||||
m_streaming = boost::algorithm::contains(stream_url, "device=" + m_machine);
|
||||
} else {
|
||||
m_streaming = false;
|
||||
}
|
||||
m_web_user_stopped = false;
|
||||
if (m_last_state != MEDIASTATE_IDLE)
|
||||
Stop(" ");
|
||||
if (m_next_retry.IsValid()) // Try open 2 seconds later, to avoid state conflict
|
||||
m_next_retry = wxDateTime::Now() + wxTimeSpan::Seconds(2);
|
||||
else
|
||||
SetStatus("", false);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
std::string machine = obj ? obj->get_dev_id() : "";
|
||||
if (obj) {
|
||||
m_camera_exists = obj->has_ipcam;
|
||||
m_dev_ver = obj->get_ota_version();
|
||||
m_lan_mode = obj->is_lan_mode_printer();
|
||||
m_lan_proto = obj->liveview_local;
|
||||
m_remote_proto = obj->get_liveview_remote();
|
||||
m_lan_ip = obj->get_dev_ip();
|
||||
m_lan_passwd = obj->get_access_code();
|
||||
m_device_busy = obj->is_camera_busy_off();
|
||||
m_tutk_state = obj->tutk_state;
|
||||
|
||||
if (DevPrinterConfigUtil::get_printer_series_str(obj->printer_type) == "series_o" && BBLNetworkPlugin::instance().use_legacy_network()) {
|
||||
// Legacy plugin cannot support remote play for H2D, force using local mode
|
||||
m_remote_proto = LiveviewRemote::LVR_None;
|
||||
}
|
||||
} else {
|
||||
m_camera_exists = false;
|
||||
m_lan_mode = false;
|
||||
m_lan_proto = LiveviewLocal::LVL_None;
|
||||
m_lan_ip.clear();
|
||||
m_lan_passwd.clear();
|
||||
m_dev_ver.clear();
|
||||
m_tutk_state.clear();
|
||||
m_remote_proto = 0;
|
||||
m_device_busy = false;
|
||||
}
|
||||
Enable(obj && obj->is_info_ready() && obj->m_push_count > 0);
|
||||
if (machine == m_machine) {
|
||||
return;
|
||||
}
|
||||
m_machine = machine;
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl switch machine: " << m_machine;
|
||||
m_disable_lan = false;
|
||||
m_failed_retry = 0;
|
||||
m_last_failed_codes.clear();
|
||||
m_last_user_play = wxDateTime::Now();
|
||||
std::string stream_url;
|
||||
if (get_stream_url(&stream_url)) {
|
||||
m_streaming = boost::algorithm::contains(stream_url, "device=" + m_machine);
|
||||
} else {
|
||||
m_streaming = false;
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
// A genuine target switch is not a stream failure and should clear the
|
||||
// manual-stop state before the new target is allowed to play.
|
||||
m_web_user_stopped = false;
|
||||
if (uses_local_camera_url) {
|
||||
m_failed_code = 0;
|
||||
m_failed_retry = 0;
|
||||
m_next_retry = wxDateTime();
|
||||
}
|
||||
if (m_last_state != MEDIASTATE_IDLE)
|
||||
Stop(" ");
|
||||
if (m_next_retry.IsValid()) // Try open 2 seconds later, to avoid state conflict
|
||||
m_next_retry = wxDateTime::Now() + wxTimeSpan::Seconds(2);
|
||||
else
|
||||
SetStatus("", false);
|
||||
}
|
||||
|
||||
wxString hide_id_middle_string(wxString const &str, size_t offset = 0, size_t length = -1)
|
||||
@@ -330,97 +353,71 @@ void refresh_agora_url(char const* device, char const* dev_ver, char const* chan
|
||||
|
||||
void MediaPlayCtrl::Play()
|
||||
{
|
||||
switch (current_mode()) {
|
||||
case CameraStreamMode::http_snapshot:
|
||||
if (!m_next_retry.IsValid() || wxDateTime::Now() < m_next_retry)
|
||||
if ((m_next_retry.IsValid() && wxDateTime::Now() < m_next_retry) || !IsShownOnScreen() || m_last_state != MEDIASTATE_IDLE)
|
||||
return;
|
||||
|
||||
const CameraStreamMode mode = current_mode();
|
||||
set_active_media_controller(mode);
|
||||
m_last_mode = mode;
|
||||
auto agent = wxGetApp().getAgent();
|
||||
|
||||
auto printer_agent = agent ? agent->get_printer_agent() : nullptr;
|
||||
const bool is_bbl = (printer_agent ? printer_agent->get_agent_info().id : "") == BBL_PRINTER_AGENT_ID;
|
||||
|
||||
if (!is_bbl) {
|
||||
const bool is_webrtc = mode == CameraStreamMode::webrtc;
|
||||
const bool is_snapshot = mode == CameraStreamMode::http_snapshot;
|
||||
const bool is_http_stream = mode == CameraStreamMode::http || mode == CameraStreamMode::https || mode == CameraStreamMode::rtsp;
|
||||
if (!is_webrtc && !is_snapshot && !is_http_stream)
|
||||
return;
|
||||
if (!IsShownOnScreen()) return;
|
||||
if (m_last_state != MEDIASTATE_IDLE) return;
|
||||
if (m_machine.empty() || !IsEnabled() || !m_camera_exists || m_url.IsEmpty() || !m_web_ctrl) {
|
||||
|
||||
auto *webrtc_ctrl = is_webrtc ? dynamic_cast<WebRtcMediaController *>(m_active_media_controller) : nullptr;
|
||||
if (is_webrtc && (!webrtc_ctrl || !m_media_ctrl)) {
|
||||
Stop(_L("Please confirm if the printer is connected."));
|
||||
return;
|
||||
}
|
||||
m_button_play->SetIcon("media_stop");
|
||||
m_web_ctrl->Load(wxURI(m_url), current_mode());
|
||||
m_web_ctrl->Play();
|
||||
m_last_state = wxMEDIASTATE_PLAYING;
|
||||
SetStatus(_L("Playing..."), false);
|
||||
return;
|
||||
case CameraStreamMode::http:
|
||||
case CameraStreamMode::https:
|
||||
case CameraStreamMode::rtsp:
|
||||
if (m_next_retry.IsValid() && wxDateTime::Now() < m_next_retry)
|
||||
if (webrtc_ctrl && webrtc_ctrl->is_active())
|
||||
return;
|
||||
if (!IsShownOnScreen()) return;
|
||||
if (m_last_state != MEDIASTATE_IDLE) return;
|
||||
|
||||
m_failed_code = 0;
|
||||
if (m_machine.empty() || !IsEnabled() || !m_camera_exists || m_url.IsEmpty()) {
|
||||
if (!m_active_media_controller || m_machine.empty() || !IsEnabled() || !m_camera_exists ||
|
||||
(!is_webrtc && m_url.IsEmpty())) {
|
||||
Stop(_L("Please confirm if the printer is connected."));
|
||||
return;
|
||||
}
|
||||
m_button_play->SetIcon("media_stop");
|
||||
load();
|
||||
return;
|
||||
case CameraStreamMode::webrtc: {
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::Play webrtc: last_state=" << m_last_state
|
||||
<< " next_retry_valid=" << m_next_retry.IsValid()
|
||||
<< " next_retry_future=" << (m_next_retry.IsValid() && wxDateTime::Now() < m_next_retry)
|
||||
<< " failed_retry=" << m_failed_retry << " shown=" << IsShownOnScreen();
|
||||
if (m_webrtc_ctrl && m_webrtc_ctrl->is_active()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::Play webrtc: session already active, ignoring";
|
||||
return;
|
||||
}
|
||||
if (m_next_retry.IsValid() && wxDateTime::Now() < m_next_retry)
|
||||
return;
|
||||
if (!IsShownOnScreen() || m_last_state != MEDIASTATE_IDLE)
|
||||
return;
|
||||
m_failed_code = 0;
|
||||
if (m_machine.empty() || !IsEnabled() || !m_camera_exists) {
|
||||
Stop(_L("Please confirm if the printer is connected."));
|
||||
return;
|
||||
}
|
||||
auto agent = wxGetApp().getAgent();
|
||||
auto channel = agent ? agent->create_camera_signaling_channel(m_machine) : nullptr;
|
||||
if (!channel) {
|
||||
Stop(_L("Sign in to OrcaCloud to view the camera."));
|
||||
return;
|
||||
}
|
||||
if (!m_webrtc_ctrl) {
|
||||
m_webrtc_ctrl = std::make_unique<WebRtcMediaController>(
|
||||
[this](const wxImage& image, wxSize size) { m_media_ctrl->SetExternalFrame(image, size); },
|
||||
[this, token = std::weak_ptr<int>(m_token)](WebRtcMediaController::Status status) {
|
||||
if (token.expired())
|
||||
return;
|
||||
CallAfter([this, status] { on_webrtc_status(status); });
|
||||
});
|
||||
}
|
||||
m_button_play->SetIcon("media_stop");
|
||||
m_media_ctrl->BeginExternalStream();
|
||||
m_last_state = MEDIASTATE_INITIALIZING;
|
||||
SetStatus(_L("Initializing..."), false);
|
||||
m_webrtc_stopping = false;
|
||||
m_webrtc_ctrl->StartSession(std::move(channel));
|
||||
m_webrtc_epoch = m_webrtc_ctrl->epoch();
|
||||
return;
|
||||
}
|
||||
default: // assumed to be CameraStreamMode::none
|
||||
if (NetworkAgent* agent = wxGetApp().getAgent()) {
|
||||
if (auto printer_agent = agent->get_printer_agent()) {
|
||||
if (printer_agent->get_agent_info().id != BBL_PRINTER_AGENT_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_webrtc) {
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::Play webrtc: last_state=" << m_last_state << " failed_retry=" << m_failed_retry
|
||||
<< " shown=" << IsShownOnScreen();
|
||||
auto channel = agent ? agent->create_camera_signaling_channel(m_machine) : nullptr;
|
||||
if (!channel) {
|
||||
Stop(_L("Sign in to OrcaCloud to view the camera."));
|
||||
return;
|
||||
}
|
||||
webrtc_ctrl->set_signalling_channel(std::move(channel));
|
||||
m_media_ctrl->BeginExternalStream();
|
||||
m_last_state = MEDIASTATE_INITIALIZING;
|
||||
SetStatus(_L("Initializing..."), false);
|
||||
} else if (is_snapshot) {
|
||||
m_last_state = wxMEDIASTATE_PLAYING;
|
||||
SetStatus(_L("Playing..."), false);
|
||||
}
|
||||
break;
|
||||
|
||||
m_button_play->SetIcon("media_stop");
|
||||
if (m_active_media_controller == m_media_ctrl) {
|
||||
// wxMediaCtrl3 reports when it has a decoded frame; load() waits for
|
||||
// that event before queuing Play so the stream is not marked stopped.
|
||||
load();
|
||||
} else {
|
||||
m_active_media_controller->Load(wxURI(m_url));
|
||||
m_active_media_controller->Play();
|
||||
}
|
||||
if (webrtc_ctrl) {
|
||||
m_webrtc_epoch = webrtc_ctrl->epoch();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_next_retry.IsValid() || wxDateTime::Now() < m_next_retry)
|
||||
return;
|
||||
if (!IsShownOnScreen())
|
||||
return;
|
||||
if (m_last_state != MEDIASTATE_IDLE) {
|
||||
return;
|
||||
}
|
||||
m_failed_code = 0;
|
||||
if (m_machine.empty()) {
|
||||
Stop(_L("Please confirm if the printer is connected."));
|
||||
@@ -441,7 +438,6 @@ void MediaPlayCtrl::Play()
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::Play: " << m_lan_proto << m_remote_proto << m_disable_lan;
|
||||
NetworkAgent *agent = wxGetApp().getAgent();
|
||||
std::string agent_version = agent ? agent->get_version() : "";
|
||||
if (m_lan_proto > LiveviewLocal::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) {
|
||||
m_disable_lan = m_remote_proto && !m_lan_mode; // try remote next time
|
||||
@@ -545,8 +541,8 @@ void MediaPlayCtrl::StopWebStream()
|
||||
{
|
||||
if (m_last_state == MEDIASTATE_IDLE)
|
||||
return;
|
||||
if (m_web_ctrl)
|
||||
m_web_ctrl->Stop();
|
||||
if (m_active_media_controller && m_active_media_controller == m_web_ctrl)
|
||||
m_active_media_controller->Stop();
|
||||
m_button_play->SetIcon("media_play");
|
||||
m_last_state = MEDIASTATE_IDLE;
|
||||
SetStatus(_L("Video Stopped."), false);
|
||||
@@ -554,15 +550,14 @@ void MediaPlayCtrl::StopWebStream()
|
||||
|
||||
void MediaPlayCtrl::Stop(wxString const &msg, wxString const &msg2)
|
||||
{
|
||||
const bool webrtc_active = m_webrtc_ctrl && m_last_mode == CameraStreamMode::webrtc;
|
||||
const bool webrtc_active = m_last_mode == CameraStreamMode::webrtc &&
|
||||
dynamic_cast<WebRtcMediaController *>(m_active_media_controller) != nullptr;
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::Stop: last_state=" << m_last_state
|
||||
<< " webrtc_active=" << webrtc_active << " failed_code=" << m_failed_code
|
||||
<< " msg='" << msg.ToUTF8().data() << "'";
|
||||
if (webrtc_active) {
|
||||
m_webrtc_stopping = true;
|
||||
m_webrtc_ctrl->StopSession();
|
||||
m_active_media_controller->Stop();
|
||||
m_media_ctrl->EndExternalStream();
|
||||
m_webrtc_stopping = false;
|
||||
}
|
||||
switch (m_last_mode) {
|
||||
case CameraStreamMode::http:
|
||||
@@ -571,13 +566,14 @@ void MediaPlayCtrl::Stop(wxString const &msg, wxString const &msg2)
|
||||
const bool snapshot = m_last_mode == CameraStreamMode::http_snapshot;
|
||||
if (m_last_state != MEDIASTATE_IDLE) {
|
||||
if (snapshot) {
|
||||
if (m_web_ctrl) m_web_ctrl->Stop();
|
||||
if (m_active_media_controller)
|
||||
m_active_media_controller->Stop();
|
||||
} else {
|
||||
// http/https mode plays through the ffmpeg backend (m_media_ctrl), not
|
||||
// the webview - tear its read thread down too, otherwise it keeps
|
||||
// pulling and painting frames after the UI says "Video Stopped".
|
||||
boost::unique_lock lock(m_mutex);
|
||||
m_tasks.push_back("<stop>");
|
||||
m_tasks.push_back({"<stop>", m_active_media_controller});
|
||||
m_cond.notify_all();
|
||||
}
|
||||
m_button_play->SetIcon("media_play");
|
||||
@@ -611,7 +607,8 @@ void MediaPlayCtrl::Stop(wxString const &msg, wxString const &msg2)
|
||||
m_media_ctrl->InvalidateBestSize();
|
||||
m_button_play->SetIcon("media_play");
|
||||
boost::unique_lock lock(m_mutex);
|
||||
m_tasks.push_back("<stop>");
|
||||
if (!webrtc_active)
|
||||
m_tasks.push_back({"<stop>", m_active_media_controller});
|
||||
m_cond.notify_all();
|
||||
if (!msg.IsEmpty())
|
||||
SetStatus(msg);
|
||||
@@ -678,7 +675,7 @@ void MediaPlayCtrl::Stop(wxString const &msg, wxString const &msg2)
|
||||
|
||||
void MediaPlayCtrl::on_webrtc_status(WebRtcMediaController::Status status)
|
||||
{
|
||||
// Drop CallAfter-queued events from a superseded StartSession attempt.
|
||||
// Drop CallAfter-queued events from a superseded Play attempt.
|
||||
if (status.epoch != m_webrtc_epoch)
|
||||
return;
|
||||
if (status.kind == WebRtcMediaController::Status::Connecting) {
|
||||
@@ -839,7 +836,9 @@ void MediaPlayCtrl::jump_to_play()
|
||||
void MediaPlayCtrl::onStateChanged(wxMediaEvent &event)
|
||||
{
|
||||
auto last_state = m_last_state;
|
||||
auto state = m_media_ctrl->GetState();
|
||||
if (m_active_media_controller != m_media_ctrl)
|
||||
return;
|
||||
auto state = m_active_media_controller->GetState();
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::onStateChanged: " << state << ", last_state: " << last_state;
|
||||
if ((int) state < 0) return;
|
||||
{
|
||||
@@ -851,14 +850,14 @@ void MediaPlayCtrl::onStateChanged(wxMediaEvent &event)
|
||||
}
|
||||
if ((last_state == MEDIASTATE_IDLE || last_state == MEDIASTATE_INITIALIZING) && state == wxMEDIASTATE_STOPPED) { return; }
|
||||
if ((last_state == wxMEDIASTATE_PAUSED || last_state == wxMEDIASTATE_PLAYING) && state == wxMEDIASTATE_STOPPED) {
|
||||
m_failed_code = m_media_ctrl->GetLastError();
|
||||
m_failed_code = m_active_media_controller->GetLastError();
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
if (last_state == MEDIASTATE_LOADING && (state == wxMEDIASTATE_STOPPED || state == wxMEDIASTATE_PAUSED)) {
|
||||
wxSize size = m_media_ctrl->GetVideoSize();
|
||||
wxSize size = m_active_media_controller->GetVideoSize();
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::onStateChanged: size: " << size.x << "x" << size.y;
|
||||
m_failed_code = m_media_ctrl->GetLastError();
|
||||
m_failed_code = m_active_media_controller->GetLastError();
|
||||
if (size.GetWidth() >= 320) {
|
||||
m_last_state = state;
|
||||
m_failed_code = 0;
|
||||
@@ -868,7 +867,7 @@ void MediaPlayCtrl::onStateChanged(wxMediaEvent &event)
|
||||
m_failed_retry = 0;
|
||||
m_disable_lan = false;
|
||||
boost::unique_lock lock(m_mutex);
|
||||
m_tasks.push_back("<play>");
|
||||
m_tasks.push_back({"<play>", m_active_media_controller});
|
||||
m_cond.notify_all();
|
||||
} else if (event.GetId()) {
|
||||
if (m_failed_code == 0)
|
||||
@@ -923,7 +922,7 @@ void MediaPlayCtrl::load()
|
||||
m_url = m_url + "&dump_info=" + boost::lexical_cast<std::string>(dump_info_file);
|
||||
}
|
||||
boost::unique_lock lock(m_mutex);
|
||||
m_tasks.push_back(m_url);
|
||||
m_tasks.push_back({m_url, m_active_media_controller});
|
||||
m_cond.notify_all();
|
||||
}
|
||||
|
||||
@@ -943,30 +942,34 @@ void MediaPlayCtrl::media_proc()
|
||||
while (m_tasks.empty()) {
|
||||
m_cond.wait(lock);
|
||||
}
|
||||
wxString url = m_tasks.front();
|
||||
if (m_tasks.size() >= 2 && !url.IsEmpty() && url[0] != '<' && m_tasks[1] == "<stop>") {
|
||||
BOOST_LOG_TRIVIAL(trace) << "MediaPlayCtrl: busy skip url: " << url;
|
||||
MediaTask task = m_tasks.front();
|
||||
if (m_tasks.size() >= 2 && !task.command.IsEmpty() && task.command[0] != '<' &&
|
||||
m_tasks[1].command == "<stop>" && task.controller == m_tasks[1].controller) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "MediaPlayCtrl: busy skip url: " << task.command;
|
||||
m_tasks.pop_front();
|
||||
m_tasks.pop_front();
|
||||
continue;
|
||||
}
|
||||
lock.unlock();
|
||||
if (url == "<stop>") {
|
||||
if (task.command == "<stop>") {
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: start stop";
|
||||
m_media_ctrl->Stop();
|
||||
if (task.controller)
|
||||
task.controller->Stop();
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: end stop";
|
||||
}
|
||||
else if (url == "<exit>") {
|
||||
else if (task.command == "<exit>") {
|
||||
break;
|
||||
}
|
||||
else if (url == "<play>") {
|
||||
else if (task.command == "<play>") {
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: start play";
|
||||
m_media_ctrl->Play();
|
||||
if (task.controller)
|
||||
task.controller->Play();
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: end play";
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: start load";
|
||||
m_media_ctrl->Load(wxURI(url));
|
||||
if (task.controller)
|
||||
task.controller->Load(wxURI(task.command));
|
||||
BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: end load";
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
@@ -75,6 +75,7 @@ private:
|
||||
static bool get_stream_url(std::string *url = nullptr);
|
||||
|
||||
CameraStreamMode current_mode() const;
|
||||
void set_active_media_controller(CameraStreamMode mode);
|
||||
|
||||
private:
|
||||
static inline const wxMediaState MEDIASTATE_IDLE = static_cast<wxMediaState>(3);
|
||||
@@ -86,10 +87,10 @@ private:
|
||||
std::shared_ptr<int> m_token = std::make_shared<int>(0);
|
||||
|
||||
wxMediaCtrl3 * m_media_ctrl;
|
||||
IMediaController * m_active_media_controller = nullptr;
|
||||
IMediaController * m_web_ctrl = nullptr;
|
||||
std::unique_ptr<WebRtcMediaController> m_webrtc_ctrl;
|
||||
CameraStreamMode m_last_mode = CameraStreamMode::none;
|
||||
bool m_webrtc_stopping = false;
|
||||
std::uint64_t m_webrtc_epoch = 0;
|
||||
std::string m_agent_camera_url;
|
||||
bool m_web_user_stopped = false;
|
||||
@@ -108,7 +109,11 @@ private:
|
||||
bool m_disable_lan = false;
|
||||
wxString m_url;
|
||||
|
||||
std::deque<wxString> m_tasks;
|
||||
struct MediaTask {
|
||||
wxString command;
|
||||
IMediaController *controller = nullptr;
|
||||
};
|
||||
std::deque<MediaTask> m_tasks;
|
||||
boost::mutex m_mutex;
|
||||
boost::condition_variable m_cond;
|
||||
boost::thread m_thread;
|
||||
|
||||
@@ -13,11 +13,13 @@ WebMediaController::WebMediaController(wxWebView* webview) : m_webview(webview)
|
||||
m_webview->SetPage("<html><head><style>html,body{margin:0;height:100%;background:#000;}</style></head><body></body></html>", "");
|
||||
}
|
||||
|
||||
void WebMediaController::Load(wxURI url) { Load(url, CameraStreamMode::http); }
|
||||
void WebMediaController::Load(wxURI url)
|
||||
{
|
||||
m_url = url.BuildURI().ToStdString();
|
||||
}
|
||||
|
||||
void WebMediaController::Load(wxURI url, CameraStreamMode mode)
|
||||
void WebMediaController::set_mode(CameraStreamMode mode)
|
||||
{
|
||||
m_url = url.BuildURI().ToStdString();
|
||||
m_stream_mode = mode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <slic3r/GUI/IMediaController.hpp>
|
||||
#include <slic3r/Utils/IPrinterAgent.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -15,7 +16,7 @@ public:
|
||||
|
||||
void Load(wxURI url) override;
|
||||
|
||||
void Load(wxURI url, CameraStreamMode mode) override;
|
||||
void set_mode(CameraStreamMode mode);
|
||||
|
||||
void Play() override;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ WebRtcMediaController::WebRtcMediaController(std::function<void(const wxImage&,
|
||||
|
||||
WebRtcMediaController::~WebRtcMediaController()
|
||||
{
|
||||
StopSession();
|
||||
Stop();
|
||||
}
|
||||
|
||||
void WebRtcMediaController::report(Status status)
|
||||
@@ -52,8 +52,14 @@ void WebRtcMediaController::report(Status status)
|
||||
m_on_status(status);
|
||||
}
|
||||
|
||||
void WebRtcMediaController::StartSession(std::unique_ptr<ICameraSignalingChannel> channel)
|
||||
void WebRtcMediaController::set_signalling_channel(std::unique_ptr<ICameraSignalingChannel> channel)
|
||||
{
|
||||
m_pending_signaling = std::move(channel);
|
||||
}
|
||||
|
||||
void WebRtcMediaController::Play()
|
||||
{
|
||||
std::unique_ptr<ICameraSignalingChannel> channel = std::move(m_pending_signaling);
|
||||
// Tear down any previous attempt WITHOUT notifying: the Stopped that would
|
||||
// otherwise be delivered (async, via CallAfter) races the new attempt's
|
||||
// Connecting and makes the consumer cancel a session that is mid-connect.
|
||||
@@ -101,7 +107,7 @@ void WebRtcMediaController::StartSession(std::unique_ptr<ICameraSignalingChannel
|
||||
signaling->open();
|
||||
}
|
||||
|
||||
void WebRtcMediaController::StopSession()
|
||||
void WebRtcMediaController::Stop()
|
||||
{
|
||||
teardown(true);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "IMediaController.hpp"
|
||||
#include <slic3r/Utils/IPrinterAgent.hpp>
|
||||
|
||||
#include <wx/image.h>
|
||||
|
||||
@@ -36,7 +37,7 @@ public:
|
||||
DECODE_ERROR,
|
||||
TIMEOUT,
|
||||
} code = ICE_FAILED;
|
||||
// Identifies the StartSession attempt this status belongs to, so the
|
||||
// Identifies the Play attempt this status belongs to, so the
|
||||
// consumer can drop CallAfter-queued events from a superseded attempt.
|
||||
std::uint64_t epoch = 0;
|
||||
};
|
||||
@@ -45,14 +46,13 @@ public:
|
||||
std::function<void(Status)> on_status);
|
||||
~WebRtcMediaController() override;
|
||||
|
||||
void StartSession(std::unique_ptr<ICameraSignalingChannel> channel) override;
|
||||
void StopSession() override;
|
||||
void set_signalling_channel(std::unique_ptr<ICameraSignalingChannel> channel);
|
||||
std::uint64_t epoch() const { return m_epoch.load(); }
|
||||
bool is_active() const { return m_alive.load(); }
|
||||
|
||||
void Load(wxURI) override {}
|
||||
void Play() override {}
|
||||
void Stop() override { StopSession(); }
|
||||
void Play() override;
|
||||
void Stop() override;
|
||||
wxMediaState GetState() override;
|
||||
wxSize GetVideoSize() const override;
|
||||
|
||||
@@ -75,6 +75,7 @@ private:
|
||||
// addRemoteCandidate until a remote description is set, so buffer them.
|
||||
std::vector<std::pair<std::string, std::string>> m_pending_candidates;
|
||||
bool m_remote_description_set = false;
|
||||
std::unique_ptr<ICameraSignalingChannel> m_pending_signaling;
|
||||
std::unique_ptr<ICameraSignalingChannel> m_signaling;
|
||||
std::shared_ptr<rtc::PeerConnection> m_peer_connection;
|
||||
std::shared_ptr<rtc::DataChannel> m_data_channel;
|
||||
|
||||
@@ -163,13 +163,13 @@ wxMediaState wxMediaCtrl3::GetState()
|
||||
return m_state;
|
||||
}
|
||||
|
||||
int wxMediaCtrl3::GetLastError()
|
||||
int wxMediaCtrl3::GetLastError() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
return m_error;
|
||||
}
|
||||
|
||||
wxSize wxMediaCtrl3::GetVideoSize()
|
||||
wxSize wxMediaCtrl3::GetVideoSize() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
return m_video_size;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "wx/bitmap.h"
|
||||
#include "wx/uri.h"
|
||||
#include "wx/mediactrl.h"
|
||||
#include "IMediaController.hpp"
|
||||
|
||||
wxDECLARE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
||||
|
||||
@@ -27,18 +28,18 @@ void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, in
|
||||
|
||||
class AVVideoDecoder;
|
||||
|
||||
class wxMediaCtrl3 : public wxWindow, BambuLib
|
||||
class wxMediaCtrl3 : public wxWindow, public Slic3r::GUI::IMediaController, BambuLib
|
||||
{
|
||||
public:
|
||||
wxMediaCtrl3(wxWindow *parent);
|
||||
|
||||
~wxMediaCtrl3();
|
||||
~wxMediaCtrl3() override;
|
||||
|
||||
void Load(wxURI url);
|
||||
void Load(wxURI url) override;
|
||||
|
||||
void Play();
|
||||
void Play() override;
|
||||
|
||||
void Stop();
|
||||
void Stop() override;
|
||||
|
||||
// Render frames supplied by a controller which owns its own transport.
|
||||
// The frame is copied while m_mutex is held; callers may release it after
|
||||
@@ -52,11 +53,11 @@ public:
|
||||
|
||||
void SetIdleImage(wxString const & image);
|
||||
|
||||
wxMediaState GetState();
|
||||
wxMediaState GetState() override;
|
||||
|
||||
int GetLastError();
|
||||
int GetLastError() const override;
|
||||
|
||||
wxSize GetVideoSize();
|
||||
wxSize GetVideoSize() const override;
|
||||
|
||||
protected:
|
||||
DECLARE_EVENT_TABLE()
|
||||
@@ -93,7 +94,7 @@ private:
|
||||
std::uint64_t m_last_PTS{0};
|
||||
std::chrono::system_clock::time_point m_last_PTS_expected;
|
||||
std::chrono::system_clock::time_point m_last_PTS_practical;
|
||||
std::mutex m_mutex;
|
||||
mutable std::mutex m_mutex;
|
||||
std::condition_variable m_cond;
|
||||
std::thread m_thread;
|
||||
std::atomic_bool m_refresh_pending{false};
|
||||
|
||||
@@ -148,152 +148,6 @@ void BBLPrinterAgent::set_cloud_agent(std::shared_ptr<ICloudServiceAgent> cloud)
|
||||
// Communication
|
||||
// ============================================================================
|
||||
|
||||
std::string BBLPrinterAgent::ams_refresh_rfid_gcode(const std::string& tray_id)
|
||||
{
|
||||
return (boost::format("M620 R%1% \n") % tray_id).str();
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::ams_calibrate_gcode(int ams_id)
|
||||
{
|
||||
return (boost::format("M620 C%1% \n") % ams_id).str();
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::ams_select_tray_gcode(const std::string& tray_id)
|
||||
{
|
||||
return (boost::format("M620 P%1% \n") % tray_id).str();
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
const std::string gcode = ams_refresh_rfid_gcode(tray_id);
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = gcode;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
const std::string gcode = ams_calibrate_gcode(ams_id);
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = gcode;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
const std::string gcode = ams_select_tray_gcode(tray_id);
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = gcode;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_xyz_abs(std::string dev_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = "G90 \n";
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_auto_leveling(std::string dev_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = "G29 \n";
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_go_home(std::string dev_id, bool is_printing, bool supports_mqtt_homing, int sequence_id, bool lan_mode)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
if (supports_mqtt_homing) {
|
||||
j["print"]["command"] = "back_to_center";
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = is_printing ? "G28 X\n" : "G28 \n";
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_set_bed(std::string dev_id, int temp, bool supports_mqtt_bed_ctrl, int sequence_id, bool lan_mode)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
if (supports_mqtt_bed_ctrl) {
|
||||
j["print"]["command"] = "set_bed_temp";
|
||||
j["print"]["temp"] = temp;
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = (boost::format("M140 S%1%\n") % temp).str();
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_set_nozzle(std::string dev_id, int temp, int sequence_id, bool lan_mode)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = (boost::format("M104 S%1%\n") % temp).str();
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_axis_control(std::string dev_id, std::string axis, double unit, double input_val, int speed,
|
||||
bool is_core_xy, bool supports_mqtt_axis_control, int sequence_id, bool lan_mode)
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
|
||||
if (supports_mqtt_axis_control) {
|
||||
int dir = input_val > 0 ? 1 : -1;
|
||||
// i3-arch printers move the bed for Y/Z, so the on-screen direction is
|
||||
// reversed -- same negation the g-code fallback below applies.
|
||||
if (!is_core_xy && (axis == "Y" || axis == "Z")) {
|
||||
dir = -dir;
|
||||
}
|
||||
|
||||
j["print"]["command"] = "xyz_ctrl";
|
||||
j["print"]["axis"] = axis;
|
||||
j["print"]["dir"] = dir;
|
||||
j["print"]["mode"] = (std::abs(input_val) >= 10) ? 1 : 0;
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
double value = input_val;
|
||||
if (!is_core_xy && (axis == "Y" || axis == "Z")) {
|
||||
value = -1.0 * input_val;
|
||||
}
|
||||
|
||||
std::string value_str = (boost::format("%.1f") % (value * unit)).str();
|
||||
std::string gcode;
|
||||
if (axis == "X" || axis == "Y" || axis == "Z") {
|
||||
gcode = (boost::format("M211 S \nM211 X1 Y1 Z1\nM1002 push_ref_mode\nG91 \nG1 %1%%2% F%3%\nM1002 pop_ref_mode\nM211 R\n")
|
||||
% axis % value_str % speed).str();
|
||||
} else if (axis == "E") {
|
||||
gcode = (boost::format("M83 \nG0 %1%%2% F%3%\n") % axis % value_str % speed).str();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = gcode;
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode)
|
||||
{
|
||||
const int rtn = lan_mode ? send_message_to_printer(dev_id, j.dump(), 0, 0) : send_message(dev_id, j.dump(), 0, 0);
|
||||
|
||||
@@ -29,23 +29,10 @@ public:
|
||||
|
||||
// Communication
|
||||
int send_message(std::string dev_id, std::string json_str, int qos, int flag) override;
|
||||
static std::string ams_refresh_rfid_gcode(const std::string& tray_id);
|
||||
static std::string ams_calibrate_gcode(int ams_id);
|
||||
static std::string ams_select_tray_gcode(const std::string& tray_id);
|
||||
int command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode) override;
|
||||
int command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode) override;
|
||||
int command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode) override;
|
||||
int command_xyz_abs(std::string dev_id, int sequence_id, bool lan_mode) override;
|
||||
int command_auto_leveling(std::string dev_id, int sequence_id, bool lan_mode) override;
|
||||
int command_go_home(std::string dev_id, bool is_printing, bool supports_mqtt_homing, int sequence_id, bool lan_mode) override;
|
||||
int command_set_bed(std::string dev_id, int temp, bool supports_mqtt_bed_ctrl, int sequence_id, bool lan_mode) override;
|
||||
int command_set_nozzle(std::string dev_id, int temp, int sequence_id, bool lan_mode) override;
|
||||
int command_axis_control(std::string dev_id, std::string axis, double unit, double input_val, int speed,
|
||||
bool is_core_xy, bool supports_mqtt_axis_control, int sequence_id, bool lan_mode) override;
|
||||
std::string default_lan_username() const override { return "bblp"; }
|
||||
int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) override;
|
||||
int disconnect_printer() override;
|
||||
int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) override;
|
||||
std::string default_lan_username() const override { return "bblp"; }
|
||||
|
||||
// Certificates
|
||||
int check_cert() override;
|
||||
|
||||
@@ -14,8 +14,19 @@
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#ifdef OPENSSL_CERT_OVERRIDE
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509err.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include <wincrypt.h>
|
||||
// wincrypt.h uses this token for a certificate-name property identifier.
|
||||
# undef X509_NAME
|
||||
#endif
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
@@ -939,6 +950,45 @@ std::string Http::tls_system_cert_store()
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Http::add_platform_root_certificates(SSL_CTX* ssl_context)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
X509_STORE* openssl_store = SSL_CTX_get_cert_store(ssl_context);
|
||||
if (!openssl_store)
|
||||
throw std::runtime_error("unable to get OpenSSL certificate store");
|
||||
|
||||
const auto load_store = [&](DWORD location) {
|
||||
HCERTSTORE windows_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
|
||||
location | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
|
||||
L"ROOT");
|
||||
if (!windows_store)
|
||||
return;
|
||||
|
||||
PCCERT_CONTEXT windows_certificate = nullptr;
|
||||
while ((windows_certificate = CertEnumCertificatesInStore(windows_store, windows_certificate)) != nullptr) {
|
||||
const unsigned char* encoded = windows_certificate->pbCertEncoded;
|
||||
X509* certificate = d2i_X509(nullptr, &encoded, static_cast<long>(windows_certificate->cbCertEncoded));
|
||||
if (!certificate) {
|
||||
ERR_clear_error();
|
||||
continue;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
if (X509_STORE_add_cert(openssl_store, certificate) != 1)
|
||||
ERR_clear_error();
|
||||
X509_free(certificate);
|
||||
}
|
||||
|
||||
CertCloseStore(windows_store, 0);
|
||||
};
|
||||
|
||||
load_store(CERT_SYSTEM_STORE_CURRENT_USER);
|
||||
load_store(CERT_SYSTEM_STORE_LOCAL_MACHINE);
|
||||
#else
|
||||
(void)ssl_context;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string Http::url_encode(const std::string &str)
|
||||
{
|
||||
::CURL *curl = ::curl_easy_init();
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "libslic3r/Exception.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
|
||||
typedef struct ssl_ctx_st SSL_CTX;
|
||||
|
||||
#define MAX_SIZE_TO_FILE 3*1024
|
||||
|
||||
namespace Slic3r {
|
||||
@@ -198,6 +200,10 @@ public:
|
||||
// Return empty string on success or error message on fail.
|
||||
static std::string tls_global_init();
|
||||
static std::string tls_system_cert_store();
|
||||
// Add platform root certificates to a standalone OpenSSL context. This
|
||||
// supplements set_default_verify_paths() on platforms where OpenSSL does
|
||||
// not use the native certificate store.
|
||||
static void add_platform_root_certificates(SSL_CTX* ssl_context);
|
||||
|
||||
// converts the given string to an url_encoded_string
|
||||
static std::string url_encode(const std::string &str);
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include "ICameraSignalingChannel.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
@@ -109,16 +112,64 @@ public:
|
||||
virtual int command_start_camera(std::string)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
|
||||
private:
|
||||
int publish_command_json(std::string dev_id, const nlohmann::json& j, bool lan_mode)
|
||||
{
|
||||
return lan_mode ? send_message_to_printer(dev_id, j.dump(), 0, 0)
|
||||
: send_message(dev_id, j.dump(), 0, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int command_xyz_abs(std::string dev_id, int sequence_id, bool lan_mode)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = "G90 \n";
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish_command_json(dev_id, j, lan_mode);
|
||||
}
|
||||
virtual int command_auto_leveling(std::string dev_id, int sequence_id, bool lan_mode)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = "G29 \n";
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish_command_json(dev_id, j, lan_mode);
|
||||
}
|
||||
virtual int command_go_home(std::string dev_id, bool is_printing, bool supports_mqtt_homing, int sequence_id, bool lan_mode)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
if (supports_mqtt_homing) {
|
||||
j["print"]["command"] = "back_to_center";
|
||||
} else {
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = is_printing ? "G28 X\n" : "G28 \n";
|
||||
}
|
||||
return publish_command_json(dev_id, j, lan_mode);
|
||||
}
|
||||
virtual int command_set_bed(std::string dev_id, int temp, bool supports_mqtt_bed_ctrl, int sequence_id, bool lan_mode)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
if (supports_mqtt_bed_ctrl) {
|
||||
j["print"]["command"] = "set_bed_temp";
|
||||
j["print"]["temp"] = temp;
|
||||
} else {
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = (boost::format("M140 S%1%\n") % temp).str();
|
||||
}
|
||||
return publish_command_json(dev_id, j, lan_mode);
|
||||
}
|
||||
virtual int command_set_nozzle(std::string dev_id, int temp, int sequence_id, bool lan_mode)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = (boost::format("M104 S%1%\n") % temp).str();
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish_command_json(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
virtual int command_axis_control(std::string dev_id, std::string axis, double unit, double input_val, int speed,
|
||||
bool is_core_xy, bool supports_mqtt_axis_control, int sequence_id, bool lan_mode)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
|
||||
@@ -130,7 +130,6 @@ void OrcaCloudSignalingChannel::run()
|
||||
|
||||
nlohmann::json token_response;
|
||||
std::string token_body;
|
||||
std::string token_error;
|
||||
unsigned int http_code = 0;
|
||||
auto request = Http::post(live_token_url);
|
||||
request.set_post_body(std::string("{}"))
|
||||
@@ -142,19 +141,13 @@ void OrcaCloudSignalingChannel::run()
|
||||
http_code = status;
|
||||
token_body = std::move(body);
|
||||
})
|
||||
.on_error([&token_body, &token_error, &http_code](std::string body, std::string error, unsigned status) {
|
||||
.on_error([&http_code](std::string, std::string, unsigned status) {
|
||||
http_code = status;
|
||||
token_body = std::move(body);
|
||||
token_error = std::move(error);
|
||||
})
|
||||
.perform_sync();
|
||||
BOOST_LOG_TRIVIAL(info) << "signaling: live-token HTTP " << http_code
|
||||
<< (token_error.empty() ? "" : " error=" + token_error)
|
||||
<< " body=" << token_body.substr(0, 512);
|
||||
try {
|
||||
token_response = nlohmann::json::parse(token_body);
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "signaling: live-token body is not JSON: " << e.what();
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
if (http_code < 200 || http_code >= 300 || !token_response.contains("token")) {
|
||||
unavailable(CameraUnavailableReason::Error, "Unable to mint camera live token");
|
||||
@@ -189,9 +182,9 @@ void OrcaCloudSignalingChannel::run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto conn = std::make_shared<Connection>();
|
||||
conn->ssl_context.set_default_verify_paths();
|
||||
Http::add_platform_root_certificates(conn->ssl_context.native_handle());
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_conn = conn;
|
||||
@@ -203,6 +196,7 @@ void OrcaCloudSignalingChannel::run()
|
||||
if (!SSL_set_tlsext_host_name(websocket.next_layer().native_handle(), host.c_str()))
|
||||
throw std::runtime_error("Unable to configure TLS server name");
|
||||
websocket.next_layer().set_verify_mode(boost::asio::ssl::verify_peer);
|
||||
websocket.next_layer().set_verify_callback(boost::asio::ssl::host_name_verification(host));
|
||||
websocket.next_layer().handshake(boost::asio::ssl::stream_base::client);
|
||||
const std::string ws_target = "/api/v1/printers/" + encode_path_component(m_dev_id) +
|
||||
"/camera/live?token=" +
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "OrcaMqttConnection.hpp"
|
||||
#include "Http.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/ssl.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
@@ -52,15 +52,6 @@ OrcaMqttConnection::~OrcaMqttConnection() { stop(); }
|
||||
|
||||
bool OrcaMqttConnection::start(const Config& config, MessageHandler on_message, StateHandler on_state) {
|
||||
std::lock_guard<std::recursive_mutex> lifecycle_lock(lifecycle_mutex);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT start url=" << config.url
|
||||
<< " use_tls=" << config.use_tls
|
||||
<< " bearer_provider=" << (config.bearer_provider ? "set" : "null")
|
||||
<< " username_present=" << (!config.username.empty())
|
||||
<< " password_present=" << (!config.password.empty())
|
||||
<< " client_id=" << config.client_id
|
||||
<< " keepalive_seconds=" << config.keepalive_seconds
|
||||
<< " message_callback=" << (on_message ? "set" : "null")
|
||||
<< " state_callback=" << (on_state ? "set" : "null");
|
||||
stop();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
@@ -79,26 +70,12 @@ bool OrcaMqttConnection::start(const Config& config, MessageHandler on_message,
|
||||
if (!initial_cv.wait_for(lock, std::chrono::seconds(10), [this] { return initial_completed; })) {
|
||||
initial_completed = true;
|
||||
initial_result = false;
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: MQTT initial connection timed out after 10 seconds"
|
||||
<< " url=" << current_config.url
|
||||
<< " last_connack_rc=" << m_last_connack_rc.load()
|
||||
<< " connected=" << connected.load()
|
||||
<< "; worker will retry";
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT start initial_result=" << initial_result
|
||||
<< " initial_completed=" << initial_completed
|
||||
<< " last_connack_rc=" << m_last_connack_rc.load()
|
||||
<< " worker_running=" << (worker.joinable() && !stopping.load());
|
||||
return initial_result;
|
||||
}
|
||||
|
||||
void OrcaMqttConnection::stop() {
|
||||
std::lock_guard<std::recursive_mutex> lifecycle_lock(lifecycle_mutex);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT stop requested"
|
||||
<< " url=" << current_config.url
|
||||
<< " connected=" << connected.load()
|
||||
<< " worker_joinable=" << worker.joinable()
|
||||
<< " last_connack_rc=" << m_last_connack_rc.load();
|
||||
stopping.store(true);
|
||||
state_cv.notify_all();
|
||||
{
|
||||
@@ -158,35 +135,26 @@ void OrcaMqttConnection::flush_subscription_change() {
|
||||
// websocket.read(); every write is serialised by write_mutex inside ws_write().
|
||||
try {
|
||||
send_pending_subscriptions(*conn);
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: direct subscription write failed (" << e.what()
|
||||
<< "); worker will resend the full set on reconnect";
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
}
|
||||
|
||||
bool OrcaMqttConnection::subscribe(const std::string& dev_id) {
|
||||
if (dev_id.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: MQTT subscribe rejected empty dev_id";
|
||||
return false;
|
||||
}
|
||||
const std::string topic = report_topic(dev_id);
|
||||
if (topic.size() > 96) { // MQTT topic filter cap enforced by the service
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: MQTT subscribe rejected oversized topic=" << topic;
|
||||
return false;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (subscriptions.count(topic) != 0 && pending_unsubscriptions.count(topic) == 0) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT subscribe already queued or active topic=" << topic
|
||||
<< " acknowledged=" << (acknowledged_subscriptions.count(topic) != 0);
|
||||
return true;
|
||||
}
|
||||
subscriptions.insert(topic);
|
||||
pending_unsubscriptions.erase(topic);
|
||||
pending_subscriptions.insert(topic);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT subscribe queued topic=" << topic
|
||||
<< " total_subscriptions=" << subscriptions.size()
|
||||
<< " connected=" << connected.load();
|
||||
}
|
||||
state_cv.notify_all();
|
||||
flush_subscription_change(); // emit SUBSCRIBE now on the live socket (no reconnect)
|
||||
@@ -213,9 +181,6 @@ bool OrcaMqttConnection::unsubscribe(const std::string& dev_id) {
|
||||
else
|
||||
++it;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT unsubscribe queued topic=" << topic
|
||||
<< " total_subscriptions=" << subscriptions.size()
|
||||
<< " connected=" << connected.load();
|
||||
}
|
||||
state_cv.notify_all();
|
||||
flush_subscription_change(); // emit UNSUBSCRIBE now on the live socket (no reconnect)
|
||||
@@ -224,7 +189,6 @@ bool OrcaMqttConnection::unsubscribe(const std::string& dev_id) {
|
||||
|
||||
void OrcaMqttConnection::clear_subscriptions() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT clear subscriptions count=" << subscriptions.size();
|
||||
subscriptions.clear();
|
||||
pending_subscriptions.clear();
|
||||
pending_unsubscriptions.clear();
|
||||
@@ -332,16 +296,12 @@ std::vector<uint8_t> OrcaMqttConnection::make_ping_packet() { return {0xc0, 0};
|
||||
|
||||
void OrcaMqttConnection::ws_write(Connection& conn, const std::vector<uint8_t>& packet) {
|
||||
if (packet.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: attempted to send empty MQTT packet";
|
||||
return;
|
||||
}
|
||||
// Writes come from the worker thread AND, for dynamic (un)subscribes, the
|
||||
// caller thread. Serialise them; the worker's concurrent read is fine (beast
|
||||
// allows one reader + one writer).
|
||||
std::lock_guard<std::mutex> lock(write_mutex);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: sending MQTT packet type=0x" << std::hex
|
||||
<< static_cast<unsigned int>(packet[0] >> 4) << std::dec
|
||||
<< " bytes=" << packet.size();
|
||||
if (conn.wss) {
|
||||
conn.wss->binary(true);
|
||||
conn.wss->write(boost::asio::buffer(packet));
|
||||
@@ -367,22 +327,14 @@ void OrcaMqttConnection::ws_close(Connection& conn) {
|
||||
conn.wss->close(boost::beast::websocket::close_code::normal, close_error);
|
||||
else if (conn.ws)
|
||||
conn.ws->close(boost::beast::websocket::close_code::normal, close_error);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT connection closed code=" << close_error.value()
|
||||
<< " message=" << close_error.message();
|
||||
}
|
||||
|
||||
void OrcaMqttConnection::ws_handshake(Connection& conn, const Config& config, const Endpoint& endpoint) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: WebSocket resolve starting host=" << endpoint.host
|
||||
<< " port=" << endpoint.port << " target=" << endpoint.target
|
||||
<< " tls=" << config.use_tls;
|
||||
const auto results = conn.resolver.resolve(endpoint.host, endpoint.port);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT DNS resolution succeeded host=" << endpoint.host;
|
||||
|
||||
std::string token;
|
||||
if (config.bearer_provider) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: requesting bearer token for WebSocket upgrade";
|
||||
token = config.bearer_provider();
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: bearer token callback completed token_present=" << !token.empty();
|
||||
}
|
||||
auto decorator = [token](boost::beast::websocket::request_type& request) {
|
||||
request.set(boost::beast::http::field::user_agent, "OrcaSlicer");
|
||||
@@ -404,21 +356,17 @@ void OrcaMqttConnection::ws_handshake(Connection& conn, const Config& config, co
|
||||
auto& stream = boost::beast::get_lowest_layer(websocket);
|
||||
stream.expires_after(std::chrono::seconds(10));
|
||||
stream.connect(results);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT TCP connection established host=" << endpoint.host
|
||||
<< " port=" << endpoint.port;
|
||||
// Set SNI before the TLS handshake so the cloud edge selects the correct
|
||||
// certificate.
|
||||
auto& tls_stream = websocket.next_layer();
|
||||
if (!SSL_set_tlsext_host_name(tls_stream.native_handle(), endpoint.host.c_str()))
|
||||
throw std::runtime_error("failed to set Orca Cloud TLS server name");
|
||||
conn.ssl_context.set_default_verify_paths();
|
||||
Http::add_platform_root_certificates(conn.ssl_context.native_handle());
|
||||
tls_stream.set_verify_mode(boost::asio::ssl::verify_peer);
|
||||
tls_stream.set_verify_callback(boost::asio::ssl::host_name_verification(endpoint.host));
|
||||
tls_stream.handshake(boost::asio::ssl::stream_base::client);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT TLS handshake completed host=" << endpoint.host;
|
||||
websocket.set_option(boost::beast::websocket::stream_base::decorator(decorator));
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: sending TLS WebSocket upgrade target=" << endpoint.target
|
||||
<< " bearer_header=" << (!token.empty());
|
||||
websocket.handshake(response, endpoint.host, endpoint.target, handshake_error);
|
||||
} else {
|
||||
{
|
||||
@@ -429,39 +377,23 @@ void OrcaMqttConnection::ws_handshake(Connection& conn, const Config& config, co
|
||||
auto& stream = boost::beast::get_lowest_layer(websocket);
|
||||
stream.expires_after(std::chrono::seconds(10));
|
||||
stream.connect(results);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT TCP connection established host=" << endpoint.host
|
||||
<< " port=" << endpoint.port << " (plaintext)";
|
||||
websocket.set_option(boost::beast::websocket::stream_base::decorator(decorator));
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: sending plaintext WebSocket upgrade target=" << endpoint.target
|
||||
<< " bearer_header=" << (!token.empty());
|
||||
websocket.handshake(response, endpoint.host, endpoint.target, handshake_error);
|
||||
}
|
||||
|
||||
if (handshake_error) {
|
||||
// Surface the server's HTTP status so a persistent rejection (stale token,
|
||||
// missing api key, wrong route) is diagnosable from the log rather than an
|
||||
// opaque "handshake declined".
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: WS handshake rejected http="
|
||||
<< response.result_int() << " (" << response.reason() << "), "
|
||||
<< handshake_error.message();
|
||||
throw boost::system::system_error(handshake_error, "Orca WebSocket handshake");
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: WebSocket handshake completed http=" << response.result_int()
|
||||
<< " negotiated_protocol=" << response["Sec-WebSocket-Protocol"];
|
||||
if (response["Sec-WebSocket-Protocol"] != "mqtt") {
|
||||
BOOST_LOG_TRIVIAL(error) << "Orca diagnostic: WebSocket handshake did not negotiate MQTT";
|
||||
throw std::runtime_error("Orca WebSocket did not negotiate MQTT");
|
||||
}
|
||||
}
|
||||
|
||||
bool OrcaMqttConnection::send_request(const std::string& dev_id, const std::string& payload) {
|
||||
if (dev_id.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: MQTT send_request rejected empty dev_id";
|
||||
return false;
|
||||
}
|
||||
if (!connected.load()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: MQTT send_request rejected because connection is not ready"
|
||||
<< " dev_id=" << dev_id << " last_connack_rc=" << m_last_connack_rc.load();
|
||||
return false;
|
||||
}
|
||||
std::shared_ptr<Connection> conn;
|
||||
@@ -470,8 +402,6 @@ bool OrcaMqttConnection::send_request(const std::string& dev_id, const std::stri
|
||||
conn = active_connection;
|
||||
}
|
||||
if (!conn) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: MQTT send_request rejected because active connection is null"
|
||||
<< " dev_id=" << dev_id;
|
||||
return false;
|
||||
}
|
||||
const std::string report = report_topic(dev_id);
|
||||
@@ -479,28 +409,19 @@ bool OrcaMqttConnection::send_request(const std::string& dev_id, const std::stri
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (subscriptions.count(report) != 0 && acknowledged_subscriptions.count(report) == 0) {
|
||||
pending_requests.emplace_back(dev_id, payload);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT request queued until SUBACK"
|
||||
<< " dev_id=" << dev_id << " payload_bytes=" << payload.size()
|
||||
<< " pending_requests=" << pending_requests.size();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
try {
|
||||
// ws_write() serialises the write via write_mutex; do not lock it here.
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT PUBLISH request dev_id=" << dev_id
|
||||
<< " topic=" << request_topic(dev_id)
|
||||
<< " payload_bytes=" << payload.size();
|
||||
ws_write(*conn, make_publish_packet(request_topic(dev_id), payload));
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: send_request failed dev_id=" << dev_id
|
||||
<< " (" << e.what() << ")";
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OrcaMqttConnection::connect_and_read() {
|
||||
m_connection_stage = "creating connection";
|
||||
auto connection = std::make_shared<Connection>();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(connection_mutex);
|
||||
@@ -509,20 +430,14 @@ void OrcaMqttConnection::connect_and_read() {
|
||||
return;
|
||||
}
|
||||
|
||||
m_connection_stage = "parsing endpoint";
|
||||
Endpoint endpoint;
|
||||
if (!parse_endpoint(current_config.url, endpoint)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Orca diagnostic: invalid MQTT endpoint=" << current_config.url;
|
||||
throw std::runtime_error("invalid Orca Cloud WebSocket endpoint");
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT connecting host=" << endpoint.host
|
||||
<< " port=" << endpoint.port << " target=" << endpoint.target;
|
||||
|
||||
m_connection_stage = "WebSocket handshake";
|
||||
ws_handshake(*connection, current_config, endpoint);
|
||||
|
||||
m_connection_stage = "sending MQTT CONNECT";
|
||||
expires_never(*connection);
|
||||
// Auth precedence: a bearer_provider authenticates the WebSocket upgrade, so the
|
||||
// CONNECT username/password fields are omitted entirely (the cloud form).
|
||||
@@ -531,9 +446,7 @@ void OrcaMqttConnection::connect_and_read() {
|
||||
use_bearer ? std::string() : current_config.username,
|
||||
use_bearer ? std::string() : current_config.password,
|
||||
current_config.keepalive_seconds));
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT CONNECT packet sent";
|
||||
|
||||
m_connection_stage = "waiting for MQTT CONNACK";
|
||||
boost::beast::flat_buffer buffer;
|
||||
expires_after(*connection, std::chrono::seconds(10));
|
||||
boost::system::error_code connack_error;
|
||||
@@ -541,16 +454,12 @@ void OrcaMqttConnection::connect_and_read() {
|
||||
if (connack_error)
|
||||
throw boost::system::system_error(connack_error, "read Orca MQTT CONNACK");
|
||||
const std::string connack = boost::beast::buffers_to_string(buffer.data());
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT CONNACK received bytes=" << connack.size()
|
||||
<< " header=" << (connack.empty() ? -1 : static_cast<int>(static_cast<uint8_t>(connack[0])))
|
||||
<< " return_code=" << (connack.size() > 3 ? static_cast<int>(static_cast<uint8_t>(connack[3])) : -1);
|
||||
// rc: 0 accepted, 1..5 refusal, -1 malformed/not a CONNACK.
|
||||
const int rc = (connack.size() == 4 && static_cast<uint8_t>(connack[0]) == 0x20)
|
||||
? static_cast<int>(static_cast<uint8_t>(connack[3]))
|
||||
: -1;
|
||||
m_last_connack_rc.store(rc);
|
||||
if (rc != 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Orca diagnostic: MQTT CONNECT refused rc=" << rc;
|
||||
if (rc == 4 || rc == 5) {
|
||||
// Bad credentials / not authorized — retrying cannot help. Make run()'s
|
||||
// loop exit and unblock any waiting start().
|
||||
@@ -565,7 +474,6 @@ void OrcaMqttConnection::connect_and_read() {
|
||||
throw std::runtime_error("Orca MQTT CONNECT refused rc=" + std::to_string(rc));
|
||||
}
|
||||
|
||||
m_connection_stage = "reading MQTT messages";
|
||||
// The subscription acknowledgement belongs to this MQTT session. Clear
|
||||
// the previous session's state before notifying the owner, because the
|
||||
// reconnect callback immediately queues the printer's initial requests.
|
||||
@@ -576,7 +484,6 @@ void OrcaMqttConnection::connect_and_read() {
|
||||
}
|
||||
notify_state(true);
|
||||
reconnect_delay_seconds.store(1); // a fresh CONNACK resets the backoff
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT connection is ready; sending current subscriptions";
|
||||
send_current_subscriptions(*connection);
|
||||
std::chrono::steady_clock::time_point next_ping = std::chrono::steady_clock::now() + std::chrono::seconds(30);
|
||||
|
||||
@@ -587,19 +494,15 @@ void OrcaMqttConnection::connect_and_read() {
|
||||
// read hot and the broker would drop us at 1.5 x keepalive.
|
||||
if (std::chrono::steady_clock::now() >= next_ping) {
|
||||
ws_write(*connection, make_ping_packet());
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT PINGREQ sent";
|
||||
next_ping = std::chrono::steady_clock::now() + std::chrono::seconds(30);
|
||||
}
|
||||
buffer.consume(buffer.size());
|
||||
m_connection_stage = "reading MQTT frame";
|
||||
expires_after(*connection, std::chrono::seconds(1));
|
||||
boost::system::error_code error;
|
||||
ws_read(*connection, buffer, error);
|
||||
if (error == boost::beast::error::timeout)
|
||||
continue;
|
||||
if (error) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: MQTT WebSocket read failed code=" << error.value()
|
||||
<< " message=" << error.message();
|
||||
throw boost::system::system_error(error, "read Orca MQTT message");
|
||||
}
|
||||
handle_packet(boost::beast::buffers_to_string(buffer.data()));
|
||||
@@ -620,14 +523,12 @@ void OrcaMqttConnection::send_current_subscriptions(Connection& conn) {
|
||||
for (const std::string& topic : topics)
|
||||
pending_subscriptions.erase(topic);
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: sending current MQTT subscriptions count=" << topics.size();
|
||||
for (const std::string& topic : topics) {
|
||||
const uint16_t packet_id = next_packet_id++;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
pending_subscribe_packets[packet_id] = topic;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: sending SUBSCRIBE topic=" << topic << " packet_id=" << packet_id;
|
||||
ws_write(conn, make_subscribe_packet(packet_id, topic, 1));
|
||||
}
|
||||
}
|
||||
@@ -648,28 +549,20 @@ void OrcaMqttConnection::send_pending_subscriptions(Connection& conn) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
pending_subscribe_packets[packet_id] = topic;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: sending pending SUBSCRIBE topic=" << topic
|
||||
<< " packet_id=" << packet_id;
|
||||
ws_write(conn, make_subscribe_packet(packet_id, topic, 1));
|
||||
}
|
||||
for (const std::string& topic : unsubscribe_topics) {
|
||||
const uint16_t packet_id = next_packet_id++;
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: sending pending UNSUBSCRIBE topic=" << topic
|
||||
<< " packet_id=" << packet_id;
|
||||
ws_write(conn, make_unsubscribe_packet(packet_id, topic));
|
||||
}
|
||||
}
|
||||
|
||||
void OrcaMqttConnection::handle_packet(const std::string& packet) {
|
||||
if (packet.size() < 2) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: received undersized MQTT packet bytes=" << packet.size();
|
||||
return;
|
||||
}
|
||||
const uint8_t header = static_cast<uint8_t>(packet[0]);
|
||||
const uint8_t packet_type = header >> 4;
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: received MQTT packet type=" << static_cast<unsigned int>(packet_type)
|
||||
<< " header=0x" << std::hex << static_cast<unsigned int>(header) << std::dec
|
||||
<< " bytes=" << packet.size();
|
||||
if (packet_type != 3) { // Only QoS 0 PUBLISH carries printer status.
|
||||
if (packet_type == 9 && packet.size() >= 5) {
|
||||
const uint16_t packet_id = (static_cast<unsigned int>(static_cast<uint8_t>(packet[2])) << 8) |
|
||||
@@ -680,9 +573,6 @@ void OrcaMqttConnection::handle_packet(const std::string& packet) {
|
||||
result_codes << ',';
|
||||
result_codes << "0x" << std::hex << static_cast<unsigned int>(static_cast<uint8_t>(packet[index]));
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: received SUBACK packet_id="
|
||||
<< packet_id
|
||||
<< " result_codes=" << result_codes.str();
|
||||
|
||||
// Each production SUBSCRIBE packet currently contains one topic.
|
||||
// MQTT grants QoS 0 or 1 for a requested QoS 1 subscription; 0x80
|
||||
@@ -710,21 +600,12 @@ void OrcaMqttConnection::handle_packet(const std::string& packet) {
|
||||
}
|
||||
}
|
||||
if (topic.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: SUBACK has no pending topic packet_id=" << packet_id;
|
||||
} else if (result == 0 || result == 1) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: report subscription active topic=" << topic
|
||||
<< " granted_qos=" << static_cast<unsigned int>(result)
|
||||
<< " releasing_requests=" << requests.size();
|
||||
for (const auto& request : requests) {
|
||||
if (!send_request(request.first, request.second)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: queued MQTT request could not be sent"
|
||||
<< " after SUBACK dev_id=" << request.first;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: report subscription rejected topic=" << topic
|
||||
<< " result_code=0x" << std::hex << static_cast<unsigned int>(result) << std::dec
|
||||
<< " dropped_requests=" << requests.size();
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -735,7 +616,6 @@ void OrcaMqttConnection::handle_packet(const std::string& packet) {
|
||||
uint8_t encoded = 0;
|
||||
do {
|
||||
if (index >= packet.size() || multiplier > 128 * 128 * 128) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: malformed MQTT PUBLISH remaining length";
|
||||
return;
|
||||
}
|
||||
encoded = static_cast<uint8_t>(packet[index++]);
|
||||
@@ -744,30 +624,23 @@ void OrcaMqttConnection::handle_packet(const std::string& packet) {
|
||||
} while ((encoded & 0x80) != 0);
|
||||
const size_t remaining_end = index + remaining;
|
||||
if (remaining_end > packet.size() || remaining < 2 || index + 2 > remaining_end) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: malformed MQTT PUBLISH body remaining=" << remaining
|
||||
<< " packet_bytes=" << packet.size();
|
||||
return;
|
||||
}
|
||||
const uint16_t topic_length = (static_cast<uint8_t>(packet[index]) << 8) |
|
||||
static_cast<uint8_t>(packet[index + 1]);
|
||||
index += 2;
|
||||
if (topic_length > packet.size() - index) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: malformed MQTT PUBLISH topic length=" << topic_length;
|
||||
return;
|
||||
}
|
||||
const std::string topic(packet.data() + index, topic_length);
|
||||
index += topic_length;
|
||||
if (((header >> 1) & 0x03) != 0) {
|
||||
if (index + 2 > remaining_end) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: malformed MQTT PUBLISH packet identifier";
|
||||
return;
|
||||
}
|
||||
index += 2; // QoS 1/2 packet identifier; the service currently sends QoS 0.
|
||||
}
|
||||
const size_t payload_size = remaining_end - index;
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: received PUBLISH topic=" << topic
|
||||
<< " payload_bytes=" << payload_size
|
||||
<< " message_callback=" << (on_message ? "set" : "null");
|
||||
// topic is "device/<id>/report" (or "/request"); hand the id up, drop anything else.
|
||||
std::string dev_id;
|
||||
if (topic.rfind("device/", 0) == 0) {
|
||||
@@ -777,11 +650,9 @@ void OrcaMqttConnection::handle_packet(const std::string& packet) {
|
||||
dev_id = topic.substr(id_start, id_end - id_start);
|
||||
}
|
||||
if (dev_id.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: dropping PUBLISH on unrecognized topic=" << topic;
|
||||
} else if (on_message) {
|
||||
on_message(dev_id, packet.substr(index, remaining_end - index));
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: dropping PUBLISH because message callback is not set";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,8 +669,6 @@ void OrcaMqttConnection::notify_state(bool is_now_connected) {
|
||||
}
|
||||
callback = on_state;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT state changed connected=" << is_now_connected
|
||||
<< " initial=" << initial << " state_callback=" << (callback ? "set" : "null");
|
||||
if (initial)
|
||||
initial_cv.notify_all();
|
||||
else if (callback)
|
||||
@@ -810,18 +679,9 @@ void OrcaMqttConnection::run() {
|
||||
while (!stopping.load()) {
|
||||
const int retry_seconds = reconnect_delay_seconds.load();
|
||||
const uint64_t attempt = ++m_attempt_number;
|
||||
m_connection_stage = "starting attempt";
|
||||
try {
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT connection attempt=" << attempt
|
||||
<< " retry_delay=" << retry_seconds
|
||||
<< " url=" << current_config.url;
|
||||
connect_and_read();
|
||||
} catch (const std::exception& error) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: MQTT connection attempt=" << attempt
|
||||
<< " failed stage=" << m_connection_stage
|
||||
<< " error=" << error.what()
|
||||
<< " last_connack_rc=" << m_last_connack_rc.load()
|
||||
<< " stopping=" << stopping.load();
|
||||
if (!stopping.load())
|
||||
notify_state(false);
|
||||
}
|
||||
@@ -831,7 +691,6 @@ void OrcaMqttConnection::run() {
|
||||
// successful connection resets reconnect_delay_seconds to 1 (connect_and_read).
|
||||
reconnect_delay_seconds.store(std::min(retry_seconds * 2, 30));
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
BOOST_LOG_TRIVIAL(info) << "Orca diagnostic: MQTT waiting before reconnect seconds=" << retry_seconds;
|
||||
state_cv.wait_for(lock, std::chrono::seconds(retry_seconds), [this] { return stopping.load(); });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,6 @@ private:
|
||||
std::atomic<uint16_t> next_packet_id{1};
|
||||
std::atomic<int> m_last_connack_rc{-1};
|
||||
uint64_t m_attempt_number{0}; // worker-thread diagnostic sequence
|
||||
std::string m_connection_stage; // worker-thread diagnostic stage
|
||||
bool initial_result{false};
|
||||
bool initial_completed{false};
|
||||
std::atomic_bool connected{false};
|
||||
|
||||
@@ -1409,9 +1409,10 @@ int OrcaPrinterAgent::start_print(PrintParams params, OnUpdateStatusFn update_fn
|
||||
if (update_fn)
|
||||
update_fn(PrintingStageSending, 0, "Starting print...");
|
||||
|
||||
const int start_rc = cloud->start_cloud_print_job(params.dev_id, job_id, remote_gcode_name(params), /*start=*/true);
|
||||
if (start_rc != BAMBU_NETWORK_SUCCESS)
|
||||
return start_rc;
|
||||
result = start_sdcard_print(params, update_fn, cancel_fn);
|
||||
|
||||
if (result != BAMBU_NETWORK_SUCCESS)
|
||||
return result;
|
||||
|
||||
if (update_fn)
|
||||
update_fn(PrintingStageFinished, 100, "Print started");
|
||||
|
||||
Reference in New Issue
Block a user