Raspberry Pi Weighting Control System
This project serves as a simple weighting control system, that was realized as a Bachelor Thesis
app_workspace.cpp
Go to the documentation of this file.
1 #include "app_workspace.h"
2 
3 #include <stdio.h>
4 #include <spdlog/spdlog.h>
5 #include "imgui.h"
6 #include "localisation.h"
7 #include "gui_label.h"
8 
9 #include "unistd.h"
10 
11 
21 void threaded_tare();
40 void threaded_measuring_watchdog(bool *msring, std::vector<HX711::Value> **watcher);
41 
42 // init instance
43 std::unique_ptr<app_workspace> app_workspace::instance;
44 
45 std::unique_ptr<app_workspace> &app_workspace::get_instance() {
46  if (!instance.get()) {
47  spdlog::debug("app_workspace.cpp - Instantiating app_workspace");
48  instance = std::unique_ptr<app_workspace>(new app_workspace());
49  }
50  return instance;
51 }
52 
59 }
60 
62  this->s6_role_labels[0] = get_localized_text("GT_ROLE_1");
63  this->s6_role_labels[1] = get_localized_text("GT_ROLE_2");
64  this->s6_role_labels[2] = get_localized_text("GT_ROLE_3");
65 
66  this->s6_month_labels[0] = get_localized_text("GT_MONTH_01");
67  this->s6_month_labels[1] = get_localized_text("GT_MONTH_02");
68  this->s6_month_labels[2] = get_localized_text("GT_MONTH_03");
69  this->s6_month_labels[3] = get_localized_text("GT_MONTH_04");
70  this->s6_month_labels[4] = get_localized_text("GT_MONTH_05");
71  this->s6_month_labels[5] = get_localized_text("GT_MONTH_06");
72  this->s6_month_labels[6] = get_localized_text("GT_MONTH_07");
73  this->s6_month_labels[7] = get_localized_text("GT_MONTH_08");
74  this->s6_month_labels[8] = get_localized_text("GT_MONTH_09");
75  this->s6_month_labels[9] = get_localized_text("GT_MONTH_10");
76  this->s6_month_labels[10] = get_localized_text("GT_MONTH_11");
77  this->s6_month_labels[11] = get_localized_text("GT_MONTH_12");
78 
79  this->s6_unit_sel_labels[0] = get_localized_text("GT_G_UNIT");
80  this->s6_unit_sel_labels[1] = get_localized_text("GT_KG_UNIT");
81 
82  this->unit_sel_labels[0] = get_localized_text("GT_MG_UNIT");
83  this->unit_sel_labels[1] = get_localized_text("GT_G_UNIT");
84  this->unit_sel_labels[2] = get_localized_text("GT_KG_UNIT");
85 
86  this->hx_measure_opts[0] = get_localized_text("SCREEN_2_CB1_SAMPLES");
87  this->hx_measure_opts[1] = get_localized_text("SCREEN_2_CB1_TIMEOUT");
88 
89  this->s3_filter_opt_labels[0] = get_localized_text("SCREEN_3_CB1_LARGER");
90  this->s3_filter_opt_labels[1] = get_localized_text("SCREEN_3_CB1_SMALLER");
91 }
92 
94  try {
95  HX711::Rate rate = HX711::Rate::HZ_80;
96  if (this->main_config->hx_conf.rate == 80) {
97  rate = HX711::Rate::HZ_80;
98  } else if (this->main_config->hx_conf.rate == 10) {
99  rate = HX711::Rate::HZ_10;
100  } else {
101  rate = HX711::Rate::OTHER;
102  }
103 
104  // hx711_controller = std::make_unique<HX711::AdvancedHX711>(
105  hx711_controller = std::make_unique<custom_hx711>(
106  this->main_config->hx_conf.data_pin,
107  this->main_config->hx_conf.clock_pin,
108  this->main_config->hx_conf.ref_unit,
109  this->main_config->hx_conf.offset,
110  rate
111  );
112 
113  return 0;
114  } catch (HX711::GpioException &ex) {
115  std::string what = ex.what();
116  std::string err = "app_workspace.cpp - hx711 initialization failed. Reason: " + what;
117  spdlog::critical(err);
118 
119  return 1;
120  }
121 }
122 
124  this->hx_measuring = true;
125  this->refresh_current_screen = true;
126 
127  this->s6_calibration_finished = false; // running tare means there is not calibration
128 
129  // using calib_thread because tare can't be run at the same time as calibration
130  this->calib_thread.reset(new std::thread(threaded_tare));
131  this->calib_thread->detach(); // not waiting for the thread to finish, but ignoring other events anyway
132 }
133 
135  this->hx_measuring = true;
136  this->refresh_current_screen = true;
137 
138  // this->s6_tare_complete = false; // when calibration is run, tare is reset (cant know if weight is stil zeroed)
139 
140  this->calib_thread.reset(new std::thread(threaded_calibration));
141  this->calib_thread->detach(); // not waiting for the thread to finish, but ignoring other events anyway
142 }
143 
145  if (this->hx711_controller.get() == nullptr) {
147  get_localized_text("ERR_HX_NOT_INIT_DESC"));
148  return 5;
149  }
150 
151  if (!this->user_logged || this->userspace.get() == nullptr || !this->userspace->has_user()) {
152  set_err_screen_and_activate(get_localized_text("ERR_NO_USER_LOGIN"),
153  get_localized_text("ERR_NO_USER_LOGIN_DESC"));
154  return 1; // can't measure if no user is logged in
155  }
156 
157  if (this->selected_hx_measure_opt == 0) {
158  if (this->samples_in < S2_MIN_SAMPLES_IN || this->samples_in > S2_MAX_SAMPLES_IN) {
160  get_localized_text("ERR_S2_SAMPLES_IN_ERR"));
161  spdlog::error("app_workspace.cpp - samples_in: {0}", this->samples_in);
162  this->clear_s2_buffers();
163  return 2;
164  }
165  } else if (this->selected_hx_measure_opt == 1) {
166  if (this->timeout_in < S2_MIN_TIMEOUT_IN || this->timeout_in > S2_MAX_TIMEOUT_IN) {
168  get_localized_text("ERR_S2_TIMEOUT_IN_ERR"));
169  spdlog::error("app_workspace.cpp - timeout_in: {0}", this->timeout_in);
170  this->clear_s2_buffers();
171  return 2;
172  }
173  } else {
175  get_localized_text("ERR_S2_UNKNOWN_DESC"));
176  return 3;
177  }
178 
179  // reset this flag, if the measurement is stopped in the moment its finishing,
180  // this will stay set to true and cause the new measurement not to save
181  this->hx_not_finished_yet = false;
182  this->hx_continuous = false;
183 
184  this->hx_measuring = true;
185  this->refresh_current_screen = true;
186 
187  this->measuring_thread.reset(new std::thread(threaded_values_read));
188  this->measuring_thread->detach(); // not waiting for the thread to finish, but ignoring other events anyway
189 
190  return 0;
191 }
192 
194  if (this->hx711_controller.get() == nullptr) {
196  get_localized_text("ERR_HX_NOT_INIT_DESC"));
197  return 1;
198  }
199 
200  if (!this->user_logged || this->userspace.get() == nullptr || !this->userspace->has_user()) {
201  set_err_screen_and_activate(get_localized_text("ERR_NO_USER_LOGIN"),
202  get_localized_text("ERR_NO_USER_LOGIN_DESC"));
203  return 2; // can't measure if no user is logged in
204  }
205 
206  // reset this flag, if the measurement is stopped in the moment its finishing,
207  // this will stay set to true and cause the new measurement not to save
208  this->hx_not_finished_yet = false;
209  this->hx_measuring = true;
210  this->hx_continuous = true;
211  this->refresh_current_screen = true;
212 
213  this->measuring_thread.reset(new std::thread(threaded_values_read_looped));
214  this->measuring_thread->detach(); // not waiting for the thread to finish, but ignoring other events anyway
215 
216  return 0;
217 }
218 
219 std::vector<HX711::Value> app_workspace::hx711_values_samples(int samples) {
220  if (!this->hx_continuous)
221  spdlog::info("app_workspace.cpp - Starting HX711 measuring for {0} samples.", samples);
222  std::mutex mtx;
223 
224  bool measuring = true;
225  std::vector<HX711::Value> *watcher = nullptr;
226 
227  this->measuring_watchdog.reset(new std::thread(threaded_measuring_watchdog, &measuring, &watcher));
228  // this->measuring_watchdog->detach(); // join after measuring would be preferrable, but that is potential deadlock
229 
230  spdlog::debug("STARTING measuring");
231 
232  mtx.lock();
233  m_start = std::chrono::high_resolution_clock::now();
234  mtx.unlock();
235  //FIXME this might throw exception if it fails
236  std::vector<HX711::Value> res = hx711_controller->getValues(samples, &watcher);
237  mtx.lock();
238  m_end = std::chrono::high_resolution_clock::now();
239  mtx.unlock();
240 
241  mtx.lock();
242  measuring = false; // needed to stop watchdog thread!!
243  mtx.unlock();
244 
245  this->measuring_watchdog->join();
246 
247  spdlog::debug("ENDING measuring");
248 
249  return res;
250 }
251 
252 std::vector<HX711::Value> app_workspace::hx711_values_timeout(int seconds) {
253  spdlog::info("app_workspace.cpp - Starting HX711 measuring for {0} seconds.", seconds);
254  std::mutex mtx;
255 
256  bool measuring = true;
257  std::vector<HX711::Value> *watcher = nullptr;
258 
259  this->measuring_watchdog.reset(new std::thread(threaded_measuring_watchdog, &measuring, &watcher));
260  // this->measuring_watchdog->detach(); // join after measuring would be preferrable, but that is potential deadlock
261 
262  spdlog::debug("STARTING measuring");
263 
264  mtx.lock();
265  m_start = std::chrono::high_resolution_clock::now();
266  mtx.unlock();
267  //FIXME this might throw exception if it fails (same as above)
268  std::vector<HX711::Value> res = hx711_controller->getValues(std::chrono::seconds(seconds), &watcher);
269  mtx.lock();
270  m_end = std::chrono::high_resolution_clock::now();
271  mtx.unlock();
272 
273  mtx.lock();
274  measuring = false; // needed to stop watchdog thread!!
275  mtx.unlock();
276 
277  this->measuring_watchdog->join();
278 
279  spdlog::debug("ENDING measuring");
280 
281  // spdlog::info("app_workspace.cpp - HX711 finished taking raw values.");
282 
283  return res;
284 }
285 
287  return this->scr_mgr;
288  //return nullptr;
289 }
290 
299  this->scr_mgr = scr_mgr;
300 }
301 
302 void app_workspace::set_err_screen_and_activate(const char* title, const char* label) {
303  extern gui_label *err_title;
304  extern gui_label *err_desc;
305  err_title->set_label(title);
306  err_desc->set_label(label);
307  this->scr_mgr->set_selected_screen(0);
308 }
309 
311  ImGui::PushFont(this->loaded_fonts.at(font_size));
312  this->font_push_cnt++;
313  cur_font_size = font_size;
314 }
315 
317  return this->cur_font_size;
318 }
319 
321  spdlog::info("app_workspace.cpp - Loading font with size {0}", size_px);
322 
323  ImGuiIO &io = ImGui::GetIO();
324  std::string font_path = this->main_config->fonts_path + this->main_config->font;
325  ImFont* font = io.Fonts->AddFontFromFileTTF(font_path.c_str(), size_px);
326 
327  if (font == NULL) {
328  // FIXME - maybe critical
329  spdlog::error("app_workspace.cpp - Failed to load font size {0}!" , size_px);
330  return 1;
331  }
332 
333  this->loaded_fonts.emplace(key, font);
334 
335  return 0;
336 }
337 
339  user_cont *usr = (user_cont*) calloc(1, sizeof(user_cont));
340  int rv;
341 
342  spdlog::info("app_workspace.cpp - Loging in user through RFID. Querrying DB...");
343 
344  rv = db_conn->query_user_data(usr, nullptr, tag->serial, tag->serial_size);
345  if (rv) {
346  spdlog::error("app_workspace.cpp - Failed to login user. db_driver log should provide more information.");
347  free(usr);
348  return 1;
349  }
350 
351  rv = db_conn->query_measurement_headers(usr);
352  if (rv) {
353  spdlog::error("app_workspace.cpp - Failed to retrieve user measurement headers.");
354  // free(usr);
355  // return 1;
356  }
357 
358  if (loading_sub) {
359  if (userspace.get() == nullptr || !userspace->has_user()) {
360  spdlog::error("app_workspace.cpp - Cannot login \"subuser\", because user workspace isn't initialized."
361  " User isn't logged in? flag: user_logged: {0}", user_logged);
362  free(usr);
363  return 1;
364  }
365 
366  if (userspace->get_user_id() == usr->id) {
367  this->set_err_screen_and_activate(get_localized_text("ERR_SUBUSER_LOGIN"),
368  get_localized_text("ERR_SUBUSER_SAME_USER"));
369  free(usr);
370  return 1;
371  }
372 
373  this->userspace->subuser.reset(usr);
374  this->scr_mgr->refresh_all_screns();
375  spdlog::info("app_workspace.cpp - Finished logging in subuser through RFID.");
376 
377  return 0;
378  }
379 
380  // loading_sub is false
381  userspace.reset(new user_workspace(usr));
382  user_logged = true;
383  scr_mgr->refresh_all_screns();
384 
385  spdlog::info("app_workspace.cpp - Finished logging in user through RFID.");
386 
387  return 0;
388 }
389 
391  int rv;
392  user_cred credentials;
393 
394  rv = db_conn->query_user_credentials(&credentials, usr_name);
395  if (rv == 2) {
396  this->set_err_screen_and_activate(get_localized_text("ERR_USER_CRED"),
397  get_localized_text("ERR_USER_NOT_FOUND_DESC"));
398  return 1;
399  }
400 
401  if (rv) {
402  this->set_err_screen_and_activate(get_localized_text("ERR_USER_CRED"),
403  get_localized_text("ERR_USER_CRED_GENERAL_DESC"));
404  return 1;
405  }
406 
407  if (strcmp(credentials.passwd, usr_passwd)) {
408  // FIXME - "credentials are wrong" - maybe do "wrong password" (but thats weaker security)
409  this->set_err_screen_and_activate(get_localized_text("ERR_USER_CRED"),
410  get_localized_text("ERR_USER_CRED_WRONG_DESC"));
411  return 1;
412  }
413 
414  return 0;
415 }
416 
417 //int app_workspace::log_in_user_cred() {
419  if (strlen(usr_name) <= 0 || strlen(usr_passwd) <= 0) {
420  this->set_err_screen_and_activate(get_localized_text("ERR_USER_LOGIN"),
421  get_localized_text("ERR_USER_CREDS_NOT_ENTERED"));
422  return;
423  }
424 
425  if (verify_user_cred()) {
426  spdlog::error("app_workspace.cpp - User login. Failed to verify credentials");
427  return;
428  }
429 
430  int rv;
431  user_cont *usr = (user_cont*) calloc(1, sizeof(user_cont));
432 
433  rv = db_conn->query_user_data(usr, usr_name);
434  if (rv) {
435  // this hould be unreachable, because user was already checked for credentials -> user exists, sql can fail
436  spdlog::error("app_workspace.cpp - Failed to login user. db_driver log should provide more information.");
437  //return 1;
438  return;
439  }
440 
441  rv = db_conn->query_measurement_headers(usr);
442  if (rv) {
443  spdlog::error("app_workspace.cpp - Failed to retrieve user measurement headers.");
444  // return;
445  }
446 
447  // loading_sub is false
448  userspace.reset(new user_workspace(usr));
449  user_logged = true;
450  clear_s1_buffers();
451  scr_mgr->refresh_all_screns();
452 
453  //return 0;
454 }
455 
457  // not checking has_user(), because this action is currently only available from user logged in screen
458 
459  if (strlen(subusr_name) <= 0) {
460  this->set_err_screen_and_activate(get_localized_text("ERR_SUBUSER_LOGIN"),
461  get_localized_text("ERR_SUBUSER_INPUT_EMPTY"));
462  return;
463  }
464 
465  int rv = db_conn->can_login_subuser(subusr_name);
466  if (rv == 2) {
467  this->set_err_screen_and_activate(get_localized_text("ERR_SUBUSER_LOGIN"),
468  get_localized_text("ERR_SUBUSER_NOT_FOUND"));
469  return;
470  } else if (rv == 3) {
471  this->set_err_screen_and_activate(get_localized_text("ERR_SUBUSER_LOGIN"),
472  get_localized_text("ERR_SUBUSER_ROLE_TOO_HIGH"));
473  return;
474  }
475  if (rv) {
476  this->set_err_screen_and_activate(get_localized_text("ERR_SUBUSER_LOGIN"),
477  get_localized_text("ERR_SUBUSER_FAILED_TO_FETCH"));
478  return;
479  }
480 
481  user_cont *usr = (user_cont*) calloc(1, sizeof(user_cont));
482 
483  rv = db_conn->query_user_data(usr, subusr_name);
484  if (rv) {
485  spdlog::error("app_workspace.cpp - Failed to login user. db_driver log should provide more information.");
486  return;
487  }
488 
489  rv = db_conn->query_measurement_headers(usr);
490  if (rv) {
491  spdlog::error("app_workspace.cpp - Failed to retrieve user measurement headers.");
492  return;
493  }
494 
495  if (userspace->get_user_id() == usr->id) {
496  this->set_err_screen_and_activate(get_localized_text("ERR_SUBUSER_LOGIN"),
497  get_localized_text("ERR_SUBUSER_SAME_USER"));
498  free(usr);
499  return;
500  }
501 
502  this->userspace->subuser.reset(usr);
503  this->scr_mgr->refresh_all_screns();
504 }
505 
507  clear_s1_buffers();
508  this->userspace->subuser.release();
509  this->userspace->measured.release();
510  this->userspace->picked.release();
511  this->scr_mgr->refresh_all_screns();
512 }
513 
515  this->logout_subuser();
516  // clear_s1_buffers(); // these should be cleared after login, but just to be sure
517  userspace.release();
518  user_logged = false;
519  scr_mgr->refresh_all_screns();
520  scr_mgr->clear_previous_screen_stack();
521 }
522 
524  if (strlen(this->s6_uname_in) <= 0 ||
525  strlen(this->s6_passwd_in) <= 0 ||
526  strlen(this->s6_name_in) <= 0 ||
527  strlen(this->s6_lastname_in) <= 0 ||
528  this->s6_year_in <= 0 ||
529  this->s6_day_in <= 0)
530  {
531  this->set_err_screen_and_activate(get_localized_text("ERR_S6_USR_ADD_INPUT_ERR"),
532  get_localized_text("ERR_S6_USR_ADD_INPUT_DESC"));
533  return 1;
534  }
535 
536  user_cont *usr_tmp = (user_cont*) calloc(1, sizeof(user_cont));
537  std::unique_ptr<user_cont> usr(usr_tmp);
538 
539  int rv = this->db_conn->is_username_available(this->s6_uname_in);
540  if (rv == 3) {
541  this->set_err_screen_and_activate(get_localized_text("ERR_S6_USR_ADD"),
542  get_localized_text("ERR_S6_USR_NAME_TAKEN"));
543  return 1;
544  } else if (rv) {
545  spdlog::error("screen_definitions.cpp - Failed to verify username availability");
546  this->set_err_screen_and_activate(get_localized_text("ERR_DB_ERROR"),
547  get_localized_text("ERR_DB_UNAME_CHECK_FAIL"));
548  return 1;
549  } else {
550  spdlog::debug("screen_definitions.cpp - Username is available.");
551  }
552 
553  if (this->s6_rfid_indicator) {
554  rv = this->db_conn->is_rfid_serial_available(this->s6_rfid_tag->serial, this->s6_rfid_tag->serial_size);
555 
556  if (rv == 3) {
557  this->set_err_screen_and_activate(get_localized_text("ERR_S6_USR_ADD"),
558  get_localized_text("ERR_S6_USR_RFID_TAKEN"));
559  return 1;
560  } else if (rv) {
561  spdlog::error("screen_definitions.cpp - Failed to verify username availability");
562  this->set_err_screen_and_activate(get_localized_text("ERR_DB_ERROR"),
563  get_localized_text("ERR_DB_RFID_CHECK_FAIL"));
564  return 1;
565  } else {
566  spdlog::debug("screen_definitions.cpp - RFID is available.");
567  memcpy(usr->rfid_serial_bin, this->s6_rfid_tag->serial, this->s6_rfid_tag->serial_size);
568  usr->rfid_ser_len = this->s6_rfid_tag->serial_size;
569  }
570  }
571 
572  std::time_t ct_tmp = std::time(nullptr);
573  std::tm *current_time = std::localtime(&ct_tmp);
574 
575  // tm_year is "current_year - 1900"
576  if (this->s6_year_in > (current_time->tm_year + 1900) || this->s6_year_in < YEAR_MIN) {
577  // spdlog::error("screen_definitions.cpp - Year out of range {0} (current_year: {1})",
578  // this->s6_year_in, (current_time->tm_year + 1900));
580  get_localized_text("ERR_DOB_YEAR_OOR"));
581  return 1;
582  }
583  if (this->s6_day_in > DAY_MAX || this->s6_day_in < DAY_MIN) {
584  spdlog::error("screen_definitions.cpp - Year out of range");
586  get_localized_text("ERR_DOB_DAY_OOR"));
587  return 1;
588  }
589 
590  char buf[64];
591  sprintf(buf, "%04d-%02d-%02d", this->s6_year_in, this->s6_selected_month + 1, this->s6_day_in);
592 
593  std::tm dob;
594  memset(&dob, 0, sizeof(std::tm));
595  strptime(buf, "%Y-%m-%d", &dob);
596 
597  usr->role = this->s6_selected_role;
598  usr->username = this->s6_uname_in;
599  usr->name = this->s6_name_in;
600  usr->lastname = this->s6_lastname_in;
601  if (strlen(this->s6_desc_in) > 0) {
602  usr->description = this->s6_desc_in;
603  }
604  usr->date_of_birth = dob;
605 
606  rv = this->db_conn->insert_user(usr.get(), this->s6_passwd_in);
607  if (rv) {
608  spdlog::error("screen_definitions.cpp - Failed to execute user insert.");
609  this->set_err_screen_and_activate(get_localized_text("ERR_DB_ERROR"),
610  get_localized_text("ERR_DB_INSERT_USER_FAIL"));
611  return 1;
612  } else {
613  this->clear_s6_buffers();
614  spdlog::info("screen_definitions.cpp - Successfully added new user.");
615  this->scr_mgr->set_selected_screen(5);
616  }
617 
618  return 0;
619 }
620 
622  return main_config->debug_screens;
623 }
624 
625 
627  return this->user_logged && this->userspace.get() != nullptr && this->userspace->has_user();
628 }
629 
631  if (has_user())
632  return this->userspace.get();
633  else
634  return nullptr;
635 }
636 
638  db_conn.reset(new db_driver(&(main_config->db_conf)));
639  return db_conn->is_open() ? 0 : 1;
640 }
641 
642 void app_workspace::clear_s1_buffers() {
643  memset(usr_name, 0, DEF_BUFF_SIZE);
644  memset(subusr_name, 0, DEF_BUFF_SIZE);
645  memset(usr_passwd, 0, DEF_BUFF_SIZE_SMALL);
646 }
647 
648 void app_workspace::clear_s2_buffers() {
651 }
652 
653 void app_workspace::clear_s6_buffers() {
654  this->s6_ref_mass_in = 0;
656  this->s6_selected_unit_option = 0;
657  this->s6_day_in = DAY_MIN;
658  this->s6_year_in = YEAR_MIN;
659  this->s6_calibration_finished = false;
660  this->s6_tare_complete = false;
661  this->s6_rfid_indicator = false;
662  this->s6_rfid_tag.release();
663  this->s6_selected_role = 0;
664  this->s6_selected_month = 0;
665  memset(this->s6_lastname_in, 0, DEF_BUFF_SIZE_SMALL);
666  memset(this->s6_uname_in, 0, DEF_BUFF_SIZE_SMALL);
667  memset(this->s6_name_in, 0, DEF_BUFF_SIZE);
668  memset(this->s6_passwd_in, 0, DEF_BUFF_SIZE);
669  memset(this->s6_desc_in, 0, DEF_BUFF_SIZE_EXTRA);
670 
671 }
672 
673 std::vector<double> app_workspace::normalize_raw_values(std::vector<HX711::Value>& raw_vals) {
674  std::vector<double> res;
675 
676  for (size_t i = 0; i < raw_vals.size(); i++) {
677  res.push_back(this->hx711_controller->normalise(raw_vals[i]));
678  }
679 
680  return res;
681 }
682 
683 /*********************************************************************************************************************/
684 /* Debug/ test fuctinos */
685 /*********************************************************************************************************************/
686 
687 
689  spdlog::debug("========== (debug) config file start ==========");
690  spdlog::debug("general settings:");
691  spdlog::debug("\tdebug_screens: {0}", main_config->debug_screens);
692  spdlog::debug("\tfonts_path: {0}", main_config->fonts_path);
693  spdlog::debug("\tfont: {0}", main_config->font);
694  spdlog::debug("\tlang_path: {0}", main_config->lang_path);
695  spdlog::debug("\tavailable_langs:");
696  for (size_t i = 0; i < main_config->lang_options.size(); i++) {
697  spdlog::debug("\t\topt {0}: {1}", i, main_config->lang_options[i]);
698  }
699  //spdlog::debug("\tavailable_langs: {0}", main_config->lang_options);
700  spdlog::debug("\tdefault_lang: {0}", main_config->lang_default);
701  spdlog::debug("\tcurrent_lang: {0}", main_config->lang_current);
702  spdlog::debug("spi keyboard settings:");
703  spdlog::debug("\tdev: {0}", main_config->keyb_conf.dev);
704  spdlog::debug("\tmode: {0}", main_config->keyb_conf.config->mode);
705  spdlog::debug("\tbits: {0}", main_config->keyb_conf.config->bits_per_word);
706  spdlog::debug("\tspeed: {0}", main_config->keyb_conf.config->speed);
707  spdlog::debug("\tdelay: {0}", main_config->keyb_conf.config->delay);
708  spdlog::debug("spi rfid settings:");
709  spdlog::debug("\tdev: {0}", main_config->rfid_conf.dev);
710  spdlog::debug("\tmode: {0}", main_config->rfid_conf.config->mode);
711  spdlog::debug("\tbits: {0}", main_config->rfid_conf.config->bits_per_word);
712  spdlog::debug("\tspeed: {0}", main_config->rfid_conf.config->speed);
713  spdlog::debug("\tdelay: {0}", main_config->rfid_conf.config->delay);
714  spdlog::debug("database settings:");
715  spdlog::debug("\thost: {0}", main_config->db_conf.host);
716  spdlog::debug("\tuser: {0}", main_config->db_conf.user);
717  spdlog::debug("\tpassword: {0}", main_config->db_conf.passwd);
718  spdlog::debug("\tdatabase: {0}", main_config->db_conf.db);
719  spdlog::debug("\tport: {0}", main_config->db_conf.port);
720  spdlog::debug("\tsocket: {0}", main_config->db_conf.socket);
721  spdlog::debug("\tclientflags: {0}", main_config->db_conf.clientflags);
722  spdlog::debug("hx711 settings:");
723  spdlog::debug("\tdata pin: {0}", main_config->hx_conf.data_pin);
724  spdlog::debug("\tclock pin: {0}", main_config->hx_conf.clock_pin);
725  spdlog::debug("\trate: {0}", main_config->hx_conf.rate);
726  spdlog::debug("\tref unit: {0}", main_config->hx_conf.ref_unit);
727  spdlog::debug("\toffset: {0}", main_config->hx_conf.offset);
728  spdlog::debug("========== (debug) config file end ==========");
729 }
730 
732  if (this->hx711_controller.get() == nullptr) {
734  get_localized_text("ERR_HX_NOT_INIT_DESC"));
735  return 5;
736  }
737 
738  if (!this->has_user()) {
739  set_err_screen_and_activate(get_localized_text("ERR_NO_USER_LOGIN"),
740  get_localized_text("ERR_NO_USER_LOGIN_DESC"));
741  return 1; // can't measure if no user is logged in, this shouldn't be reachable
742  }
743 
744  this->hx_measuring = true;
745  this->test_hx_testing = true;
747 
748  this->measuring_thread.reset(new std::thread([]() {
749  std::mutex mtx;
750  mtx.lock();
751  app_workspace *app_wrk = app_workspace::get_instance().get();
752 
753  // constant iterations
754  for (int i = 0; i < HX_TEST_CONST_IT_COUNT; i++) {
756  auto res = std::chrono::duration_cast<std::chrono::milliseconds>(app_wrk->m_end - app_wrk->m_start).count();
757  app_wrk->test_hx_samples_times[i].first = res;
758  app_wrk->test_hx_samples_times[i].second =
759  "Smps: " + std::to_string(HX_TEST_SAMP_COUNT) + " - " + std::to_string(res) + " ms";
760  }
761 
762  // increasing iterations
763  for (int i = 0; i < HX_TEST_INC_IT_COUNT; i++) {
764  app_wrk->hx711_values_samples(HX_TEST_SAMP_COUNT * (i + 1));
765  auto res = std::chrono::duration_cast<std::chrono::milliseconds>(app_wrk->m_end - app_wrk->m_start).count();
766  app_wrk->test_hx_samples_times[i + HX_TEST_CONST_IT_COUNT].first = res;
767  app_wrk->test_hx_samples_times[i + HX_TEST_CONST_IT_COUNT].second =
768  "Smps: " + std::to_string(HX_TEST_SAMP_COUNT * (i + 1)) + " - " + std::to_string(res) + " ms";
769  }
770 
771  app_wrk->hx_measuring = false;
772  app_wrk->test_hx_testing = false;
774  mtx.unlock();
775  }));
776 
777  this->measuring_thread->detach(); // not waiting for the thread to finish, but ignoring other events anyway
778 
779  return 0;
780 }
781 
783  if (this->hx711_controller.get() == nullptr) {
785  get_localized_text("ERR_HX_NOT_INIT_DESC"));
786  return 5;
787  }
788 
789  if (!this->has_user()) {
790  set_err_screen_and_activate(get_localized_text("ERR_NO_USER_LOGIN"),
791  get_localized_text("ERR_NO_USER_LOGIN_DESC"));
792  return 1; // can't measure if no user is logged in, this shouldn't be reachable
793  }
794 
795  this->hx_measuring = true;
796  this->test_hx_testing = true;
798 
799  this->measuring_thread.reset(new std::thread([]() {
800  std::mutex mtx;
801  mtx.lock();
802  app_workspace *app_wrk = app_workspace::get_instance().get();
803 
804  // constant iterations
805  for (int i = 0; i < HX_TEST_CONST_IT_COUNT; i++) {
806  auto res = app_wrk->hx711_values_timeout(HX_TEST_TIME_COUNT);
807  app_wrk->test_hx_timeout_collected[i].first = res.size();
808  app_wrk->test_hx_timeout_collected[i].second =
809  "In: " + std::to_string(HX_TEST_TIME_COUNT) + "s - " + std::to_string(res.size()) + " samples";
810  }
811 
812  // increasing iterations
813  for (int i = 0; i < HX_TEST_INC_IT_COUNT; i++) {
814  auto res = app_wrk->hx711_values_timeout(HX_TEST_TIME_COUNT * (i + 1));
815  app_wrk->test_hx_timeout_collected[i + HX_TEST_CONST_IT_COUNT].first = res.size();
816  app_wrk->test_hx_timeout_collected[i + HX_TEST_CONST_IT_COUNT].second =
817  "In: " + std::to_string(HX_TEST_TIME_COUNT * (i + 1)) + "s - " + std::to_string(res.size())+" samples";
818  }
819 
820  app_wrk->hx_measuring = false;
821  app_wrk->test_hx_testing = false;
823  mtx.unlock();
824  }));
825 
826  this->measuring_thread->detach(); // not waiting for the thread to finish, but ignoring other events anyway
827 
828  return 0;
829 }
830 
833 }
834 
837 }
838 
839 
840 /*********************************************************************************************************************/
841 /* Functions used by app_wrokspace for hx711 thread measuring */
842 /*********************************************************************************************************************/
843 
845  std::mutex mtx;
846  std::vector<HX711::Value> res;
847 
848  mtx.lock();
849  app_workspace *app_wrk = app_workspace::get_instance().get();
850 
851  if (app_wrk->selected_hx_measure_opt == 0) {
852  res = app_wrk->hx711_values_samples(app_wrk->samples_in);
853  } else if (app_wrk->selected_hx_measure_opt == 1) {
854  res = app_wrk->hx711_values_timeout(app_wrk->timeout_in);
855  }
856 
857  // thanks to this measuring isn't save when cancelled mid-way
858  /*
859  if (app_wrk->hx_not_finished_yet) {
860  app_wrk->hx_measuring = false;
861  app_wrk->hx_continuous = false;
862  app_wrk->hx_not_finished_yet = false;
863  app_wrk->refresh_current_screen = true;
864  mtx.unlock();
865  return; // could use goto end of this function
866  }
867  */
868 
869  if (res.size() <= 0) {
870  app_wrk->set_err_screen_and_activate(get_localized_text("ERR_S2_MEASURING_FAILURE"),
871  get_localized_text("ERR_S2_MEASURING_NO_VALS"));
872  return;
873  }
874 
875  unsigned long m_len =
876  std::chrono::duration_cast<std::chrono::microseconds>(app_wrk->m_end - app_wrk->m_start).count();
877  std::time_t start_timet = std::chrono::system_clock::to_time_t(app_wrk->m_start);
878  std::time_t end_timet = std::chrono::system_clock::to_time_t(app_wrk->m_end);
879  std::tm start_tm, end_tm;
880  localtime_r(&start_timet, &start_tm);
881  localtime_r(&end_timet, &end_tm);
882 
883  std::vector<double> values = app_wrk->normalize_raw_values(res);
884  app_wrk->userspace->init_measured(values, &start_tm, &end_tm, m_len); // inits userspace->measured
885  app_wrk->userspace->get_last_hx_measuring()->log_measurement_to_debug();
886 
887  // insert to db
888  int rv = app_wrk->db_conn->insert_measurement(app_wrk->userspace->measured.get());
889  if (rv) {
890  spdlog::error("app_workspace.cpp - hx711_measurement: failet to insert measurement to DB.");
891  } else {
892  rv = app_wrk->db_conn->increment_user_measurement_count(app_wrk->userspace->get_measured_id());
893  if (rv) {
894  spdlog::error("app_workspace.cpp - hx711_measurement: Successfully inserted measurement but"
895  " failed to increment user measurement_count.");
896  } else {
897  // to save reloading from db
898  app_wrk->userspace->get_measured_user()->measure_count++;
899  }
900 
901  rv = app_wrk->db_conn->query_measurement_headers(app_wrk->userspace->get_measured_user());
902  if (rv) {
903  spdlog::error("app_workspace.cpp - hx711_measurement: Failed to retrieve (update)"
904  " user measurement headers.");
905  } else {
906  app_wrk->get_scr_mgr()->refresh_screen_elements(3); // refresh measurement list
907  }
908 
909  // fetch username of measuree and measurer (last measurement preview on screen 2)
910  std::string uname;
911  rv = app_wrk->db_conn->query_username(uname, app_wrk->userspace->measured->measurer_id);
912  if (rv) {
913  spdlog::error("app_workspace.cpp - hx711_measurement: Failed to retrieve measurer username.");
914  } else {
915  if (app_wrk->userspace->measured->measurer_id != app_wrk->userspace->measured->measuree_id) {
916  std::string sub_uname;
917  rv = app_wrk->db_conn->query_username(sub_uname, app_wrk->userspace->measured->measuree_id);
918 
919  if (rv) {
920  spdlog::error("app_workspace.cpp - hx711_measurement: Failed to retrieve measuree username.");
921  } else {
922  app_wrk->userspace->measured->init_convinience_vars(uname.c_str(), sub_uname.c_str());
923  }
924  } else {
925  app_wrk->userspace->measured->init_convinience_vars(uname.c_str(), uname.c_str());
926  }
927  }
928  // else { // this branch is for debug
929  // measurement_header *h = app_wrk->userspace->get_user()->measur_headers.at(0).get();
930  // measurement *m = new measurement();
931  // rv = app_wrk->db_conn->query_measurement(m, h->id);
932  // if (rv) {
933  // spdlog::error("app_workspace.cpp - hx711_measurement: Failed to retrieve measurement that was just inserted");
934  // } else {
935  // app_wrk->userspace->measured->compare(m);
936  // }
937  // }
938  }
939 
940  // following 2 flags are reset just to be sure
941  app_wrk->hx_continuous = false;
942  app_wrk->hx_not_finished_yet = false;
943 
944  app_wrk->hx_measuring = false;
945  app_wrk->refresh_current_screen = true;
946 
947  mtx.unlock();
948 }
949 
951  std::mutex mtx;
952  std::vector<HX711::Value> res;
953 
954  mtx.lock();
955  app_workspace *app_wrk = app_workspace::get_instance().get();
956 
957  spdlog::info("app_workspace.cpp - Starting taring");
958  app_wrk->s6_tare_complete = false; // making sure tare is false
959 
960  // tare start
961  HX711::Value orig_offset = app_wrk->hx711_controller->getOffset();
962  HX711::Value orig_ref_unit = app_wrk->hx711_controller->getReferenceUnit();
963 
964  try {
965  app_wrk->hx711_controller->setReferenceUnit(1);
966  app_wrk->hx711_controller->setOffset(0);
967  } catch (std::exception &ex) {
968  spdlog::error("app_workspace.cpp - Caught exception while taring HX711");
969  app_wrk->hx_measuring = false;
970  app_wrk->refresh_current_screen = true;
971 
972  mtx.unlock();
973  return;
974  }
975 
976  size_t samples = app_wrk->s6_samples_in;
977  app_wrk->zero_value = app_wrk->hx711_controller->read(HX711::Options(samples));
978 
979  try {
980  app_wrk->hx711_controller->setReferenceUnit(orig_ref_unit);
981  app_wrk->hx711_controller->setOffset(orig_offset);
982  } catch (std::exception &ex) {
983  spdlog::error("app_workspace.cpp - Caught exception while cleaning after HX711 calibration");
984  app_wrk->hx_measuring = false;
985  app_wrk->refresh_current_screen = true;
986 
987  mtx.unlock();
988  return;
989  }
990  // tare end
991 
992  spdlog::info("app_workspace.cpp - Successfully finished calibrating");
993  app_wrk->hx_measuring = false;
994  app_wrk->s6_tare_complete = true;
995  app_wrk->refresh_current_screen = true;
996 
997  mtx.unlock();
998 }
999 
1001  std::mutex mtx;
1002  std::vector<HX711::Value> res;
1003 
1004  mtx.lock();
1005  app_workspace *app_wrk = app_workspace::get_instance().get();
1006 
1007  spdlog::info("app_workspace.cpp - Starting calibration");
1008 
1009  // calibration start
1010  HX711::Value orig_offset = app_wrk->hx711_controller->getOffset();
1011  HX711::Value orig_ref_unit = app_wrk->hx711_controller->getReferenceUnit();
1012 
1013  try {
1014  app_wrk->hx711_controller->setReferenceUnit(1);
1015  app_wrk->hx711_controller->setOffset(0);
1016  } catch (std::exception &ex) {
1017  spdlog::error("app_workspace.cpp - Caught exception while preparing for HX711 calibration");
1018  app_wrk->hx_measuring = false;
1019  app_wrk->refresh_current_screen = true;
1020 
1021  mtx.unlock();
1022  return;
1023  }
1024 
1025 
1026  double known_weight = app_wrk->s6_ref_mass_in;
1027  size_t samples = app_wrk->s6_samples_in;
1028 
1029  const double raw = app_wrk->hx711_controller->read(HX711::Options(samples));
1030  const double ref_unit_float = (raw - app_wrk->zero_value) / known_weight;
1031  app_wrk->ref_unit = static_cast<HX711::Value>(round(ref_unit_float));
1032 
1033  if (app_wrk->ref_unit == 0)
1034  app_wrk->ref_unit = 1;
1035 
1036  // FIXME remove s6_calib... those are useless, same data stored twice (but s6_calib.. is used in gui)
1037  // offset
1038  app_wrk->s6_calib_offset = app_wrk->zero_value;
1039 
1040  // ref_unit
1041  app_wrk->s6_calib_ref_unit = app_wrk->ref_unit;
1042 
1043  try {
1044  app_wrk->hx711_controller->setReferenceUnit(orig_ref_unit);
1045  app_wrk->hx711_controller->setOffset(orig_offset);
1046  } catch (std::exception &ex) {
1047  spdlog::error("app_workspace.cpp - Caught exception while cleaning after HX711 calibration");
1048  app_wrk->hx_measuring = false;
1049  app_wrk->refresh_current_screen = true;
1050 
1051  mtx.unlock();
1052  return;
1053  }
1054 
1055  // calibration end
1056 
1057  spdlog::info("app_workspace.cpp - Successfully finished calibrating");
1058  app_wrk->s6_calibration_finished = true;
1059  app_wrk->s6_tare_complete = false;
1060  app_wrk->hx_measuring = false;
1061  app_wrk->refresh_current_screen = true;
1062 
1063  mtx.unlock();
1064 }
1065 
1067  std::mutex mtx;
1068  long failed_measures = 0, failed_inserts = 0; // in case measuring or insert fails, the number of fails will be logged
1069  unsigned long measure_count = 1;
1070  int consec_fm = 0, consec_fi = 0; // consecutive fail counter, after reaching several consecutive fails, end measuring
1071  int rv;
1072  std::vector<HX711::Value> res;
1073  std::unique_ptr<measurement> measr; // using own measurement instead of userspace->measured
1074 
1075  mtx.lock();
1076  app_workspace *app_wrk = app_workspace::get_instance().get();
1077  mtx.unlock();
1078 
1079  while (1) {
1080  mtx.lock();
1081  if (!app_wrk->hx_continuous || app_wrk->hx_not_finished_yet) break;
1082  mtx.unlock();
1083 
1084  // prepare next measuring iteration
1085  if (consec_fi > HX_CONT_MAX_CONSEC_FAIL_FI || consec_fm > HX_CONT_MAX_CONSEC_FAIL_FM) {
1086  spdlog::error("app_workspace.cpp - countinous measuring failed. Reason is because of consecutive"
1087  "measuring or insert failures. Failed measures: {0} (limit: {1}), failed inserts: {2} (limit: {3})",
1089  break;
1090  }
1091  measr.reset(new measurement());
1092 
1093  // read hx711 and get results
1094  std::vector<HX711::Value> res = app_wrk->hx711_values_samples(HX_CONT_SAMPLES);
1095 
1096  // was using this to avoid locking the whole thread while measuring, but moved this to hx711_values_samples()
1097  // mtx.lock();
1098  // app_wrk->m_start = std::chrono::high_resolution_clock::now();
1099  // mtx.unlock();
1100  // std::vector<HX711::Value> res = app_wrk->hx711_controller->getValues(HX_CONT_SAMPLES);
1101  // mtx.lock();
1102  // app_wrk->m_end = std::chrono::high_resolution_clock::now();
1103  // mtx.unlock();
1104 
1105  // stop measuring on request (hx_not_finished_yet), but don't break if there is data to write
1106  if (app_wrk->hx_not_finished_yet && res.size() <= 0) break;
1107 
1108  // check if results were measured (maybe can do size() != CONTINOUS_M_SAMPLES)
1109  if (res.size() <= 0) {
1110  failed_measures++;
1111  consec_fm++;
1112  continue; // failed measuring, try again
1113  }
1114  consec_fm = 0; // probably more effective than else consec_fm = 0; ?
1115 
1116  mtx.lock();
1117  unsigned long m_len =
1118  std::chrono::duration_cast<std::chrono::microseconds>(app_wrk->m_end - app_wrk->m_start).count();
1119  std::time_t start_timet = std::chrono::system_clock::to_time_t(app_wrk->m_start);
1120  std::time_t end_timet = std::chrono::system_clock::to_time_t(app_wrk->m_end);
1121  std::tm start_tm, end_tm;
1122  localtime_r(&start_timet, &start_tm);
1123  localtime_r(&end_timet, &end_tm);
1124 
1125  std::vector<double> values = app_wrk->normalize_raw_values(res);
1126  measurement::init_measuring(measr.get(), app_wrk->get_userspace(), values, &start_tm, &end_tm, m_len);
1127 
1128  measr->measurement_part = measure_count;
1129  measure_count++;
1130 
1131  // db insert
1132  auto i_start = std::chrono::steady_clock::now();
1133  rv = app_wrk->db_conn->insert_measurement(measr.get());
1134  auto i_end = std::chrono::steady_clock::now();
1135  spdlog::debug("app_workspace.cpp - hx711_continuous_measurement: inserting measurement to DB"
1136  " took {0}ms ({1} us)", std::chrono::duration_cast<std::chrono::milliseconds>(i_end - i_start).count(),
1137  std::chrono::duration_cast<std::chrono::microseconds>(i_end - i_start).count());
1138  if (rv) {
1139  spdlog::error("app_workspace.cpp - hx711_continuous_measurement: failed to insert measurement to DB.");
1140  failed_inserts++;
1141  consec_fi++;
1142  }
1143  else consec_fi = 0; // not using continue, need else
1144 
1145  mtx.unlock();
1146  }
1147 
1148  // update measurement_number and screen 3 header list
1149  if ((measure_count - failed_inserts) > 1) { // atleast one result was measured and inserted
1150  rv = app_wrk->db_conn->increment_user_measurement_count(app_wrk->userspace->get_measured_id());
1151  if (rv) {
1152  spdlog::error("app_workspace.cpp - hx711_measurement: Successfully inserted measurement but"
1153  " FAILED to increment user measurement_count.");
1154  } else {
1155  // to save reloading from db
1156  app_wrk->userspace->get_measured_user()->measure_count++;
1157  }
1158 
1159  rv = app_wrk->db_conn->query_measurement_headers(app_wrk->userspace->get_measured_user());
1160  if (rv) {
1161  spdlog::error("app_workspace.cpp - hx711_measurement: Failed to retrieve (update)"
1162  " user measurement headers.");
1163  } else {
1164  app_wrk->get_scr_mgr()->refresh_screen_elements(3); // refresh measurement list
1165  }
1166 
1167  // fetch username of measuree and measurer (convenience vars)
1168  // last measuring result (last part of continuous measuring)
1169  app_wrk->userspace->measured = std::unique_ptr(std::move(measr));
1170 
1171  std::string uname;
1172  rv = app_wrk->db_conn->query_username(uname, app_wrk->userspace->measured->measurer_id);
1173  if (rv) {
1174  spdlog::error("app_workspace.cpp - hx711_measurement: Failed to retrieve measurer username.");
1175  } else {
1176  if (app_wrk->userspace->measured->measurer_id != app_wrk->userspace->measured->measuree_id) {
1177  std::string sub_uname;
1178  rv = app_wrk->db_conn->query_username(sub_uname, app_wrk->userspace->measured->measuree_id);
1179 
1180  if (rv) {
1181  spdlog::error("app_workspace.cpp - hx711_measurement: Failed to retrieve measuree username.");
1182  } else {
1183  app_wrk->userspace->measured->init_convinience_vars(uname.c_str(), sub_uname.c_str());
1184  }
1185  } else {
1186  app_wrk->userspace->measured->init_convinience_vars(uname.c_str(), uname.c_str());
1187  }
1188  }
1189 
1190  }
1191 
1192  // mtx.lock();
1193  app_wrk->hx_measuring = false;
1194  app_wrk->hx_continuous = false;
1195  app_wrk->hx_not_finished_yet = false;
1196  app_wrk->refresh_current_screen = true;
1197  mtx.unlock();
1198 }
1199 
1200 void threaded_measuring_watchdog(bool *msring, std::vector<HX711::Value> **watcher) {
1201  std::mutex mtx;
1202  int fail_cnt = 0;
1203 
1204  mtx.lock();
1205  app_workspace *app_wrk = app_workspace::get_instance().get();
1206  mtx.unlock();
1207 
1208  size_t val_len = 0;
1209  spdlog::debug("STARTING measuring watchdog");
1210 
1211  while (1) {
1212  mtx.lock();
1213  if (!(*msring)) break;
1214 
1215  if (*watcher != nullptr && ((*watcher)->size() - val_len) > 50) { // every X samples do something
1216  /*
1217  auto tmp_start = (*watcher)->begin() + val_len; // iterator start (not doing -1, because not including last)
1218  auto tmp_end = (*watcher)->end(); // iterator end
1219  std::vector<HX711::Value> tmp(tmp_start, tmp_end);
1220  */
1221 
1222  if (val_len < (*watcher)->size()) {
1223  std::vector<HX711::Value> tmp;
1224  for (size_t i = val_len; i < (*watcher)->size(); i++) {
1225  tmp.push_back((*watcher)->at(i));
1226  }
1227  val_len = (*watcher)->size();
1228 
1229  auto norm_values = app_wrk->normalize_raw_values(tmp);
1230  app_wrk->observed_measurement.reset(new measurement);
1231  measurement::init_simple_measuring(app_wrk->observed_measurement.get(), norm_values);
1232  app_wrk->refresh_current_screen = true;
1233  } else
1234  fail_cnt++;
1235 
1236  if (fail_cnt == 20) { // 20 * 50 takes 1 second to finish - maybe make it quicker (< 20)
1237  printf("breaking on fail_cnt\n");
1238  *msring = false;
1239  break; // after 20 "not update" break
1240  }
1241  }
1242  mtx.unlock();
1243 
1244  std::this_thread::sleep_for(std::chrono::milliseconds(50));
1245  }
1246 
1247  spdlog::debug("ENDING measuring watchdog");
1248 }
void threaded_values_read()
This function is started in a new thread for reading HX711 values.
void threaded_values_read_looped()
This function is started in a new thread for reading HX711 values in a loop. This reading is done in ...
void threaded_tare()
This function is started in a new thread for taring HX711.
void threaded_measuring_watchdog(bool *msring, std::vector< HX711::Value > **watcher)
When an HX711 reading is started, when creating new thread, this thread is created as well....
void threaded_calibration()
This function is started in a new thread for calibrating HX711.
#define S2_MAX_SAMPLES_IN
Definition: app_workspace.h:30
#define DEF_BUFF_SIZE
Definition: app_workspace.h:23
#define DAY_MIN
Definition: app_workspace.h:44
#define DEF_BUFF_SIZE_EXTRA
Definition: app_workspace.h:27
#define YEAR_MIN
Definition: app_workspace.h:46
#define DEF_BUFF_SIZE_SMALL
Definition: app_workspace.h:22
#define S2_MIN_TIMEOUT_IN
Definition: app_workspace.h:31
#define S2_MIN_SAMPLES_IN
Definition: app_workspace.h:29
#define HX_TEST_TIME_COUNT
Definition: app_workspace.h:55
#define S6_MIN_SAMPLES_IN
Definition: app_workspace.h:34
#define HX_TEST_CONST_IT_COUNT
Definition: app_workspace.h:52
#define HX_TEST_INC_IT_COUNT
Definition: app_workspace.h:53
#define HX_CONT_SAMPLES
Definition: app_workspace.h:50
#define HX_CONT_MAX_CONSEC_FAIL_FI
Definition: app_workspace.h:48
#define HX_CONT_MAX_CONSEC_FAIL_FM
Definition: app_workspace.h:49
#define S2_MAX_TIMEOUT_IN
Definition: app_workspace.h:32
#define DAY_MAX
Definition: app_workspace.h:45
#define HX_TEST_SAMP_COUNT
Definition: app_workspace.h:54
One of the most importat classes in the whole project. Holds variables that define the state of the a...
int hx711_measure()
Performs hx711 measuring with set values of either samples or timeout. The results is saved to the da...
std::chrono::time_point< std::chrono::high_resolution_clock > m_start
std::vector< HX711::Value > hx711_values_samples(int samples)
Reads the HX711 sensor until @samples is collected. Also starts new thread which is used to monitor o...
std::unique_ptr< custom_hx711 > hx711_controller
HX711 controller. This is an instance of custom_hx711 which extends library's AdvancedHX711.
void logoff_user()
Logs out user and subuser if logged in.
static std::unique_ptr< app_workspace > & get_instance()
Get the instance app_workspace which is a singleton.
HX711::Value zero_value
bool s6_calibration_finished
user_workspace * get_userspace()
void use_font_size(app_workspace_ns::font_size font_size)
When this is called following gui elements will use selected font_size until next call of this or fon...
std::chrono::time_point< std::chrono::high_resolution_clock > m_end
void set_err_screen_and_activate(const char *title, const char *label)
Set the err screen and activate the screen on next frame.
bool s6_rfid_indicator
void init_labels()
This is called after localisation dictionary is loaded. After the dict is loaded arrays defined in ap...
void hx711_tare()
Function that performs taring on the hx711 controller.
const char * s6_month_labels[S6_MONTH_CNT]
std::unique_ptr< db_driver > db_conn
Database driver holder.
std::unique_ptr< app_config > main_config
Application config loaded from app_config.conf (main config file).
int register_new_user()
This function validets screen 6 buffers and if everything checks out then inserts new user into the D...
const char * s6_role_labels[S6_ROLE_CNT]
int log_in_user_rfid(rfid_reader::rfid_tag *tag, bool loading_sub=false)
Logs in user through scanned RFID tag. Initializes user_workspace if loading_sub is false.
std::pair< long, std::string > test_hx_samples_times[HX_TEST_CONST_IT_COUNT+HX_TEST_INC_IT_COUNT]
int open_db_connection()
Tries to open the database connection and init db_driver.
int load_font_size(app_workspace_ns::font_size key, float size_px)
Initializes font into the map.
std::vector< double > normalize_raw_values(std::vector< HX711::Value > &raw_vals)
Takes raw values and normalizes them using HX offset and reference unit. Resulting values are in Gram...
char s6_passwd_in[DEF_BUFF_SIZE_SMALL]
char usr_passwd[DEF_BUFF_SIZE_SMALL]
void logout_subuser()
Logs out subuser.
std::unique_ptr< measurement > observed_measurement
This variable is used to observe measuring.
const char * s3_filter_opt_labels[S3_FILTER_OPT_CNT]
app_workspace()
Construct a new app workspace object.
void hx711_calibrate()
Function that performs calibration on the hx711 controller.
bool hx_not_finished_yet
int hx711_continuous_measure()
Starts hx711 measuring that will run until its stopped by user.
app_workspace_ns::font_size get_font_size()
Get the font size.
bool is_debug_screens()
Retruns flag is.
int font_push_cnt
Whenever a font is used, it is pushed to the font stack of ImGui library. All pushed fonts need to be...
std::pair< long, std::string > test_hx_timeout_collected[HX_TEST_CONST_IT_COUNT+HX_TEST_INC_IT_COUNT]
char s6_name_in[DEF_BUFF_SIZE]
char s6_lastname_in[DEF_BUFF_SIZE_SMALL]
const char * unit_sel_labels[UNIT_SEL_CNT]
bool has_user()
Checks if user is logged in. This is determined by user_space being initialized and having the user_l...
std::vector< HX711::Value > hx711_values_timeout(int seconds)
Reads the HX711 sensor until @timeout is reached. Also starts new thread which is used to monitor ong...
int selected_hx_measure_opt
int verify_user_cred()
Tests if user entered correct credentials.
screen_manager * get_scr_mgr()
Get the screen manager instance. This instance is kind of singleton. Is initalized only once on start...
std::map< app_workspace_ns::font_size, ImFont * > loaded_fonts
Map of loaded fonts.
char subusr_name[DEF_BUFF_SIZE]
void set_kb_testing(bool val)
void set_scr_mgr(screen_manager *scr_mgr)
Set the screen manager instancte. This should only be called once, when the application is starting u...
std::unique_ptr< rfid_reader::rfid_tag > s6_rfid_tag
char usr_name[DEF_BUFF_SIZE]
void login_subuser()
When a user is already logged in and their role is employee or admin, they can log in another user as...
const char * s6_unit_sel_labels[S6_UNIT_SEL_CNT]
bool refresh_current_screen
When this is set to true, elements of current screen will be reinitialized for next frame.
HX711::Value ref_unit
int init_hx711_controller()
Initializes the hx711 controller.
bool user_logged
Flag to indicate if a user is logged in.
char s6_uname_in[DEF_BUFF_SIZE_SMALL]
std::unique_ptr< user_workspace > userspace
User's workspace. Serves similar function as app_workspace but for user data.
void log_in_user_cred()
Logs in user using credentials. Credentials are gained from screen_1 buffers.
int s6_selected_unit_option
char s6_desc_in[DEF_BUFF_SIZE_EXTRA]
const char * hx_measure_opts[S2_MEASURE_OTPS_CNT]
Handles database querries.
Definition: db_driver.h:41
This is a wrapper for ImGui Text which serves as unchangeble label.
Definition: gui_label.h:11
void set_label(const char *label)
Definition: gui_label.cpp:54
Container for measurement data and (convenience) variables, that are used to show measurement in GUI.
static void init_simple_measuring(measurement *m, std::vector< double > &values)
static void init_measuring(measurement *m, user_workspace *uspace, std::vector< double > &values, std::tm *start_tm, std::tm *end_tm, unsigned long m_length)
void clear_previous_screen_stack()
void set_selected_screen(uint8_t screen)
void refresh_screen_elements(uint8_t screen)
Class used as a container for user data, that are selected from database. (and also for insert,...
unsigned long id
Container that servers for storing users data and manipulating them.
const char * get_localized_text(const char *key)
Get the localized text object.
font_size
This enum defines sizes of corresponding fonts. E.g.: SMALL_FONT is 12px.
void set_kb_testing_inner(bool val)
Definition: keyboard.cpp:222
bool get_kb_testing_inner()
Definition: keyboard.cpp:216
gui_label * err_title
gui_label * err_desc
#define ADMIN_CTRL_SCREEN
RFID tag structure. Stores data read from SPI.
Definition: rfid_reader.h:12
uint8_t serial[10]
Definition: rfid_reader.h:14
Struct used to contain username, password and user status until credentials are verified.
Definition: db_driver.h:30
char passwd[64]
Definition: db_driver.h:33