Raspberry Pi Weighting Control System
This project serves as a simple weighting control system, that was realized as a Bachelor Thesis
Functions
app_workspace.cpp File Reference
#include "app_workspace.h"
#include <stdio.h>
#include <spdlog/spdlog.h>
#include "imgui.h"
#include "localisation.h"
#include "gui_label.h"
#include "unistd.h"

Go to the source code of this file.

Functions

void threaded_values_read ()
 This function is started in a new thread for reading HX711 values. More...
 
void threaded_tare ()
 This function is started in a new thread for taring HX711. More...
 
void threaded_calibration ()
 This function is started in a new thread for calibrating HX711. More...
 
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 intervals. More...
 
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. This thread serves for measuring values written by HX711. More...
 

Function Documentation

◆ threaded_calibration()

void threaded_calibration ( )

This function is started in a new thread for calibrating HX711.

Definition at line 1000 of file app_workspace.cpp.

1000  {
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 }
One of the most importat classes in the whole project. Holds variables that define the state of the a...
std::unique_ptr< custom_hx711 > hx711_controller
HX711 controller. This is an instance of custom_hx711 which extends library's AdvancedHX711.
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
bool refresh_current_screen
When this is set to true, elements of current screen will be reinitialized for next frame.
HX711::Value ref_unit

◆ threaded_measuring_watchdog()

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. This thread serves for measuring values written by HX711.

Parameters
msringWhen this is set to false, watchdog is stopped
watcherValues, that are watched

Definition at line 1200 of file app_workspace.cpp.

1200  {
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 }
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...
std::unique_ptr< measurement > observed_measurement
This variable is used to observe measuring.
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)

◆ threaded_tare()

void threaded_tare ( )

This function is started in a new thread for taring HX711.

Definition at line 950 of file app_workspace.cpp.

950  {
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 }

◆ threaded_values_read()

void threaded_values_read ( )

This function is started in a new thread for reading HX711 values.

Definition at line 844 of file app_workspace.cpp.

844  {
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 }
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::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.
std::unique_ptr< db_driver > db_conn
Database driver holder.
bool hx_not_finished_yet
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
screen_manager * get_scr_mgr()
Get the screen manager instance. This instance is kind of singleton. Is initalized only once on start...
std::unique_ptr< user_workspace > userspace
User's workspace. Serves similar function as app_workspace but for user data.
void refresh_screen_elements(uint8_t screen)
const char * get_localized_text(const char *key)
Get the localized text object.

◆ threaded_values_read_looped()

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 intervals.

Definition at line 1066 of file app_workspace.cpp.

1066  {
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 }
#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
user_workspace * get_userspace()
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)