/* * TODO: rename this to dbus_procedures.c * eulogium_procedures, available procedures * * Copyright (c) 2015 Ultimaker B.V. * Author: Olliver Schinagl * * SPDX-License-Identifier: AGPL-3.0+ */ #include #include #include #include "dbus_common.h" #include "eulogium.h" #include "print_data.h" #include "procedures.h" #include "settings_data.h" #include "ui_widgets.h" #define _PROC_PRINT "PRINT" #define _META_PRINT_JOBNAME "jobname" #define _META_PRINT_JOBNAME_TYPE VALUE_STR #define _META_PRINT_TIME "time" #define _META_PRINT_TIME_TYPE VALUE_DOUBLE #define _META_PRINT_TIME_TOTAL "time_total" #define _META_PRINT_TIME_TOTAL_TYPE VALUE_DOUBLE #define _META_PRINT_PROGRESS "progress" #define _META_PRINT_PROGRESS_TYPE VALUE_DOUBLE #define _PROC_POST_PRINT "POST_PRINT" #define _PROC_PRE_PRINT_SETUP "PRE_PRINT_SETUP" #define _PROC_RUN_PRE_PRINT_SETUP "RUN_PRE_PRINT_SETUP" #define _PROC_WAIT_FOR_CLEANUP "WAIT_FOR_CLEANUP" #define _PROC_BED_HEATUP "HEATUP_BED" #define _PROC_HOTEND_HEATUP_0 "HEATUP_HOTEND_0" #define _PROC_HOTEND_HEATUP_1 "HEATUP_HOTEND_1" #define _PROC_PRINT_SPEED "PRINT_SPEED" #define _PROC_FAN_SPEED "FAN_SPEED" #define _PROC_FLOW_RATE "MATERIAL_FLOW" #define _META_CURRENT "current" #define _META_TARGET "target" #define _STEP_PRINTING "PRINTING" #define _STEP_PRINT_SPEEDING "PRINT_SPEEDING" #define _STEP_HOTEND_HEATING "HOTEND_HEATING" #define _STEP_BED_HEATING "BED_HEATING" #define _STEP_FAN_SPEEDING "FAN_SPEEDING" #define _STEP_MATERIAL_FLOWING "MATERIAL_FLOWING" #define _STEP_HOTEND_HOMEING "HOTEND_HOMEING" #define _STEP_BED_HOMEING "HOTEND_HOMEING" #define _PROC_MSG_PRINTER_CLEANED "PRINTER_CLEANED" static Eldbus_Proxy *__proxy = NULL; static void _container_basic_variant(Eldbus_Message_Iter *parent, int type, ...) { Eldbus_Message_Iter *child; va_list value; char sig[2] = { '\0' }; sig[0] = type; child = eldbus_message_iter_container_new(parent, 'v', sig); va_start(value, type); eldbus_message_iter_arguments_vappend(child, sig, value); va_end(value); eldbus_message_iter_container_close(parent, child); } static void _container_dict_basic_variant_append(Eldbus_Message_Iter *array, int type, const char *key, ...) /* TODO rename something key/value */ { Eldbus_Message_Iter *value, *dict; va_list ap; char sig[2] = { '\0' }; sig[0] = type; dict = eldbus_message_iter_container_new(array, 'e', NULL); /* { */ eldbus_message_iter_basic_append(dict, 's', key); /* s (key) */ value = eldbus_message_iter_container_new(dict, 'v', sig); /* start variant */ va_start(ap, key); eldbus_message_iter_arguments_vappend(value, sig, ap); /* v (value) */ va_end(ap); eldbus_message_iter_container_close(dict, value); /* end variant */ eldbus_message_iter_container_close(array, dict); /* } */ } /* TODO move to ui_invalidate_navi_items ?? */ static void _invalidate_navi_items(Evas_Object *navi, const enum navi_page_state page_state) { Eina_List *navi_list, *l; Elm_Object_Item *navi_item; enum navi_page_state page; navi_list = elm_naviframe_items_get(navi); EINA_LIST_FOREACH(navi_list, l, navi_item) { page = (enum navi_page_state)(uintptr_t)elm_object_item_data_get(navi_item); if (page == page_state) elm_object_item_data_set(navi_item, (void *)PAGE_INVALID); } eina_list_free(navi_list); } static void _get_meta_print(void *data, const void *key, Eldbus_Message_Iter *var) { struct print_data *print = data; const char *skey = key; char *var_sig; if (!print) { EINA_LOG_ERR("dial_data should not be null"); return; } var_sig = eldbus_message_iter_signature_get(var); if (!strcmp(skey, _META_PRINT_JOBNAME)) { char *value = NULL; if (!eldbus_message_iter_arguments_get(var, "s", &value)) {/* TODO: check if value is leaking mem here */ EINA_LOG_ERR("Message signature does not match \"s\", got %s", var_sig); } else { uint_fast16_t value_size = strlen(value) + 1; print->jobname = realloc(print->jobname, value_size); strncpy(print->jobname, value, value_size); } } else if (!strcmp(skey, _META_PRINT_TIME)) { int32_t value = 0; if (!eldbus_message_iter_arguments_get(var, "i", &value)) EINA_LOG_ERR("Message signature does not match \"i\", got %s", var_sig); else print->time = value; } else if (!strcmp(skey, _META_PRINT_TIME_TOTAL)) { int32_t value = 0; if (!eldbus_message_iter_arguments_get(var, "i", &value)) EINA_LOG_ERR("Message signature does not match \"i\", got %s", var_sig); else print->total_time = value; } if (!strcmp(skey, _META_PRINT_PROGRESS)) { double value = 0.0; if (!eldbus_message_iter_arguments_get(var, "d", &value)) EINA_LOG_ERR("Message signature does not match \"d\", got %s", var_sig); else print->progress = value; } free(var_sig); } static void _get_meta_cur_tar(void *data, const void *key, Eldbus_Message_Iter *var) { struct settings_dial_data *dial_data = data; const char *skey = key; char *var_sig; double value; if (!dial_data) { EINA_LOG_ERR("dial_data should not be null"); return; } var_sig = eldbus_message_iter_signature_get(var); if (!strcmp(skey, _META_TARGET)) { if (!eldbus_message_iter_arguments_get(var, "d", &value)) EINA_LOG_ERR("Message signature does not match \"d\", got %s", var_sig); else dial_data->value = value; } else if (!strcmp(skey, _META_CURRENT)) { if (!eldbus_message_iter_arguments_get(var, "d", &value)) EINA_LOG_ERR("Message signature does not match \"d\", got %s", var_sig); else dial_data->value_end = value; } free(var_sig); } static void _on_start_print_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { struct print_data *print = data; const char *errname, *errmsg; Eina_Bool print_started = EINA_FALSE; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "b", &print_started)) { EINA_LOG_ERR("Signature mistmatch, \"b\"."); return; } if (print_started == EINA_TRUE) { EINA_LOG_INFO("Print has been successfully started"); print->block = EINA_FALSE; } else { EINA_LOG_ERR("Unable to start print"); /* TODO, if print start failed, invalidate all PRINTING pages */ //_invalidate_navi_items(eulogium->navi, PAGE_PRINTING); } } static void _on_start_dial_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { char *label = data; const char *errname, *errmsg; Eina_Bool procedure_started = EINA_FALSE; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "b", &procedure_started)) { EINA_LOG_ERR("Signature mistmatch, \"b\"."); return; } if (procedure_started == EINA_TRUE) { EINA_LOG_INFO("Procedure %s has been successfully started", label); } else { EINA_LOG_ERR("Unable to start procedure %s", label); /* TODO, if tuning failed .. */ } } Eina_Bool _print_progress_cleanup(void *data, Elm_Object_Item *eoi EINA_UNUSED) { eulogium_print_data_clear(data); return EINA_TRUE; } void procedure_process_step(struct eulogium_data *eulogium, struct procedure_data *procedure) { Evas_Object *content = NULL; Elm_Object_Item *navi_item = NULL; enum navi_page_state page_state = PAGE_NORMAL; if (!procedure) return; if (!procedure->step_active) return; /* TODO build 'remember previous screen so we don't redraw the same' */ EINA_LOG_CRIT("%s", procedure->step_active->key); if (procedure->step_active->step == STEP_PRINTING) { content = eulogium_print_progress(eulogium->navi, eulogium, (struct print_data *)procedure->meta); page_state = PAGE_PRINTING; } if (procedure->step_active->step == PROC_WAIT_FOR_CLEANUP) { _invalidate_navi_items(eulogium->navi, PAGE_PRINTING); content = eulogium_clean_print_bed(eulogium); } if (!content) return; navi_item = elm_naviframe_item_simple_push(eulogium->navi, content); elm_object_item_data_set(navi_item, (void *)page_state); if (page_state == PAGE_PRINTING) elm_naviframe_item_pop_cb_set(navi_item, _print_progress_cleanup, eulogium); } static struct procedure_msg print_msgs[] = { { .key = _PROC_MSG_PRINTER_CLEANED, .msg = PROC_MSG_PRINTER_CLEANED, }, { NULL }, /* sentinel */ }; static struct procedure_step steps_print[] = { { .key = _PROC_RUN_PRE_PRINT_SETUP, .step = PROC_RUN_PRE_PRINT_SETUP, }, { .key = _STEP_PRINTING, .step = STEP_PRINTING, }, { .key = _PROC_POST_PRINT, .step = PROC_POST_PRINT, }, { .key = _PROC_WAIT_FOR_CLEANUP, .step = PROC_WAIT_FOR_CLEANUP, }, { NULL }, /* sentinel */ }; static struct procedure_step steps_bed_temp_set[] = { { .key = _STEP_BED_HEATING, .step = STEP_HEATING, }, { NULL }, /* sentinel */ }; static struct procedure_step steps_hotend_temp_set[] = { { .key = _STEP_HOTEND_HEATING, .step = STEP_HEATING, }, { NULL }, /* sentinel */ }; static struct procedure_step steps_fan_speed_set[] = { { .key = _STEP_FAN_SPEEDING, .step = STEP_SPEEDING, }, { NULL }, /* sentinel */ }; static struct procedure_step steps_flow_rate_set[] = { { .key = _STEP_MATERIAL_FLOWING, .step = STEP_SPEEDING, }, { NULL }, /* sentinel */ }; static struct procedure_step steps_print_speed_set[] = { { .key = _STEP_PRINT_SPEEDING, .step = STEP_SPEEDING, }, { NULL }, /* sentinel */ }; static struct procedure_data procedures[] = { [PROC_PRINT] = { .key = _PROC_PRINT, .status = PROC_READY, .parser = _get_meta_print, .executable = EINA_FALSE, .available = EINA_FALSE, ._steps = steps_print, .step_active = NULL, .meta = NULL, /* struct print_data * */ }, [PROC_BED_HEATUP] = { .key = _PROC_BED_HEATUP, .status = PROC_READY, .parser = _get_meta_cur_tar, .executable = EINA_FALSE, .available = EINA_FALSE, ._steps = steps_bed_temp_set, .step_active = NULL, .meta = NULL, }, [PROC_HOTEND_HEATUP_0] = { .key = _PROC_HOTEND_HEATUP_0, .status = PROC_READY, .parser = _get_meta_cur_tar, .executable = EINA_FALSE, .available = EINA_FALSE, ._steps = steps_hotend_temp_set, .step_active = NULL, .meta = NULL, }, [PROC_HOTEND_HEATUP_1] = { .key = _PROC_HOTEND_HEATUP_1, .status = PROC_READY, .parser = _get_meta_cur_tar, .executable = EINA_FALSE, .available = EINA_FALSE, ._steps = steps_hotend_temp_set, .step_active = NULL, .meta = NULL, }, [PROC_PRINT_SPEED] = { .key = _PROC_PRINT_SPEED, .status = PROC_READY, .parser = _get_meta_cur_tar, .executable = EINA_FALSE, .available = EINA_FALSE, ._steps = steps_print_speed_set, .step_active = NULL, .meta = NULL, }, [PROC_FAN_SPEED] = { .key = _PROC_FAN_SPEED, .status = PROC_READY, .parser = _get_meta_cur_tar, .executable = EINA_FALSE, .available = EINA_FALSE, ._steps = steps_fan_speed_set, .step_active = NULL, .meta = NULL, }, [PROC_FLOW_RATE] = { .key = _PROC_FLOW_RATE, .status = PROC_READY, .parser = _get_meta_cur_tar, .executable = EINA_FALSE, .available = EINA_FALSE, ._steps = steps_flow_rate_set, .step_active = NULL, .meta = NULL, }, { NULL }, /* sentinel */ }; void procedure_meta_set(struct procedure_data *procedure, void *data) { procedure->meta = data; } void *procedure_meta_get(struct procedure_data *procedure) { return procedure->meta; } const struct procedure_step *procedure_step_get(const struct procedure_data *proc, const char *key) { uint_fast16_t i; if (!proc) return NULL; for (i = 0; proc->_steps[i].key; i++) { if (!strcmp(proc->_steps[i].key, key)) return &proc->_steps[i]; } return NULL; }; const struct procedure_data *procedure_get(const char *key) { enum procedure_key i; for (i = PROC_PRINT; procedures[i].key; i++) { if (!strcmp(procedures[i].key, key)) return &procedures[i]; } return NULL; }; Eldbus_Pending *procedure_message(const struct procedure_data *proc, const struct procedure_msg *msg) { return eldbus_proxy_call(__proxy, "messageProcedure", NULL, NULL, -1, "ss", proc->key, msg->key); } Eldbus_Pending *procedure_led_brightness_set(const Evas_Object *dial) { //struct settings_dial_data *dial_data; // dial_data = evas_object_data_get(dial, "dial_data"); // eldbus_proxy_call(dial_data->proxy, "SetBrightness", _on_dial_units_update_ret, dial, -1, ""); } Eldbus_Pending *procedure_print_printer_cleaned(void) /* XXX pass procedure step? */ { return eldbus_proxy_call(__proxy, "messageProcedure", on_method_generic_bool_ret, NULL, -1, "ss", _PROC_PRINT, _PROC_MSG_PRINTER_CLEANED); } /* TODO half of the content of this procedure is generic and could be gotten from the procedure if it where a parameter. This can be made much more generic. */ Eldbus_Pending *procedure_print_start(const struct print_data *print) { Eldbus_Message *msg; Eldbus_Message_Iter *iter, *array; msg = eldbus_proxy_method_call_new(__proxy, "startProcedure"); iter = eldbus_message_iter_get(msg); /* Compose msg sa{sv} */ eldbus_message_iter_basic_append(iter, 's', "PRINT"); array = eldbus_message_iter_container_new(iter, 'a', "{sv}"); _container_dict_basic_variant_append(array, 's', "name", print->name); _container_dict_basic_variant_append(array, 's', "url", print->url); eldbus_message_iter_container_close(iter, array); return eldbus_proxy_send(__proxy, msg, _on_start_print_ret, print, -1); } /* TODO, add resend/retry if actual value does not match current value */ Eldbus_Pending *procedure_target_set(const enum procedure_key proc_key) { Eldbus_Message *msg; Eldbus_Message_Iter *iter, *array; struct procedure_data *procedure = &procedures[proc_key]; struct settings_dial_data *dial_data = procedure->meta; msg = eldbus_proxy_method_call_new(__proxy, "startProcedure"); iter = eldbus_message_iter_get(msg); /* Compose msg sa{sv} */ printf("Prockey: %s\n", procedure->key); eldbus_message_iter_basic_append(iter, 's', procedure->key); array = eldbus_message_iter_container_new(iter, 'a', "{sv}"); _container_dict_basic_variant_append(array, 'd', "target", dial_data->value); eldbus_message_iter_container_close(iter, array); return eldbus_proxy_send(__proxy, msg, _on_start_dial_ret, dial_data->label, -1); } Eldbus_Pending *procedure_metadata_get(enum procedure_key proc_key) { return eldbus_proxy_call(__proxy, "getProcedureMetaData", on_method_get_procedure_metadata_ret, &procedures[proc_key], -1, "s", procedures[proc_key].key); } void procedure_meta_getall(void) { enum procedure_key i; for (i = PROC_NONE; i < PROC_LAST; i++) if (procedures[i].key) procedure_metadata_get(i); }; struct procedure_data *procedures_init(Eldbus_Proxy *proxy) { __proxy = proxy; /* TODO: we probably should do something here to prepare all procedures and their meta data * so that we can do the getall here and drop the function altogether. */ return procedures; }; void procedures_shutdown(void) { free(procedures[PROC_PRINT].meta); eldbus_proxy_unref(__proxy); };