TRAIN_SMILE,
TRAIN_FROWN
} DRAW_TARGET;
+
typedef struct appdata {
Evas_Object *win;
Evas_Object *conform;
* @param[out] length of data len
* @retval 0 if no error
*/
-int data_parse_route(const char *source, char **route, char **data);
+int util_parse_route(const char *source, char **route, char **data);
/**
* @brief get full resource path for given file.
* @param[in] shared true if resource is in shared/res
* @retval APP_ERROR_NONE if no error
*/
-int data_get_resource_path(const char *file, char *full_path, bool shared);
+int util_get_resource_path(const char *file, char *full_path, bool shared);
+
+/**
+ * @brief handle given path_data. If data is invalid, it is essentially noop
+ *
+ * @param ad appdata
+ * @param data path_data to be handled
+ */
+void data_handle_path_data(appdata_s *ad, const char *data);
+
+/**
+ * @brief update draw target from the data. currently the label is depending on
+ * ad->tries only
+ *
+ * @param[in] ad appdata
+ * @return int APP_ERROR_NONE if success
+ */
+int data_update_draw_target(appdata_s *ad);
/**
* @brief extract data feature from given model.
* @param[in] ad appdata
- * @param[in] dst state the name of the data set
- * @param[in] append decide whether to append to the exisiting file
*
* This function runs a mobilnetv2 last layer detached and saves an output
* vector. input for this model is png file drawn to the canvas(stored in
* appdata) output can be pased to nntrainer and used.
*/
-int data_extract_feature(appdata_s *ad, const char *dst, bool append);
+int data_extract_feature(appdata_s *ad);
/**
* @brief nntrainer training model that is to run from pthread_create
- * @param[in] data appdata.
+ * @param[in] ad appdata.
* @return not used.
*/
void *data_run_model(void *ad);
/**
+ * @brief nntrainer update train result from data_run_model
+ *
+ * @param[in] ad appdata
+ * @return not used
+ */
+void *data_update_train_result(void *ad);
+
+/**
* @brief parse result string
* @param[in] result result string to be parsed.
* @param[out] train_result structured data from result string
#ifndef __nntrainer_example_custom_shortcut_H__
#define __nntrainer_example_custom_shortcut_H__
-#include "data.h"
-#include <Elementary.h>
-#include <dlog.h>
#include <tizen.h>
+#include <Elementary.h>
+
+#include "data.h"
+#include "view.h"
+
#if !defined(PACKAGE)
#define PACKAGE "org.example.nntrainer-example-custom-shortcut"
#endif
+/**
+ * @brief presenter to handle routing to a page
+ *
+ * @param data appdata
+ * @param obj not used
+ * @param emission not used
+ * @param source string information that has where to go.
+ */
+void presenter_on_routes_request(void *data, Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source);
+
+/**
+ * @brief presenter to handle canvas submission in the inference
+ *
+ * @param data appdata
+ * @param obj not used
+ * @param emission not used
+ * @param source not used
+ */
+void presenter_on_canvas_submit_inference(void *data, Evas_Object *obj,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED);
+
+/**
+ * @brief presenter to handle canvas submission in the training
+ *
+ * @param data appdata
+ * @param obj not used
+ * @param emission not used
+ * @param source not used
+ */
+void presenter_on_canvas_submit_training(void *data, Evas_Object *obj,
+ const char *emission EINA_UNUSED,
+ const char *source EINA_UNUSED);
+
#endif /* __nntrainer_example_custom_shortcut_H__ */
/**
* @brief initiate window and conformant.
* @param[in] ad appdata of the app
- * @param[in] w width
- * @param[in] h height
* @retval #APP_ERROR_*
*/
int view_init(appdata_s *ad);
/**
- * @brief creates layout from edj
+ * @brief initiate canvas
+ *
+ * @param[in] ad appdata
+ * @return int APP_DATA_NONE when no error
+ */
+int view_init_canvas(appdata_s *ad);
+
+/**
+ * @brief creates layout from edj and push it to the naviframe
* @param[in/out] ad appdata of the app
- * @param[in] group_name name of the layout to be pushed to main naviframe.
+ * @param[in] path name of the layout to be pushed to main naviframe.
+ */
+int view_routes_to(appdata_s *ad, const char *path);
+
+/**
+ * @brief set canvas clean and update related labels
+ *
+ * @param ad[in] appdata
*/
-int view_routes_to(appdata_s *ad, const char *group_name);
+void view_set_canvas_clean(appdata_s *ad);
/**
* @brief callback function to update training result
* @bug No known bugs except for NYI items
*
*/
-#include "data.h"
#include <regex.h>
#include <stdio.h>
#include <string.h>
-int data_parse_route(const char *source, char **route, char **data) {
+#include "data.h"
+
+int util_parse_route(const char *source, char **route, char **data) {
char *dst = strdup(source);
const char sep = ':';
char *i;
return APP_ERROR_NONE;
}
-int data_get_resource_path(const char *file, char *full_path, bool shared) {
+int util_get_resource_path(const char *file, char *full_path, bool shared) {
char *root_path;
if (shared) {
root_path = app_get_shared_resource_path();
return APP_ERROR_NONE;
}
-int data_get_data_path(const char *file, char *full_path) {
+int util_get_data_path(const char *file, char *full_path) {
char *root_path;
root_path = app_get_data_path();
pthread_mutex_unlock(&ad->pipe_lock);
}
-static int run_nnpipeline_(appdata_s *ad, const char *src, bool append) {
+static int run_nnpipeline_(appdata_s *ad, const char *src) {
char pipe_description[5000];
char model_path[PATH_MAX];
int status = ML_ERROR_NONE;
- data_get_resource_path("mobilenetv2.tflite", model_path, false);
+ util_get_resource_path("mobilenetv2.tflite", model_path, false);
status = pthread_mutex_lock(&ad->pipe_lock);
if (status != 0) {
return status;
}
-int data_extract_feature(appdata_s *ad, const char *dst, bool append) {
+void data_handle_path_data(appdata_s *ad, const char *data) {
+ /// handling path_data to check if it's for inference or path
+ if (!strcmp(data, "inference")) {
+ ad->draw_target = INFER;
+ } else if (!strcmp(data, "train")) {
+ ad->draw_target = TRAIN_UNSET;
+ }
+}
+
+int data_update_draw_target(appdata_s *ad) {
+ switch (ad->tries % NUM_CLASS) {
+ case 0:
+ ad->draw_target = TRAIN_SMILE;
+ return APP_ERROR_NONE;
+ case 1:
+ ad->draw_target = TRAIN_FROWN;
+ return APP_ERROR_NONE;
+ default:
+ LOG_E("Given label is unknown");
+ return APP_ERROR_NOT_SUPPORTED;
+ }
+}
+
+int data_extract_feature(appdata_s *ad) {
char png_path[PATH_MAX];
+ const char *dst =
+ ad->tries < MAX_TRAIN_TRIES ? TRAIN_SET_PATH : VALIDATION_SET_PATH;
cairo_status_t cr_stat = CAIRO_STATUS_SUCCESS;
int status = APP_ERROR_NONE;
- data_get_data_path("temp.png", png_path);
+ util_get_data_path("temp.png", png_path);
LOG_D("start writing to png_path: %s ", png_path);
cr_stat = cairo_surface_write_to_png(ad->cr_surface, png_path);
return APP_ERROR_INVALID_PARAMETER;
}
- data_get_data_path(dst, ad->pipe_dst);
+ util_get_data_path(dst, ad->pipe_dst);
LOG_I("start inference to dataset: %s ", ad->pipe_dst);
- status = run_nnpipeline_(ad, png_path, append);
+ status = run_nnpipeline_(ad, png_path);
return status;
}
printf("test");
LOG_D("start running model");
- data_get_resource_path("model.ini", model_conf_path, false);
- data_get_data_path("label.dat", label_path);
+ util_get_resource_path("model.ini", model_conf_path, false);
+ util_get_data_path("label.dat", label_path);
LOG_D("opening file");
file = fopen(label_path, "w");
return NULL;
}
+void *data_update_train_result(void *data) {
+ appdata_s *ad = (appdata_s *)data;
+
+ // run model in another thread
+ int read_fd = ad->pipe_fd[0];
+ FILE *fp;
+ char buf[255];
+
+ fp = fdopen(read_fd, "r");
+
+ LOG_D("start waiting to get result");
+
+ ecore_pipe_thaw(ad->data_output_pipe);
+
+ while (fgets(buf, 255, fp) != NULL) {
+ if (ecore_pipe_write(ad->data_output_pipe, buf, 255) == false) {
+ LOG_E("pipe write error");
+ return NULL;
+ };
+ usleep(150);
+ }
+
+ LOG_D("training finished");
+ fclose(fp);
+ close(read_fd);
+ sleep(1);
+ ecore_pipe_freeze(ad->data_output_pipe);
+
+ return NULL;
+}
+
int data_parse_result_string(const char *src, train_result_s *train_result) {
// clang-format off
// #10/10 - Training Loss: 0.398767 >> [ Accuracy: 75% - Validation Loss : 0.467543 ]
* @bug No known bugs except for NYI items
*/
-#include "main.h"
-#include "data.h"
-#include "view.h"
#include <pthread.h>
+
#include <tizen.h>
+#include "data.h"
+#include "main.h"
+#include "view.h"
+
+static int routes_to_(appdata_s *ad, const char *source) {
+ int status = view_routes_to(ad, source);
+ if (status != 0) {
+ LOG_E("routing to a new view failed for %s", source);
+ }
+
+ elm_layout_signal_callback_add(ad->layout, "routes/to", "*",
+ &presenter_on_routes_request, ad);
+
+ return status;
+}
+
+static int train_(appdata_s *ad) {
+ int status = ML_ERROR_NONE;
+
+ status = pipe(ad->pipe_fd);
+ if (status < 0) {
+ LOG_E("opening pipe for training failed");
+ }
+
+ ad->best_accuracy = 0.0;
+
+ LOG_D("creating thread to run model");
+ status = pthread_create(&ad->tid_writer, NULL, data_run_model, (void *)ad);
+ if (status < 0) {
+ LOG_E("creating pthread failed %s", strerror(errno));
+ return status;
+ }
+ status = pthread_detach(ad->tid_writer);
+ if (status < 0) {
+ LOG_E("detaching writing thread failed %s", strerror(errno));
+ pthread_cancel(ad->tid_writer);
+ }
+
+ status =
+ pthread_create(&ad->tid_reader, NULL, data_update_train_result, (void *)ad);
+ if (status < 0) {
+ LOG_E("creating pthread failed %s", strerror(errno));
+ return status;
+ }
+ status = pthread_detach(ad->tid_reader);
+ if (status < 0) {
+ LOG_E("detaching reading thread failed %s", strerror(errno));
+ pthread_cancel(ad->tid_writer);
+ }
+
+ return status;
+}
+
+static int init_page_(appdata_s *ad, const char *path) {
+ int status = APP_ERROR_NONE;
+
+ if (!strcmp(path, "draw")) {
+ ad->tries = 0;
+
+ status = view_init_canvas(ad);
+ if (status != APP_ERROR_NONE) {
+ LOG_E("initiating canvas failed");
+ return status;
+ }
+
+ view_set_canvas_clean(ad);
+
+ if (ad->draw_target == INFER) {
+ elm_layout_signal_callback_add(ad->layout, "draw/proceed", "",
+ presenter_on_canvas_submit_inference, ad);
+ } else if (ad->draw_target == TRAIN_UNSET) {
+ elm_layout_signal_callback_add(ad->layout, "draw/proceed", "",
+ presenter_on_canvas_submit_training, ad);
+ } else {
+ LOG_E("undefined draw target in initiation");
+ return APP_ERROR_INVALID_CONTEXT;
+ }
+ return status;
+ }
+
+ return status;
+}
+
+void presenter_on_routes_request(void *data, Evas_Object *obj EINA_UNUSED,
+ const char *emission EINA_UNUSED,
+ const char *source) {
+ char *path, *path_data;
+ appdata_s *ad = (appdata_s *)data;
+
+ int status = util_parse_route(source, &path, &path_data);
+ if (status) {
+ LOG_E("something wrong with parsing %s", source);
+ return;
+ }
+
+ LOG_D("%s %s", path, path_data);
+ if (routes_to_(ad, path) != 0)
+ return;
+
+ /// check if path and path_data should be handled in special way,
+ data_handle_path_data(ad, path_data);
+ init_page_(ad, path);
+}
+
+void presenter_on_canvas_submit_inference(void *data, Evas_Object *obj,
+ const char *emission,
+ const char *source) {
+ /** appdata handling NYI */
+ if (routes_to_((appdata_s *)data, "test_result") != 0)
+ return;
+}
+
+void presenter_on_canvas_submit_training(void *data, Evas_Object *obj,
+ const char *emission,
+ const char *source) {
+ appdata_s *ad = (appdata_s *)data;
+ int status = APP_ERROR_NONE;
+
+ status = data_update_draw_target(ad);
+ if (status != APP_ERROR_NONE) {
+ LOG_E("setting draw target failed");
+ return;
+ }
+
+ status = data_extract_feature(ad);
+ if (status != APP_ERROR_NONE) {
+ LOG_E("feature extraction failed");
+ return;
+ }
+
+ if (ad->tries == MAX_TRIES - 1) {
+ ad->tries = 0;
+ elm_naviframe_item_pop(ad->naviframe);
+ routes_to_((appdata_s *)data, "train_result");
+ train_(ad);
+ }
+
+ /// prepare next canvas
+ ad->tries++;
+ view_set_canvas_clean(ad);
+}
+
+/********************* app related methods **************************/
static bool app_create(void *data) {
/* Hook to take necessary actions before main event loop starts
Initialize UI resources and application's data
return false;
}
- data_get_resource_path(EDJ_PATH, ad->edj_path, false);
+ util_get_resource_path(EDJ_PATH, ad->edj_path, false);
if (chdir(data_path) < 0) {
LOG_E("change root directory failed");
view_init(ad);
- if (view_routes_to(ad, "home"))
+ if (routes_to_(ad, "home"))
return false;
ad->home = ad->nf_it;
const char *group_name,
Eext_Event_Cb back_cb, void *user_data);
-static int create_canvas_(appdata_s *ad, const char *draw_mode);
-static int train(appdata_s *ad);
-
static void on_win_delete_(void *data, Evas_Object *obj, void *event_info) {
ui_app_exit();
}
elm_naviframe_item_pop(obj);
}
-static void on_routes_to_(void *data, Evas_Object *obj, const char *emission,
- const char *source);
-
/**
* @brief initiate window and conformant.
* @param[in] ad appdata of the app
/**
* @brief creates layout from edj
* @param[in/out] ad app data of the add
- * @param[in] group_name name of the layout to be pushed to main naviframe.
+ * @param[in] path name of the layout to be pushed to main naviframe.
*/
-int view_routes_to(appdata_s *ad, const char *group_name) {
- char *path, *path_data;
- int status;
-
- status = data_parse_route(group_name, &path, &path_data);
- if (status) {
- LOG_E("something wrong with parsing %s", group_name);
- return status;
- }
-
- LOG_D("%s %s", path, path_data);
+int view_routes_to(appdata_s *ad, const char *path) {
ad->layout = create_layout_(ad->naviframe, ad->edj_path, path, NULL, NULL);
-
if (ad->layout == NULL) {
LOG_E("failed to create layout");
- status = APP_ERROR_INVALID_CONTEXT;
evas_object_del(ad->win);
- goto CLEAN_UP;
+ return APP_ERROR_INVALID_CONTEXT;
}
ad->nf_it = elm_naviframe_item_push(ad->naviframe, NULL, NULL, NULL,
if (ad->nf_it == NULL) {
LOG_E("naviframe_item_push failed");
- status = APP_ERROR_INVALID_PARAMETER;
- goto CLEAN_UP;
- }
-
- elm_layout_signal_callback_add(ad->layout, "routes/to", "*", on_routes_to_,
- ad);
-
- if (!strcmp(path, "draw")) {
- status = create_canvas_(ad, path_data);
- }
-
- if (!strcmp(path, "train_result")) {
- status = train(ad);
+ return APP_ERROR_INVALID_PARAMETER;
}
-CLEAN_UP:
- free(path);
- return status;
-}
-
-static void on_routes_to_(void *data, Evas_Object *obj, const char *emission,
- const char *source) {
- view_routes_to((appdata_s *)data, source);
+ return APP_ERROR_NONE;
}
/**
void *event_info) {
LOG_D("deleting canvas");
appdata_s *ad = (appdata_s *)data;
+ cairo_status_t stat;
- evas_object_del(ad->canvas);
- cairo_surface_destroy(ad->cr_surface);
- if (cairo_surface_status(ad->cr_surface) != CAIRO_STATUS_SUCCESS) {
- LOG_E("delete cr_surface failed");
+ if (ad->cr_surface != NULL) {
+ cairo_surface_destroy(ad->cr_surface);
+ stat = cairo_surface_status(ad->cr_surface);
+ if (stat != CAIRO_STATUS_SUCCESS)
+ LOG_E("delete cr_surface failed reason: %s",
+ cairo_status_to_string(stat));
+ ad->cr_surface = NULL;
}
- cairo_destroy(ad->cr);
- if (cairo_status(ad->cr) != CAIRO_STATUS_SUCCESS) {
- LOG_E("delete cairo failed");
- }
-}
-static void canvas_erase_all_(appdata_s *ad) {
- cairo_set_source_rgba(ad->cr, 0.3, 0.3, 0.3, 0.2);
- cairo_set_operator(ad->cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint(ad->cr);
- cairo_surface_flush(ad->cr_surface);
- evas_object_image_data_update_add(ad->canvas, 0, 0, ad->width, ad->height);
-}
+ if (ad->cr != NULL) {
+ cairo_destroy(ad->cr);
+ stat = cairo_status(ad->cr);
+ if (stat != CAIRO_STATUS_NULL_POINTER)
+ LOG_E("delete cairo failed reason: %s", cairo_status_to_string(stat));
+ ad->cr = NULL;
+ }
-static void on_draw_reset_(void *data, Evas_Object *obj, const char *emission,
- const char *source) {
- appdata_s *ad = (appdata_s *)data;
- LOG_D("draw reset");
- canvas_erase_all_(ad);
+ evas_object_del(ad->canvas);
}
-static void set_draw_texts_(appdata_s *ad) {
+void view_set_canvas_clean(appdata_s *ad) {
char buf[256];
char emoji[5];
+
+ /// setting draw label and text
switch (ad->draw_target) {
case INFER:
strcpy(emoji, "❓");
sprintf(buf, "draw for %s [%d/%d]", emoji, ad->tries + 1, MAX_TRIES);
elm_object_part_text_set(ad->layout, "draw/title", buf);
elm_object_part_text_set(ad->layout, "draw/label", emoji);
-}
-static void on_draw_proceed_infer_(void *data, Evas_Object *obj,
- const char *emission, const char *source) {
- view_routes_to((appdata_s *)data, "test_result");
+ /// clear cairo surface
+ cairo_set_source_rgba(ad->cr, 0.3, 0.3, 0.3, 0.2);
+ cairo_set_operator(ad->cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ad->cr);
+ cairo_surface_flush(ad->cr_surface);
+ evas_object_image_data_update_add(ad->canvas, 0, 0, ad->width, ad->height);
}
-static void on_draw_proceed_train_(void *data, Evas_Object *obj,
- const char *emission, const char *source) {
+static void on_draw_reset_(void *data, Evas_Object *obj, const char *emission,
+ const char *source) {
appdata_s *ad = (appdata_s *)data;
- int status = APP_ERROR_NONE;
-
- switch (ad->tries % NUM_CLASS) {
- case 0:
- ad->draw_target = TRAIN_SMILE;
- break;
- case 1:
- ad->draw_target = TRAIN_FROWN;
- break;
- default:
- LOG_E("Given label is unknown");
- return;
- }
-
- LOG_D("labeling proceed");
- status = data_extract_feature(
- ad, ad->tries < MAX_TRAIN_TRIES ? TRAIN_SET_PATH : VALIDATION_SET_PATH,
- true);
-
- if (status != APP_ERROR_NONE) {
- LOG_E("feature extraction failed");
- }
-
- if (ad->tries == MAX_TRIES - 1) {
- ad->tries = 0;
- elm_naviframe_item_pop(ad->naviframe);
- view_routes_to(ad, "train_result");
- return;
- }
-
- /// prepare next canvas
- ad->tries++;
- set_draw_texts_(ad);
- canvas_erase_all_(ad);
+ LOG_D("draw reset");
+ view_set_canvas_clean(ad);
}
-static int create_canvas_(appdata_s *ad, const char *draw_mode) {
- LOG_D("init canvas, %s", draw_mode);
+int view_init_canvas(appdata_s *ad) {
Eina_Bool status;
Evas_Object *frame = elm_layout_add(ad->layout);
elm_layout_signal_callback_add(ad->layout, "draw/reset", "", on_draw_reset_,
ad);
- if (!strcmp(draw_mode, "inference")) {
- ad->draw_target = INFER;
- elm_layout_signal_callback_add(ad->layout, "draw/proceed", "",
- on_draw_proceed_infer_, ad);
- } else if (!strcmp(draw_mode, "train")) {
- ad->draw_target = TRAIN_UNSET;
- elm_layout_signal_callback_add(ad->layout, "draw/proceed", "",
- on_draw_proceed_train_, ad);
- }
-
- set_draw_texts_(ad);
- ad->tries = 0;
ad->canvas = canvas;
ad->cr_surface = cairo_surface;
ad->cr = cr;
return APP_ERROR_NONE;
}
-static void *process_train_result(void *data) {
- appdata_s *ad = (appdata_s *)data;
-
- // run model in another thread
- int read_fd = ad->pipe_fd[0];
- FILE *fp;
- char buf[255];
-
- fp = fdopen(read_fd, "r");
-
- LOG_D("start waiting to get result");
-
- ecore_pipe_thaw(ad->data_output_pipe);
-
- while (fgets(buf, 255, fp) != NULL) {
- if (ecore_pipe_write(ad->data_output_pipe, buf, 255) == false) {
- LOG_E("pipe write error");
- return NULL;
- };
- usleep(150);
- }
-
- LOG_D("training finished");
- fclose(fp);
- close(read_fd);
- sleep(1);
- ecore_pipe_freeze(ad->data_output_pipe);
-
- return NULL;
-}
-
-static int train(appdata_s *ad) {
- int status = ML_ERROR_NONE;
-
- status = pipe(ad->pipe_fd);
- if (status < 0) {
- LOG_E("opening pipe for training failed");
- }
-
- ad->best_accuracy = 0.0;
-
- LOG_D("creating thread to run model");
- status = pthread_create(&ad->tid_writer, NULL, data_run_model, (void *)ad);
- if (status < 0) {
- LOG_E("creating pthread failed %s", strerror(errno));
- return status;
- }
- status = pthread_detach(ad->tid_writer);
- if (status < 0) {
- LOG_E("detaching writing thread failed %s", strerror(errno));
- pthread_cancel(ad->tid_writer);
- }
-
- status =
- pthread_create(&ad->tid_reader, NULL, process_train_result, (void *)ad);
- if (status < 0) {
- LOG_E("creating pthread failed %s", strerror(errno));
- return status;
- }
- status = pthread_detach(ad->tid_reader);
- if (status < 0) {
- LOG_E("detaching reading thread failed %s", strerror(errno));
- pthread_cancel(ad->tid_writer);
- }
-
- return status;
-}
-
void view_update_result_cb(void *data, void *buffer, unsigned int nbytes) {
appdata_s *ad = (appdata_s *)data;