From 8443008dfa60fafb1000b44aff9ec2bccbfab63b Mon Sep 17 00:00:00 2001 From: euquiq <31453004+euquiq@users.noreply.github.com> Date: Sat, 27 Jun 2020 23:59:11 -0300 Subject: [PATCH] New Antenna length Calculator It reads the antennas definition from a txt file: WHIPCALC/ANTENNAS.TXT Inside the textfile you place each antenna you own with the following sintaxis: For example: ANT500 185 315 450 586 724 862 Input the required frequency, adjust the wave type (full / half / quarter, etc.) and the calculator will return the antenna length (metric and imperial) while also calculating how much you need to expand the fitting antennas you got defined on the txt. It may return up to 8 matching antennas, which is more than enough (normally you will have 2, perhaps 3 telescopic antennas around for your portapack) If by any chance your antennas txt got more than 8 antennas, and more than 8 matches the length of the freq / wave you want, it will only show the first 8 matching antennas and will warn you at the bottom that there are even more results (hidden). All calculations now are rounded into the best integer, considering first decimal, so precision is double than the original antenna calculator app. --- firmware/application/apps/ui_whipcalc.cpp | 107 +++++++++++++++++++--- firmware/application/apps/ui_whipcalc.hpp | 56 +++++++---- firmware/common/ui_widget.cpp | 5 +- sdcard/WHIPCALC/ANTENNAS.TXT | 4 + 4 files changed, 138 insertions(+), 34 deletions(-) create mode 100644 sdcard/WHIPCALC/ANTENNAS.TXT diff --git a/firmware/application/apps/ui_whipcalc.cpp b/firmware/application/apps/ui_whipcalc.cpp index 64de95b4..4ed2100d 100644 --- a/firmware/application/apps/ui_whipcalc.cpp +++ b/firmware/application/apps/ui_whipcalc.cpp @@ -64,22 +64,48 @@ void WhipCalcView::update_result() { text_result_metric.set(m + "m " + cm + "." + mm + "cm"); - // ANT500 elements for crude adjustment - length /= 0.14; - if (int(length) <= 4) { - auto elements = to_string_dec_int((int)length, 1); - text_result_ant500.set(elements + " " + frac_str[((int(length * 10.0) % 10) + 1) / 3] + "ANT500 elements"); - } else { - text_result_ant500.set("-"); - } + uint8_t ant_count = 8; //Shown antennas counter + console.write("\f"); //Equivalent to clear console and string buffer. + length *= 1000; //Get length in mm needed to extend the antenna + for (antenna_entry antenna : antenna_db) { //go thru all antennas available + if (length >= antenna.elements.front() && length <= antenna.elements.back()) //This antenna is OK + { + uint16_t element,refined_quarter=0; + for(element=0; element < antenna.elements.size();element++) { + if (length == antenna.elements[element]) //Exact element in length + { + element++; //Real element is +1 (zero based vector) + break; //Done with this ant + } + else if (length < antenna.elements[element]) + { + double remain, this_element, quarter = 0; + remain = length - antenna.elements[element-1]; //mm needed from this element to reach length + this_element=antenna.elements[element] - antenna.elements[element -1]; //total mm on this element + quarter = (remain * 4) / this_element; //havoc & portack ended on this int(quarter) resolution. + if (quarter - int(quarter) > 0.5) { //rounding gave a measure closer to next quarter + refined_quarter=int(quarter) + 1; + if(refined_quarter == 4) { //rounding gave a measure closer to next element + refined_quarter = 0; + element++; + } + } else { + refined_quarter=int(quarter); + } + break; //Done with this ant + } + } + if (!ant_count) { + console.write(" and more ..."); + break; + } + console.write(antenna.label + " " + to_string_dec_int(element,1) + frac_str[refined_quarter] + " elements\n"); + ant_count--; + } + } // Imperial calclength = (speed_of_light_fps / (double)field_frequency.value()) * divider; - -/* auto feet = to_string_dec_int((int)length, 3); - auto inch = to_string_dec_int(int(length * 10.0) % 12, 2); - auto inch_c = to_string_dec_int(int(length * 100.0) % 10, 1); */ - auto feet = to_string_dec_int(int(calclength), 3); calclength = get_decimals(calclength,12); //inches auto inch = to_string_dec_int(int(calclength), 2); @@ -94,13 +120,38 @@ WhipCalcView::WhipCalcView( add_children({ &labels, + &antennas_on_memory, &field_frequency, &options_type, &text_result_metric, &text_result_imperial, - &text_result_ant500, + &console, &button_exit }); + + File antennas_file; //LOAD /WHIPCALC/ANTENNAS.TXT from microSD + auto result = antennas_file.open("WHIPCALC/ANTENNAS.TXT"); + antenna_db.clear(); //Start with fresh db + if (result.is_valid()) { + antenna_Default(); //There is no txt, store a default ant500 + } else { + std::string line; //There is a txt file + char one_char[1]; //Read it char by char + for (size_t pointer=0; pointer < antennas_file.size();pointer++) { + antennas_file.seek(pointer); + antennas_file.read(one_char, 1); + if ((int)one_char[0] > 31) { //ascii space upwards + line += one_char[0]; //Add it to the textline + } + else if (one_char[0] == '\n') { //New Line + txtline_process(line); //make sense of this textline + line.clear(); //Ready for next textline + } + } + if (line.length() > 0) txtline_process(line); //Last line had no newline at end ? + if (!antenna_db.size()) antenna_Default(); //no antenna found on txt, use default + } + antennas_on_memory.set(to_string_dec_int(antenna_db.size(),2) + " antennas"); //tell user options_type.on_change = [this](size_t, OptionsField::value_t) { this->update_result(); @@ -128,4 +179,32 @@ WhipCalcView::WhipCalcView( update_result(); } +void ui::WhipCalcView::txtline_process(std::string& line) { + if (line.find("#") != std::string::npos) return; //Line is just a comment + size_t previous = 0; + uint16_t value = 0; + antenna_entry new_antenna; + size_t current = line.find(" "); + while (current != std::string::npos) { + if (!previous) { //first space found + new_antenna.label.assign(line,0,current); //antenna label + } else { + value = std::stoi(line.substr(previous,current - previous)); + if (!value) return; //No element length? abort antenna + new_antenna.elements.push_back(value); //Store this new element + } + previous = current + 1; + current = line.find(" ",previous); //Search for next space delimiter + } + if (!previous) return; //Not even a label ? drop this antenna! + value = std::stoi(line.substr(previous,current - previous)); //Last element + if (!value) return; + new_antenna.elements.push_back(value); + antenna_db.push_back(new_antenna); //Add this antenna +} + + void ui::WhipCalcView::antenna_Default() { + antenna_db.push_back({"ANT500",{ 185, 315, 450, 586, 724, 862} }); //store a default ant500 +} + } diff --git a/firmware/application/apps/ui_whipcalc.hpp b/firmware/application/apps/ui_whipcalc.hpp index d9a66343..d8585925 100644 --- a/firmware/application/apps/ui_whipcalc.hpp +++ b/firmware/application/apps/ui_whipcalc.hpp @@ -28,6 +28,7 @@ #include "ui_receiver.hpp" #include "ui_navigation.hpp" #include "string_format.hpp" +#include namespace ui { @@ -43,50 +44,67 @@ private: const double speed_of_light_mps = 299792458.0; // m/s const double speed_of_light_fps = 983571087.90472; // feet/s - const std::string frac_str[4] = { "", "1/4 ", "1/2 ", "3/4 " }; + const std::string frac_str[4] = { "", " 1/4", " 1/2", " 3/4" }; + + struct antenna_entry { + std::string label { }; + std::vector elements { }; + }; + + std::vector antenna_db { }; double get_decimals(double num, int16_t mult, bool round = false); void update_result(); + + uint16_t string_to_number(std::string); + void txtline_process(std::string&); + void antenna_Default(); Labels labels { + { { 5 * 8, 1 * 16 }, "Loaded:", Color::light_grey() }, { { 2 * 8, 2 * 16 }, "Frequency:", Color::light_grey() }, - { { 2 * 8, 3 * 16 }, "Type:", Color::light_grey() } + { { 7 * 8, 3 * 16 }, "Wave:", Color::light_grey() }, + { { 5 * 8, 4 * 16 }, "Metric:", Color::light_grey() }, + { { 3 * 8, 5 * 16 }, "Imperial:", Color::light_grey() } }; + Text antennas_on_memory { + { 13 * 8, 1 * 16, 2 * 16, 16 }, + }; + FrequencyField field_frequency { { 13 * 8, 2 * 16 }, }; OptionsField options_type { - { 8 * 8, 3 * 16 }, - 12, + { 13 * 8, 3 * 16 }, + 7, { - { "Full wave", 8 }, - { "Half wave", 4 }, - { "Quarter wave", 2 }, - { "3/4 wave", 6 }, - { "1/8 wave", 1 }, - { "3/8 wave", 3 }, - { "5/8 wave", 5 }, - { "7/8 wave", 7 } + { "Full", 8 }, + { "Half", 4 }, + { "Quarter", 2 }, + { "3/4", 6 }, + { "1/8", 1 }, + { "3/8", 3 }, + { "5/8", 5 }, + { "7/8", 7 } } }; Text text_result_metric { - { 3 * 8, 5 * 16, 10 * 16, 16 }, + { 13 * 8, 4 * 16, 10 * 16, 16 }, "-" }; Text text_result_imperial { - { 2 * 8, 6 * 16, 10 * 16, 16 }, - "-" - }; - Text text_result_ant500 { - { 2 * 8, 8 * 16, 26 * 16, 16 }, + { 13 * 8, 5 * 16, 10 * 16, 16 }, "-" }; + Console console { + { 0, 7 * 16, 240, 144 } //Allows to show up to 8 antennas + }; Button button_exit { - { 72, 264, 96, 32 }, + { 72, 17 * 16, 96, 32 }, "Exit" }; }; diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 5e2d7db8..c4c035a6 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -595,7 +595,10 @@ void Console::write(std::string message) { pen_color = s.foreground; escape = false; } else { - if (c == '\n') { + if (c=='\f') { //Add FORM FEED (clear screen) + clear(); + buffer.clear(); + } else if (c == '\n') { crlf(); } else if (c == '\x1B') { escape = true; diff --git a/sdcard/WHIPCALC/ANTENNAS.TXT b/sdcard/WHIPCALC/ANTENNAS.TXT new file mode 100644 index 00000000..da821ef2 --- /dev/null +++ b/sdcard/WHIPCALC/ANTENNAS.TXT @@ -0,0 +1,4 @@ +# +ANT700 95 134 175 206 230 245 +ANT500 185 315 450 586 724 862 +CHEAPO 118 183 253 326 399 476 \ No newline at end of file