| @@ -0,0 +1,2 @@ | |||||
| .pio | |||||
| .vscode | |||||
| @@ -0,0 +1,39 @@ | |||||
| This directory is intended for project header files. | |||||
| A header file is a file containing C declarations and macro definitions | |||||
| to be shared between several project source files. You request the use of a | |||||
| header file in your project source file (C, C++, etc) located in `src` folder | |||||
| by including it, with the C preprocessing directive `#include'. | |||||
| ```src/main.c | |||||
| #include "header.h" | |||||
| int main (void) | |||||
| { | |||||
| ... | |||||
| } | |||||
| ``` | |||||
| Including a header file produces the same results as copying the header file | |||||
| into each source file that needs it. Such copying would be time-consuming | |||||
| and error-prone. With a header file, the related declarations appear | |||||
| in only one place. If they need to be changed, they can be changed in one | |||||
| place, and programs that include the header file will automatically use the | |||||
| new version when next recompiled. The header file eliminates the labor of | |||||
| finding and changing all the copies as well as the risk that a failure to | |||||
| find one copy will result in inconsistencies within a program. | |||||
| In C, the usual convention is to give header files names that end with `.h'. | |||||
| It is most portable to use only letters, digits, dashes, and underscores in | |||||
| header file names, and at most one dot. | |||||
| Read more about using header files in official GCC documentation: | |||||
| * Include Syntax | |||||
| * Include Operation | |||||
| * Once-Only Headers | |||||
| * Computed Includes | |||||
| https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html | |||||
| @@ -0,0 +1,46 @@ | |||||
| This directory is intended for project specific (private) libraries. | |||||
| PlatformIO will compile them to static libraries and link into executable file. | |||||
| The source code of each library should be placed in a an own separate directory | |||||
| ("lib/your_library_name/[here are source files]"). | |||||
| For example, see a structure of the following two libraries `Foo` and `Bar`: | |||||
| |--lib | |||||
| | | | |||||
| | |--Bar | |||||
| | | |--docs | |||||
| | | |--examples | |||||
| | | |--src | |||||
| | | |- Bar.c | |||||
| | | |- Bar.h | |||||
| | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html | |||||
| | | | |||||
| | |--Foo | |||||
| | | |- Foo.c | |||||
| | | |- Foo.h | |||||
| | | | |||||
| | |- README --> THIS FILE | |||||
| | | |||||
| |- platformio.ini | |||||
| |--src | |||||
| |- main.c | |||||
| and a contents of `src/main.c`: | |||||
| ``` | |||||
| #include <Foo.h> | |||||
| #include <Bar.h> | |||||
| int main (void) | |||||
| { | |||||
| ... | |||||
| } | |||||
| ``` | |||||
| PlatformIO Library Dependency Finder will find automatically dependent | |||||
| libraries scanning project source files. | |||||
| More information about PlatformIO Library Dependency Finder | |||||
| - https://docs.platformio.org/page/librarymanager/ldf.html | |||||
| @@ -0,0 +1,18 @@ | |||||
| ; PlatformIO Project Configuration File | |||||
| ; | |||||
| ; Build options: build flags, source filter | |||||
| ; Upload options: custom upload port, speed and extra flags | |||||
| ; Library options: dependencies, extra library storages | |||||
| ; Advanced options: extra scripting | |||||
| ; | |||||
| ; Please visit documentation for the other options and examples | |||||
| ; https://docs.platformio.org/page/projectconf.html | |||||
| [env:nanoatmega328new] | |||||
| platform = atmelavr | |||||
| board = nanoatmega328 | |||||
| framework = arduino | |||||
| lib_deps = | |||||
| bogde/HX711@^0.7.4 | |||||
| marcoschwartz/LiquidCrystal_I2C@^1.1.4 | |||||
| thijse/EEPROMEx@0.0.0-alpha+sha.09d7586108 | |||||
| @@ -0,0 +1,60 @@ | |||||
| #include "buttons.h" | |||||
| #include "lcd.h" | |||||
| #include "scale.h" | |||||
| void Buttons::init() { | |||||
| pinMode(tare_button, INPUT); | |||||
| pinMode(controller_button, INPUT); | |||||
| pinMode(plus_button, INPUT); | |||||
| pinMode(minus_button, INPUT); | |||||
| } | |||||
| bool Buttons::is_any_pressed() { | |||||
| return digitalRead(tare_button) || digitalRead(controller_button); | |||||
| } | |||||
| void Buttons::on_button_pressed(Scale& scale, WeightControllerPool& pool, const LCD& lcd) { | |||||
| Action buttonAction = get_button_action(); | |||||
| switch (buttonAction) { | |||||
| case Action::TAR: | |||||
| scale.tare(); | |||||
| break; | |||||
| case Action::CALIBRATE: | |||||
| scale.calibrate(); | |||||
| break; | |||||
| case Action::NEXT_CONTROLLER: | |||||
| lcd.clear(); | |||||
| pool.next(); | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| Buttons::Action Buttons::get_button_action() { | |||||
| int button_pressed = 0; | |||||
| for (int i = 0; i < buttons_count; i++) { | |||||
| button_pressed |= digitalRead(buttons[i]) < i; | |||||
| } | |||||
| if (last_pressed == button_pressed) { | |||||
| } | |||||
| Buttons::Action action; | |||||
| if (button_pressed & 0x0001) { | |||||
| action = Action::TAR; | |||||
| } | |||||
| else if (tare_pressed && !controller_pressed) { | |||||
| action = Action::NEXT_CONTROLLER; | |||||
| } | |||||
| else { | |||||
| action = Action::NONE; | |||||
| } | |||||
| if (action == Action::TAR && (now - then) > 2000) { | |||||
| action = Action::CALIBRATE; | |||||
| } | |||||
| return action; | |||||
| } | |||||
| @@ -0,0 +1,30 @@ | |||||
| #ifndef BUTTONS_H | |||||
| #define BUTTONS_H | |||||
| #include <Arduino.h> | |||||
| #include "lcd.h" | |||||
| #include "scale.h" | |||||
| #include "weight_controller.h" | |||||
| #define tare_button A0 | |||||
| #define controller_button A1 | |||||
| #define plus_button A2 | |||||
| #define minus_button A3 | |||||
| class Buttons { | |||||
| private: | |||||
| enum class Action { | |||||
| NONE, | |||||
| TAR, | |||||
| CALIBRATE, | |||||
| NEXT_CONTROLLER | |||||
| }; | |||||
| public: | |||||
| void init(); | |||||
| bool is_any_pressed(); | |||||
| void on_button_pressed(Scale &scale, WeightControllerPool &pool, const LCD &lcd); | |||||
| Buttons::Action get_button_action(); | |||||
| }; | |||||
| #endif | |||||
| @@ -0,0 +1,89 @@ | |||||
| #include "lcd.h" | |||||
| LCD::LCD() {} | |||||
| LCD::~LCD() { | |||||
| delete lcd; | |||||
| } | |||||
| void LCD::init() { | |||||
| lcd = new LiquidCrystal_I2C(0x27, columns, rows); | |||||
| lcd->init(); | |||||
| lcd->backlight(); | |||||
| lcd->setBacklight(HIGH); | |||||
| } | |||||
| void LCD::print_init_message(int calibration_weight) const { | |||||
| lcd->setCursor(0, 0); | |||||
| lcd->print(F("YCM Scale")); | |||||
| lcd->setCursor(0, 1); | |||||
| lcd->print(F("Scaled to: ")); | |||||
| lcd->print(calibration_weight); | |||||
| lcd->print(F("g")); | |||||
| delay(1500); | |||||
| } | |||||
| void LCD::print_calibration(int calib_weight) const { | |||||
| lcd->setCursor(0, 1); | |||||
| lcd->print("Calibration: "); | |||||
| lcd->print(calib_weight); | |||||
| lcd->print(" g"); | |||||
| delay(800); | |||||
| clear_row(1); | |||||
| } | |||||
| void LCD::print_weight(double weight, int precision, const char* unit) const { | |||||
| // | |||||
| // MAKE SURE NEGATIVE AND POSITIVE VALUES DON'T JUMP | |||||
| // | |||||
| if (weight > 0) { | |||||
| lcd->print(" "); | |||||
| } | |||||
| // | |||||
| // | |||||
| lcd->print(weight, precision); | |||||
| lcd->print(" "); | |||||
| lcd->print(unit); | |||||
| } | |||||
| void LCD::print_weights(double grams, double grains) const { | |||||
| lcd->setCursor(0, 0); | |||||
| print_weight(grams, 3, "g "); | |||||
| lcd->setCursor(0, 1); | |||||
| print_weight(grains, 2, "grn "); | |||||
| } | |||||
| void LCD::print_control_result(String name, double val_min, double val_max, int result) { | |||||
| lcd->setCursor(0, 0); | |||||
| lcd->print(name); | |||||
| lcd->print(" "); | |||||
| lcd->print(val_min, 2); | |||||
| lcd->print("-"); | |||||
| lcd->print(val_max, 2); | |||||
| lcd->setCursor(0, 1); | |||||
| if (result == -1) { | |||||
| lcd->print("TOO LITTLE"); | |||||
| } | |||||
| else if (result == 1) { | |||||
| lcd->print("TOO MUCH "); | |||||
| } | |||||
| else { | |||||
| lcd->print("PASSED "); | |||||
| } | |||||
| } | |||||
| void LCD::clear_row(int row) const { | |||||
| lcd->setCursor(0, row); | |||||
| for (int i = 0; i < columns; i++) { | |||||
| lcd->print(" "); | |||||
| } | |||||
| lcd->setCursor(0, row); | |||||
| } | |||||
| void LCD::clear() const { | |||||
| lcd->clear(); | |||||
| } | |||||
| @@ -0,0 +1,27 @@ | |||||
| #ifndef LCD_H | |||||
| #define LCD_H | |||||
| #include <Arduino.h> | |||||
| #include <LiquidCrystal_I2C.h> | |||||
| class LCD { | |||||
| private: | |||||
| LiquidCrystal_I2C* lcd = nullptr; // set the LCD address to 0x27 for a 16 chars and 2 line display | |||||
| const int columns = 18; | |||||
| const int rows = 2; | |||||
| public: | |||||
| LCD(); | |||||
| ~LCD(); | |||||
| void init(); | |||||
| void print_init_message(int calibration_weight) const; | |||||
| void print_calibration(int calib_weight) const; | |||||
| void print_weight(double weight, int precision, const char* unit) const; | |||||
| void print_weights(double grams, double grains) const; | |||||
| void print_control_result(String name, double val_min, double val_max, int result); | |||||
| void clear_row(int row) const; | |||||
| void clear() const; | |||||
| }; | |||||
| #endif | |||||
| @@ -0,0 +1,92 @@ | |||||
| #include <Arduino.h> | |||||
| #include <EEPROMex.h> | |||||
| #include "lcd.h" | |||||
| #include "serial.h" | |||||
| #include "scale.h" | |||||
| #include "buttons.h" | |||||
| #include "weight_controller.h" | |||||
| #define shift_element 3 | |||||
| // ===================== | |||||
| // ======= SETUP ======= | |||||
| // ===================== | |||||
| LCD lcd; | |||||
| SerialIO serial; | |||||
| Scale scale; | |||||
| Buttons buttons; | |||||
| WeightControllerPool pool; | |||||
| void setup() | |||||
| { | |||||
| // | |||||
| // INIT | |||||
| // | |||||
| lcd.init(); | |||||
| serial.init(); | |||||
| scale.init(); | |||||
| buttons.init(); | |||||
| pool.init(); | |||||
| // | |||||
| // DISPLAY INIT MESSAGES | |||||
| // | |||||
| serial.print_init_message(); | |||||
| lcd.print_init_message(scale.get_calibration_weight()); | |||||
| lcd.clear(); | |||||
| // | |||||
| // DISPLAY INIT MESSAGES | |||||
| // | |||||
| } | |||||
| void loop() | |||||
| { | |||||
| // | |||||
| // ON BUTTON PRESSED ACTION | |||||
| // | |||||
| if (buttons.is_any_pressed()) | |||||
| { | |||||
| buttons.on_button_pressed(scale, pool, lcd); | |||||
| } | |||||
| // | |||||
| // READ WEIGHT | |||||
| // | |||||
| scale.read(); | |||||
| if (pool.is_controller_displayed()) { | |||||
| // | |||||
| // SHOW CONTROL RESULT | |||||
| // | |||||
| WeightController &controller = pool.get(); | |||||
| int result = controller.compare(scale.get_average_grain()); | |||||
| lcd.print_control_result(controller.get_name(), controller.get_val_min(), controller.get_val_max(), result); | |||||
| // | |||||
| // SHOW CONTROL RESULT | |||||
| // | |||||
| } else { | |||||
| // | |||||
| // PRINT WEIGHT | |||||
| // | |||||
| lcd.print_weights(scale.get_average_gram(), scale.get_average_grain()); | |||||
| // | |||||
| // PRINT WEIGHT | |||||
| // | |||||
| } | |||||
| // | |||||
| // PROCESS REQUESTS FROM SERIAL | |||||
| // | |||||
| if (serial.is_available()) | |||||
| { | |||||
| serial.on_command(scale, pool, lcd); | |||||
| if (serial.is_debug_info_allowed()) | |||||
| { | |||||
| serial.print_debug_info(scale.get_raw(), scale.get_average_raw(), scale.get_offset(), scale.get_weight(), scale.get_actual_gram(), scale.get_average_gram(), scale.get_average_grain()); | |||||
| } | |||||
| } | |||||
| // | |||||
| // PROCESS REQUESTS FROM SERIAL | |||||
| // | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| #include "scale.h" | |||||
| void Scale::init() { | |||||
| scaled_weight = EEPROM.readDouble(e_scale); | |||||
| int gain = EEPROM.readInt(e_gain); | |||||
| hx711.begin(out, clck, gain); | |||||
| offset = init_reading(); | |||||
| } | |||||
| long Scale::init_reading() { | |||||
| hx711.read_average(20); | |||||
| return hx711.read_average(NUMBER_OF_READINGS); | |||||
| } | |||||
| void Scale::read() { | |||||
| raw = hx711.read(); | |||||
| actual_gram = (raw - offset) / scaled_weight; | |||||
| if (abs(actual_gram - average_gram) > EPSILON) { | |||||
| sum = 0; | |||||
| count = 0; | |||||
| sum_raw = 0; | |||||
| average_raw = raw; | |||||
| average_gram = actual_gram; | |||||
| } | |||||
| else { | |||||
| sum += actual_gram; | |||||
| sum_raw += raw; | |||||
| count++; | |||||
| average_gram = sum / count; | |||||
| average_raw = sum_raw / count; | |||||
| } | |||||
| } | |||||
| void Scale::tare() { | |||||
| offset = average_raw; | |||||
| } | |||||
| void Scale::calibrate() { | |||||
| scaled_weight = (raw - offset) / get_calibration_weight(); | |||||
| EEPROM.updateDouble(e_scale, scaled_weight); | |||||
| } | |||||
| @@ -0,0 +1,80 @@ | |||||
| #ifndef SCALE_H | |||||
| #define SCALE_H | |||||
| #include <HX711.h> | |||||
| #include <EEPROMex.h> | |||||
| #define e_scale 0 | |||||
| #define e_calib_w 8 | |||||
| #define e_gain 10 | |||||
| #define none 0 | |||||
| #define tar 1 | |||||
| #define cal 2 | |||||
| #define shift_element 3 | |||||
| #define delay_vypis 800 | |||||
| #define NUMBER_OF_READINGS 30 | |||||
| class Scale { | |||||
| private: | |||||
| HX711 hx711; | |||||
| double sum = 0; | |||||
| long sum_raw = 0; | |||||
| int count = 0; | |||||
| double average_gram = 0; | |||||
| long average_raw = 0; | |||||
| double EPSILON = 0.01; | |||||
| long raw; | |||||
| long offset = 0; | |||||
| double scaled_weight = 15940.0; // aprox. 15 g | |||||
| double actual_gram; | |||||
| const int out = 2; | |||||
| const int clck = 3; | |||||
| public: | |||||
| void init(); | |||||
| long init_reading(); | |||||
| void read(); | |||||
| void tare(); | |||||
| void calibrate(); | |||||
| long get_raw() const { | |||||
| return raw; | |||||
| } | |||||
| long get_average_raw() const { | |||||
| return average_raw; | |||||
| } | |||||
| long get_offset() const { | |||||
| return offset; | |||||
| } | |||||
| int get_calibration_weight() const { | |||||
| return EEPROM.readInt(e_calib_w); | |||||
| } | |||||
| double get_weight() const { | |||||
| return scaled_weight; | |||||
| } | |||||
| double get_actual_gram() const { | |||||
| return actual_gram; | |||||
| } | |||||
| double get_average_grain() const { | |||||
| return average_gram / 0.06479891; | |||||
| } | |||||
| double get_average_gram() const { | |||||
| return average_gram; | |||||
| } | |||||
| }; | |||||
| #endif | |||||
| @@ -0,0 +1,119 @@ | |||||
| #include "serial.h" | |||||
| #include "lcd.h" | |||||
| void SerialIO::init() { | |||||
| Serial.begin(9600); | |||||
| } | |||||
| bool SerialIO::is_available() const { | |||||
| return Serial.available(); | |||||
| } | |||||
| void SerialIO::print_gain(int gain) const { | |||||
| Serial.print(F("zosilnenie = ")); | |||||
| Serial.print(gain, DEC); | |||||
| Serial.println(); | |||||
| } | |||||
| bool SerialIO::is_debug_info_allowed() const { | |||||
| return this->debug_info_allowed; | |||||
| } | |||||
| void SerialIO::print_init_message() const { | |||||
| Serial.println(F(" milivahy")); | |||||
| Serial.println(F(" ")); | |||||
| Serial.println(F(" v - vypis hodnot zap-vyp")); | |||||
| Serial.println(F(" r - presnost zobrazenia [r 3 2]")); | |||||
| Serial.println(F(" t - tare - nulovanie")); | |||||
| Serial.println(F(" c - kalibracia")); | |||||
| Serial.println(F(" g - zosilnenie 64, 128 [g 128]")); | |||||
| Serial.println(F(" w - kalibracne zavazie v g [ w 1]")); | |||||
| Serial.println(F(" p - nastavenie porovnania [ p 1 IT_1 2.0 3.0]")); | |||||
| Serial.println(); | |||||
| } | |||||
| void SerialIO::on_command(Scale& scale, WeightControllerPool& pool, LCD& lcd) | |||||
| { | |||||
| char var = Serial.read(); | |||||
| switch (var) | |||||
| { | |||||
| case 'c': | |||||
| scale.calibrate(); | |||||
| lcd.print_calibration(scale.get_calibration_weight()); | |||||
| Serial.println(); | |||||
| Serial.print(F("Scale = ")); | |||||
| Serial.println(scale.get_weight()); | |||||
| break; | |||||
| case 't': | |||||
| scale.tare(); | |||||
| break; | |||||
| case 'v': | |||||
| debug_info_allowed = !debug_info_allowed; | |||||
| break; | |||||
| case 'w': | |||||
| int calib_weight = Serial.parseInt(); | |||||
| Serial.print(F("calibration weight = ")); | |||||
| Serial.print(calib_weight, DEC); | |||||
| Serial.println(F(" g")); | |||||
| EEPROM.writeInt(e_calib_w, calib_weight); | |||||
| break; | |||||
| case 'r': | |||||
| des_m_g = Serial.parseInt(); | |||||
| des_m_grain = Serial.parseInt(); | |||||
| break; | |||||
| case 'p': { | |||||
| int index = Serial.parseInt(); | |||||
| String name = Serial.readStringUntil(' '); | |||||
| double val_min = Serial.parseFloat(); | |||||
| double val_max = Serial.parseFloat(); | |||||
| for (int j = 0; j < pool.get_max(); j++) | |||||
| { | |||||
| WeightController& controller = pool.get(j); | |||||
| Serial.println(); | |||||
| Serial.print(controller.get_name()); | |||||
| Serial.print(F(" ")); | |||||
| Serial.print(controller.get_val_min(), 2); | |||||
| Serial.print(F(" ")); | |||||
| Serial.print(controller.get_val_max(), 2); | |||||
| } | |||||
| break; | |||||
| } case 'g': | |||||
| int gain = Serial.parseInt(); | |||||
| if (gain == 64 || gain == 128) | |||||
| { | |||||
| EEPROM.writeInt(e_gain, gain); | |||||
| } | |||||
| print_gain(gain); | |||||
| break; | |||||
| case 'h': | |||||
| print_init_message(); | |||||
| break; | |||||
| } | |||||
| } | |||||
| void SerialIO::print_debug_info(long raw, double average_raw, long offset, double weight, double gram, double average_gram, double grain) const { | |||||
| Serial.print(F("RAW = ")); | |||||
| Serial.print(raw); | |||||
| Serial.print(F(", AV_RAW = ")); | |||||
| Serial.print(average_raw); | |||||
| Serial.print(F(", offset = ")); | |||||
| Serial.print(offset); | |||||
| Serial.print(F(", RAW-offset = ")); | |||||
| Serial.print(raw - offset); | |||||
| Serial.print(F(", Scale = ")); | |||||
| Serial.print(weight); | |||||
| Serial.print(F(", gram = ")); | |||||
| Serial.print(gram, des_m_g); | |||||
| Serial.print(F(", average = ")); | |||||
| Serial.print(average_gram, des_m_g); | |||||
| Serial.print(F(", grain = ")); | |||||
| Serial.println(grain, des_m_grain); | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| #ifndef SERIAL_H | |||||
| #define SERIAL_H | |||||
| #include <Arduino.h> | |||||
| #include "weight_controller.h" | |||||
| #include "scale.h" | |||||
| #include "lcd.h" | |||||
| #define e_calib_w 8 | |||||
| #define e_gain 10 | |||||
| class SerialIO { | |||||
| private: | |||||
| int des_m_g = 5; | |||||
| int des_m_grain = 3; | |||||
| bool debug_info_allowed = false; | |||||
| public: | |||||
| void init(); | |||||
| bool is_available() const; | |||||
| void print_gain(int gain) const; | |||||
| bool is_debug_info_allowed() const; | |||||
| void print_init_message() const; | |||||
| void on_command(Scale& scale, WeightControllerPool &pool, LCD &lcd); | |||||
| void print_debug_info(long raw, double average_raw, long offset, double weight, double gram, double average_gram, double grain) const; | |||||
| }; | |||||
| #endif | |||||
| @@ -0,0 +1,45 @@ | |||||
| #include "weight_controller.h" | |||||
| void WeightController::init(String name, double min, double max) { | |||||
| this->name = name; | |||||
| this->val_min = min; | |||||
| this->val_max = max; | |||||
| } | |||||
| int WeightController::compare(double weight) const { | |||||
| if (val_min > weight) { | |||||
| return -1; | |||||
| } | |||||
| else if (val_max < weight) { | |||||
| return 1; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| void WeightControllerPool::next() { | |||||
| if (current == 0) { | |||||
| controller_displayed = true; | |||||
| } | |||||
| current++; | |||||
| if (current - 1 >= max) { | |||||
| controller_displayed = false; | |||||
| current = 0; | |||||
| } | |||||
| } | |||||
| WeightController& WeightControllerPool::get() { | |||||
| return items[current - 1]; | |||||
| } | |||||
| WeightController& WeightControllerPool::get(int index) { | |||||
| if (index < 0) { | |||||
| return items[0]; | |||||
| } | |||||
| else if (index > max) { | |||||
| return items[max]; | |||||
| } | |||||
| return items[index]; | |||||
| } | |||||
| @@ -0,0 +1,77 @@ | |||||
| #ifndef WEIGHT_CONTROLLER_H | |||||
| #define WEIGHT_CONTROLLER_H | |||||
| #include <Arduino.h> | |||||
| class WeightController { | |||||
| private: | |||||
| String name; | |||||
| double val_min; | |||||
| double val_max; | |||||
| public: | |||||
| void init(String name, double min, double max); | |||||
| int compare(double weight) const; | |||||
| String get_name() const { | |||||
| return name; | |||||
| } | |||||
| double get_val_min() const { | |||||
| return val_min; | |||||
| } | |||||
| double get_val_max() const { | |||||
| return val_max; | |||||
| } | |||||
| void set_name(String name) { | |||||
| this->name = name; | |||||
| } | |||||
| void set_min(double min) { | |||||
| this->val_min = min; | |||||
| } | |||||
| void set_max(double max) { | |||||
| this->val_max = max; | |||||
| } | |||||
| }; | |||||
| class WeightControllerPool { | |||||
| private: | |||||
| int max = 4; | |||||
| WeightController items[4]; | |||||
| int current = 0; | |||||
| bool controller_displayed = false; | |||||
| public: | |||||
| void init() { | |||||
| items[0].init("9mm", 190, 200); | |||||
| items[1].init(".223", 0, 1); | |||||
| items[2].init("6.5", 200, 300); | |||||
| items[3].init(".308", 2, 3); | |||||
| } | |||||
| void set_item(int index, String name, double min, double max) { | |||||
| WeightController &controller = items[index]; | |||||
| controller.set_name(name); | |||||
| controller.set_min(min); | |||||
| controller.set_max(max); | |||||
| } | |||||
| bool is_controller_displayed() const { | |||||
| return controller_displayed; | |||||
| } | |||||
| int get_max() const{ | |||||
| return max; | |||||
| } | |||||
| void next(); | |||||
| WeightController &get(); | |||||
| WeightController &get(int index); | |||||
| }; | |||||
| #endif | |||||
| @@ -0,0 +1,11 @@ | |||||
| This directory is intended for PlatformIO Unit Testing and project tests. | |||||
| Unit Testing is a software testing method by which individual units of | |||||
| source code, sets of one or more MCU program modules together with associated | |||||
| control data, usage procedures, and operating procedures, are tested to | |||||
| determine whether they are fit for use. Unit testing finds problems early | |||||
| in the development cycle. | |||||
| More information about PlatformIO Unit Testing: | |||||
| - https://docs.platformio.org/page/plus/unit-testing.html | |||||