diff --git a/src/guppyscreen.cpp b/src/guppyscreen.cpp index 39c6d69..de312c1 100644 --- a/src/guppyscreen.cpp +++ b/src/guppyscreen.cpp @@ -26,15 +26,15 @@ lv_theme_t GuppyScreen::th_new; lv_obj_t *GuppyScreen::screen_saver = NULL; #endif +KWebSocketClient GuppyScreen::ws(NULL); + std::mutex GuppyScreen::lv_lock; GuppyScreen::GuppyScreen() - : ws(NULL) - , spoolman_panel(ws, lv_lock) + : spoolman_panel(ws, lv_lock) , main_panel(ws, lv_lock, spoolman_panel) , init_panel(main_panel, main_panel.get_tune_panel().get_bedmesh_panel(), lv_lock) { - ws.register_notify_update(State::get_instance()); main_panel.create_panel(); } @@ -149,6 +149,8 @@ GuppyScreen *GuppyScreen::init(std::function hal_init) { } #endif // OS_ANDROID + ws.register_notify_update(State::get_instance()); + GuppyScreen *gs = GuppyScreen::get(); auto printers = conf->get_json("/printers"); if (!printers.empty()) { @@ -207,6 +209,7 @@ std::mutex &GuppyScreen::get_lock() { } void GuppyScreen::connect_ws(const std::string &url) { + init_panel.set_message(LV_SYMBOL_WARNING " Waiting for printer to initialize..."); ws.connect(url.c_str(), [this]() { init_panel.connected(ws); }, [this]() { init_panel.disconnected(ws); }); diff --git a/src/guppyscreen.h b/src/guppyscreen.h index d8f2034..3a1bfbd 100644 --- a/src/guppyscreen.h +++ b/src/guppyscreen.h @@ -25,8 +25,8 @@ class GuppyScreen { static lv_obj_t *screen_saver; #endif static std::mutex lv_lock; + static KWebSocketClient ws; - KWebSocketClient ws; SpoolmanPanel spoolman_panel; MainPanel main_panel; InitPanel init_panel; diff --git a/src/init_panel.cpp b/src/init_panel.cpp index 3db184a..7fff4e1 100644 --- a/src/init_panel.cpp +++ b/src/init_panel.cpp @@ -41,10 +41,11 @@ InitPanel::~InitPanel() { void InitPanel::connected(KWebSocketClient &ws) { spdlog::debug("init panel connected"); - ws.send_jsonrpc("printer.objects.list", - [this, &ws](json& d) { - State *state = State::get_instance(); - state->reset(); + State *state = State::get_instance(); + state->reset(); + + ws.send_jsonrpc("printer.objects.list", [this, &ws](json& d) { + State *state = State::get_instance(); state->set_data("printer_objs", d, "/result"); ws.send_jsonrpc("server.files.roots", @@ -130,3 +131,7 @@ void InitPanel::disconnected(KWebSocketClient &ws) { lv_obj_clear_flag(cont, LV_OBJ_FLAG_HIDDEN); lv_obj_move_foreground(cont); } + +void InitPanel::set_message(const char *message) { + lv_label_set_text(label, message); +} diff --git a/src/init_panel.h b/src/init_panel.h index 190b469..27e7121 100644 --- a/src/init_panel.h +++ b/src/init_panel.h @@ -16,6 +16,7 @@ class InitPanel { void connected(KWebSocketClient &ws); void disconnected(KWebSocketClient &ws); + void set_message(const char *message); private: lv_obj_t *cont; diff --git a/src/print_panel.cpp b/src/print_panel.cpp index 08d81bb..7a840ef 100644 --- a/src/print_panel.cpp +++ b/src/print_panel.cpp @@ -184,7 +184,7 @@ void PrintPanel::subscribe() { if (d.contains("result")) { for (auto f : d["result"]) { - root.add_path(KUtils::split(f["path"], '/'), f["path"], f["modified"].template get()); + root.add_path(KUtils::split(f["path"], '/'), f["path"], f["modified"].template get()); } } Tree *dir = root.find_path(KUtils::split(cur_path, '/')); diff --git a/src/print_status_panel.cpp b/src/print_status_panel.cpp index fe8c508..29555c4 100644 --- a/src/print_status_panel.cpp +++ b/src/print_status_panel.cpp @@ -65,14 +65,9 @@ PrintStatusPanel::PrintStatusPanel(KWebSocketClient &websocket_client, , elapsed(detail_cont, &clock_img, 100, "0s") , time_left(detail_cont, &hourglass, 100, "...") , estimated_time_s(0) - , flow_ts(std::time(nullptr)) - , last_filament_used(0.0) , filament_diameter(1.75) // XXX: check config - , flow(0.0) , extruder_target(-1) , heater_bed_target(-1) - , cur_layer(-1) - , total_layer(-1) { lv_obj_move_background(status_cont); lv_obj_clear_flag(status_cont, LV_OBJ_FLAG_SCROLLABLE); @@ -173,13 +168,10 @@ void PrintStatusPanel::reset() { elapsed.update_label("0s"); time_left.update_label("..."); estimated_time_s = 0; - flow_ts = std::time(nullptr); - last_filament_used = 0.0; auto v = State::get_instance() ->get_data("/printer_state/configfile/config/extruder/filament_diameter"_json_pointer); filament_diameter = v.is_null() ? 1.750 : std::stod(v.template get()); - flow = 0.0; extruder_target = -1; heater_bed_target = -1; @@ -263,6 +255,12 @@ void PrintStatusPanel::populate() { lv_label_set_text(progress_label, fmt::format("{}%", new_value).c_str()); mini_print_status.update_progress(new_value); } + + v = s->get_data( + "/printer_state/gcode_move/homing_origin/2"_json_pointer); + if (!v.is_null()) { + z_offset.update_label(fmt::format("{:.5} mm", v.template get()).c_str()); + } } void PrintStatusPanel::handle_metadata(const std::string &gcode_file, json &j) { @@ -281,6 +279,8 @@ void PrintStatusPanel::handle_metadata(const std::string &gcode_file, json &j) { } } + current_file = j["/result"_json_pointer]; + auto width_scale = (double)lv_disp_get_physical_hor_res(NULL) / 800.0; auto thumb_detail = KUtils::get_thumbnail(gcode_file, j, width_scale); std::string fullpath = thumb_detail.first; @@ -350,17 +350,10 @@ void PrintStatusPanel::consume(json &j) { } // speed - auto speed = j["/params/0/gcode_move/speed"_json_pointer]; - auto speed_factor = State::get_instance() - ->get_data("/printer_state/gcode_move/speed_factor"_json_pointer); - - if (!speed.is_null() && !speed_factor.is_null()) { - double s = speed.template get(); - double sf = speed_factor.template get(); - int req_speed = static_cast((s / 60.0 * sf)); - - spdlog::trace("calucated speed {}, {}, {}", speed, speed_factor, req_speed); - print_speed.update_label((std::to_string(req_speed) + " mm/s").c_str()); + auto speed = j["/params/0/motion_report/live_velocity"_json_pointer]; + if (!speed.is_null()) { + int s = static_cast(speed.template get()); + print_speed.update_label((std::to_string(s) + " mm/s").c_str()); } // zoffset @@ -406,10 +399,10 @@ void PrintStatusPanel::consume(json &j) { mini_print_status.update_progress(new_value); } - // flow - v = j["/params/0/print_stats/filament_used"_json_pointer]; + v = j["/params/0/motion_report/live_extruder_velocity"_json_pointer]; if (!v.is_null()) { - update_flow_rate(v.template get()); + double flow = pi() / 4 * std::pow(filament_diameter, 2) * v.template get(); + flow_rate.update_label(fmt::format("{:.1f} mm3/s", flow > 0.0 ? flow : 0.0).c_str()); } v = j["/params/0/pause_resume/is_paused"_json_pointer]; @@ -433,9 +426,7 @@ void PrintStatusPanel::consume(json &j) { // layers v = j["/params/0/print_stats/info"_json_pointer]; - if (!v.is_null()) { - update_layers(v); - } + update_layers(v); } void PrintStatusPanel::handle_callback(lv_event_t *event) { @@ -473,83 +464,72 @@ void PrintStatusPanel::update_time_progress(uint32_t time_passed) { } elapsed.update_label(KUtils::eta_string(time_passed).c_str()); - - // auto speed_factor = State::get_instance() - // ->get_data(json::json_pointer("/status/gcode_move/speed_factor")); - } -void PrintStatusPanel::update_flow_rate(double filament_used) { - /* - - const extruderPosition = parseFloat(filament_used) - const filament_diameter = this.$store.getters['printer/getPrinterSettings']('extruder.filament_diameter') || 1.75 - const timeDelta = (Date.now() - this.flow.timestamp) / 1000 - if (timeDelta >= 2) { - if ( - this.flow.lastExtruderPosition && - this.flow.lastExtruderPosition < extruderPosition && - this.flow.timestamp - ) { - // console.log('getting flow', filament_diameter, timeDelta) - const filamentDiff = extruderPosition - this.flow.lastExtruderPosition - const filamentCrossSection = Math.pow(filament_diameter / 2, 2) * Math.PI - - this.flow.value = filamentCrossSection * filamentDiff / timeDelta - - if (this.flow.max < this.flow.value) this.flow.max = this.flow.value - } +void PrintStatusPanel::update_layers(json &info) { + layers.update_label(fmt::format("{} / {}", current_layer(info), max_layer(info)).c_str()); +} - this.flow.lastExtruderPosition = extruderPosition - this.flow.timestamp = Date.now() - } - */ - auto delta = std::time(nullptr) - flow_ts; - spdlog::trace("got filament_used {}, last_filament_used {}, t_delta {}", - filament_used, last_filament_used, delta); - if (delta > 1) { - if (last_filament_used - && (last_filament_used < filament_used)) { - spdlog::trace("updating flow last {} cur {}, t_delta {}", - last_filament_used, filament_used, delta); - - auto filament_delta = filament_used - last_filament_used; - auto filament_xsection = std::pow((filament_diameter / 2), 2) * pi(); - flow = filament_xsection * filament_delta / delta; - - spdlog::trace("caculated flow {}", flow); - #ifdef GUPPY_SMALL_SCREEN - flow_rate.update_label(fmt::format("{:.1f} mm3/s", flow).c_str()); - #else - flow_rate.update_label(fmt::format("{:.2f} mm3/s", flow).c_str()); - #endif +int PrintStatusPanel::max_layer(json &info) { + if (!info.is_null()) { + auto v = info["/total_layer"_json_pointer]; + if (!v.is_null()) { + return v.template get(); } - - last_filament_used = filament_used; - flow_ts = std::time(nullptr); } -} -void PrintStatusPanel::update_layers(json &info) { - spdlog::debug("layers {}", info.dump()); - auto v = info["/current_layer"_json_pointer]; - int new_cur_layer = cur_layer; - int new_total_layer = total_layer; - if (!v.is_null()) { - new_cur_layer = v.template get(); + if (!current_file.is_null()) { + auto v = current_file["/layer_count"_json_pointer]; + if (!v.is_null()) { + return v.template get(); + } else { + auto first_layer_height = current_file["/first_layer_height"_json_pointer]; + auto layer_height = current_file["/layer_height"_json_pointer]; + auto object_height = current_file["/object_height"_json_pointer]; + + if (!first_layer_height.is_null() && !layer_height.is_null() && !object_height.is_null()) { + auto layer = static_cast(std::ceil((object_height.template get() - first_layer_height.template get()) / layer_height.template get() + 1)); + return layer > 0 ? layer : 0; + } + } } + return 0; +} - v = info["/total_layer"_json_pointer]; - if (!v.is_null()) { - new_total_layer = v.template get(); +int PrintStatusPanel::current_layer(json &info) { + if (!info.is_null()) { + auto v = info["/current_layer"_json_pointer]; + if (!v.is_null()) { + return v.template get(); + } } - if (new_total_layer != total_layer || new_cur_layer != cur_layer) { - total_layer = new_total_layer; - cur_layer = new_cur_layer; + if (!current_file.is_null()) { + State *s = State::get_instance(); + auto pd = s->get_data("/printer_state/print_stats/print_duration"_json_pointer); + auto zpos = s->get_data("/printer_state/gcode_move/gcode_position/2"_json_pointer); + + auto first_layer_height = current_file["/first_layer_height"_json_pointer]; + auto layer_height = current_file["/layer_height"_json_pointer]; + + if (!pd.is_null() + && pd.template get() > 0 + && !zpos.is_null() + && !first_layer_height.is_null() + && !layer_height.is_null()) { + auto layer = static_cast(std::ceil((zpos.template get() - first_layer_height.template get()) / layer_height.template get() + 1)); + auto total = max_layer(info); + if (layer > total) { + return total; + } - layers.update_label(fmt::format("{} / {}", cur_layer, total_layer).c_str()); + if (layer > 0) { + return layer; + } + } } + + return 0; } FineTunePanel &PrintStatusPanel::get_finetune_panel() { diff --git a/src/print_status_panel.h b/src/print_status_panel.h index b6bdd90..1817085 100644 --- a/src/print_status_panel.h +++ b/src/print_status_panel.h @@ -37,7 +37,9 @@ class PrintStatusPanel : public NotifyConsumer { void update_time_progress(uint32_t time_passed); void update_flow_rate(double filament_used); void update_layers(json &info); - + int max_layer(json &info); + int current_layer(json &info); + FineTunePanel &get_finetune_panel(); private: @@ -81,8 +83,7 @@ class PrintStatusPanel : public NotifyConsumer { double flow; int extruder_target; int heater_bed_target; - int cur_layer; - int total_layer; + json current_file; std::map fan_speeds; }; diff --git a/src/state.cpp b/src/state.cpp index b9f9014..803c43e 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -49,7 +49,6 @@ void State::reset() { void State::set_data(const std::string &key, json &j, const std::string &json_path) { std::lock_guard guard(lock); - // spdlog::debug("setting state {} : {}", key, j.dump()); auto patch = j[json::json_pointer(json_path)]; if (!patch.is_null()) { // spdlog::debug("setting data key {}\nbefore: {}\npatch: {}", key, data.contains(key) ? data[key].dump() : "nil" @@ -57,7 +56,6 @@ void State::set_data(const std::string &key, json &j, const std::string &json_pa data[key].merge_patch(patch); // spdlog::debug("after: {}", data.contains(key) ? data[key].dump() : "nil"); } - } json &State::get_data() { diff --git a/src/websocket_client.cpp b/src/websocket_client.cpp index 8e3585b..bca6a47 100644 --- a/src/websocket_client.cpp +++ b/src/websocket_client.cpp @@ -37,7 +37,7 @@ int KWebSocketClient::connect(const char* url, spdlog::debug("onopen {}", resp->body.c_str()); connected(); }; - onmessage = [this, connected, disconnected](const std::string& msg) { + onmessage = [this, connected, disconnected](const std::string &msg) { // if (msg.find("notify_proc_stat_update") == std::string::npos) { // spdlog::trace("onmessage(type={} len={}): {}", opcode() == WS_OPCODE_TEXT ? "text" : "binary", // (int)msg.size(), msg); @@ -45,48 +45,47 @@ int KWebSocketClient::connect(const char* url, auto j = json::parse(msg); if (j.contains("id")) { - // XXX: get rid of consumers and use function ptrs for callback - const auto &entry = consumers.find(j["id"]); - if (entry != consumers.end()) { - entry->second->consume(j); - consumers.erase(entry); - } - - const auto &cb_entry = callbacks.find(j["id"]); - if (cb_entry != callbacks.end()) { - cb_entry->second(j); - callbacks.erase(cb_entry); - } + const auto &entry = consumers.find(j["id"]); + if (entry != consumers.end()) { + entry->second->consume(j); + consumers.erase(entry); + } + + const auto &cb_entry = callbacks.find(j["id"]); + if (cb_entry != callbacks.end()) { + cb_entry->second(j); + callbacks.erase(cb_entry); + } } if (j.contains("method")) { std::string method = j["method"].template get(); if ("notify_status_update" == method) { - for (const auto &entry : notify_consumers) { - entry->consume(j); - } - }// else if ("notify_gcode_response" == method) { + for (const auto &entry : notify_consumers) { + entry->consume(j); + } + } // else if ("notify_gcode_response" == method) { // for (const auto &gcode_cb : gcode_resp_cbs) { // gcode_cb(j); // } // } else if ("notify_klippy_disconnected" == method) { - disconnected(); + disconnected(); } else if ("notify_klippy_ready" == method) { - connected(); + connected(); } for (const auto &entry : method_resp_cbs) { - if (method == entry.first) { - for (const auto &handler_entry : entry.second) { - handler_entry.second(j); - } - } + if (method == entry.first) { + for (const auto &handler_entry : entry.second) { + handler_entry.second(j); + } + } } } }; - + onclose = [disconnected]() { spdlog::debug("onclose"); disconnected(); @@ -147,17 +146,17 @@ int KWebSocketClient::send_jsonrpc(const std::string &method, const json ¶ms } void KWebSocketClient::register_notify_update(NotifyConsumer *consumer) { - const auto &entry = notify_consumers.find(consumer); - if (entry == notify_consumers.end()) { - notify_consumers.insert(consumer); + if (std::find(notify_consumers.begin(), notify_consumers.end(), consumer) == std::end(notify_consumers)) { + notify_consumers.push_back(consumer); } } void KWebSocketClient::unregister_notify_update(NotifyConsumer *consumer) { - const auto &entry = notify_consumers.find(consumer); - if (entry != notify_consumers.end()) { - notify_consumers.erase(entry); - } + notify_consumers.erase(std::remove_if( + notify_consumers.begin(), notify_consumers.end(), + [consumer](NotifyConsumer *c) { + return c == consumer; + })); } int KWebSocketClient::send_jsonrpc(const std::string &method, diff --git a/src/websocket_client.h b/src/websocket_client.h index 0387554..b50f89d 100644 --- a/src/websocket_client.h +++ b/src/websocket_client.h @@ -6,7 +6,6 @@ #include "hv/json.hpp" #include -#include #include #include #include @@ -41,7 +40,7 @@ class KWebSocketClient : public hv::WebSocketClient { private: std::map> callbacks; std::map consumers; - std::set notify_consumers; + std::vector notify_consumers; // std::vector> gcode_resp_cbs; // method_name : { :handler-cb }