123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- #include <Arduino.h>
-
- #include "config.h"
- #include "config_pins.h"
- #include "lcd.h"
- #include "states.h"
-
- State::State(State *_parent) : parent(_parent), child(NULL), title("no title") {
- if (_parent != NULL) {
- _parent->setChild(this);
- }
- }
-
- // --------------------------------------
-
- StateText::StateText(State *_parent) : State(_parent) {
- heading = "no heading";
- text = "text missing";
- onEnterFunc = []() { };
- whenInFunc = [](StateMachineInput smi) {
- State *s = states_get();
- if (smi.click && (s != NULL)) {
- if (s->getChild() != NULL) {
- states_go_to(s->getChild());
- } else if (s->getParent() != NULL) {
- states_go_to(s->getParent());
- }
- }
- };
- }
-
- void StateText::setHeading(const char *_heading) {
- heading = _heading;
- }
-
- void StateText::setText(const char *_text) {
- text = _text;
- }
-
- void StateText::onEnter(EnterFuncPtr func) {
- onEnterFunc = func;
- }
-
- void StateText::whenIn(InFuncPtr func) {
- whenInFunc = func;
- }
-
- void StateText::updateText(void) {
- lcd_clear();
- if (heading != NULL) {
- lcd_set_heading(heading);
- } else if (getTitle() != NULL) {
- lcd_set_heading(getTitle());
- }
- if (text != NULL) {
- lcd_set_text(text);
- }
- }
-
- void StateText::enterState(void) {
- if (onEnterFunc != NULL) {
- onEnterFunc();
- }
-
- updateText();
- }
-
- void StateText::inState(struct StateMachineInput smi) {
- if (whenInFunc != NULL) {
- whenInFunc(smi);
- }
- }
-
- // --------------------------------------
-
- StateMenu::StateMenu(State *_parent, bool _show_parent) : State(_parent) {
- show_parent = _show_parent;
- menuPos = 0;
- menuOff = 0;
- }
-
- void StateMenu::setChild(State *_child) {
- children.push_back(_child);
- }
-
- void StateMenu::addChild(State *_child, int pos) {
- if (pos < 0) {
- setChild(_child);
- } else {
- array_insert_at_pos(&children, _child, pos);
- }
- }
-
- void StateMenu::enterState(void) {
- display();
- }
-
- void StateMenu::display(void) {
- lcd_clear();
- lcd_set_heading(getTitle());
-
- int size = children.size();
- if (show_parent) {
- size++;
- }
-
- for (int i = menuOff; (i < menuOff + lcd_text_lines()) && (i < size); i++) {
- String s;
- if (i == menuPos) {
- s = F("> ");
- } else {
- s = F(" ");
- }
- if (i == children.size()) {
- s += getParent()->getTitle();
- } else {
- s += children.at(i)->getTitle();
- }
- lcd_set_menu_text(i - menuOff, s.c_str());
- }
- }
-
- void StateMenu::inState(struct StateMachineInput smi) {
- int size = children.size();
- if (show_parent) {
- size++;
- }
-
- if (smi.encoder != 0) {
- menuPos -= smi.encoder;
-
- while (menuPos < 0) {
- menuPos += size;
- }
-
- while (menuPos >= size) {
- menuPos -= size;
- }
-
- while (menuPos < menuOff) {
- menuOff--;
- }
-
- while (menuPos >= (menuOff + lcd_text_lines())) {
- menuOff++;
- }
-
- display();
- }
-
- if (smi.click) {
- if (menuPos == children.size()) {
- menuPos = 0;
- menuOff = 0;
- states_go_to(getParent());
- } else {
- states_go_to(children.at(menuPos));
- }
- }
- }
-
- // --------------------------------------
-
- StateDynamicMenu::StateDynamicMenu(State *_parent) : State(_parent) {
- menuPos = 0;
- menuOff = 0;
- prefix = "";
- countFunc = NULL;
- getFunc = NULL;
- callFunc = NULL;
- }
-
- void StateDynamicMenu::dataCount(CountFuncPtr count) {
- countFunc = count;
- }
-
- void StateDynamicMenu::dataGet(GetFuncPtr get) {
- getFunc = get;
- }
-
- void StateDynamicMenu::dataCall(CallFuncPtr call) {
- callFunc = call;
- }
-
- void StateDynamicMenu::display(void) {
- lcd_clear();
- lcd_set_heading(getTitle());
-
- for (int i = menuOff; (i < menuOff + lcd_text_lines()) && (i < count + 1); i++) {
- String s;
- if (i == menuPos) {
- s = F("> ");
- } else {
- s = F(" ");
- }
- if (i == count) {
- s += getParent()->getTitle();
- } else {
- s += contents.at(i);
- }
- lcd_set_menu_text(i - menuOff, s.c_str());
- }
- }
-
- void StateDynamicMenu::setPrefix(String pre) {
- prefix = pre;
- }
-
- void StateDynamicMenu::enterState(void) {
- // cache all entries on entering state
- if (countFunc != NULL) {
- count = countFunc();
- } else {
- count = 0;
- }
- contents.clear();
- for (int i = 0; i < count; i++) {
- if (getFunc != NULL) {
- contents.push_back(prefix + String(getFunc(i)));
- } else {
- contents.push_back(prefix + String(i + 1));
- }
- }
-
- display();
- }
-
- void StateDynamicMenu::inState(StateMachineInput smi) {
- if (smi.encoder != 0) {
- menuPos -= smi.encoder;
-
- while (menuPos < 0) {
- menuPos += count + 1;
- }
-
- while (menuPos >= count + 1) {
- menuPos -= count + 1;
- }
-
- while (menuPos < menuOff) {
- menuOff--;
- }
-
- while (menuPos >= (menuOff + lcd_text_lines())) {
- menuOff++;
- }
-
- display();
- }
-
- if (smi.click) {
- if (menuPos == count) {
- menuPos = 0;
- menuOff = 0;
- states_go_to(getParent());
- } else {
- if (callFunc != NULL) {
- callFunc(menuPos);
- }
- }
- }
- }
-
- // --------------------------------------
-
- template <typename T>
- StateValue<T>::StateValue(State *_parent, T &_value, T _min, T _max) : State(_parent), value(_value) {
- min = _min;
- max = _max;
- heading = NULL;
- text = NULL;
- onEnterFunc = NULL;
- updateFunc = NULL;
- updateLiveFunc = NULL;
- }
-
- template <typename T>
- void StateValue<T>::setHeading(const char *_heading) {
- heading = _heading;
- }
-
- template <typename T>
- void StateValue<T>::setText(const char *_text) {
- text = _text;
- }
-
- template <typename T>
- void StateValue<T>::onEnter(EnterFuncPtr func) {
- onEnterFunc = func;
- }
-
- template <typename T>
- void StateValue<T>::onUpdate(UpdateFuncPtr func) {
- updateFunc = func;
- }
-
- template <typename T>
- void StateValue<T>::onLiveUpdate(UpdateFuncPtr func) {
- updateLiveFunc = func;
- }
-
- template <typename T>
- void StateValue<T>::display(void) {
- lcd_clear();
- if (heading == NULL) {
- lcd_set_heading(getTitle());
- } else {
- lcd_set_heading(heading);
- }
-
- String s = String(min) + F(" .. ") + String(value) + F(" .. ") + String(max);
-
- if (text != NULL) {
- s = text + String(F("\n")) + s;
- }
-
- lcd_set_text(s.c_str());
- }
-
-
- template <typename T>
- void StateValue<T>::enterState(void) {
- if (onEnterFunc != NULL) {
- onEnterFunc();
- }
- display();
- }
-
- template <typename T>
- void StateValue<T>::inState(StateMachineInput smi) {
- if (smi.encoder != 0) {
- float vf = smi.encoder;
- vf *= 1.0 + ((float)smi.rpm / ENCODER_RPM_VALUE_FACTOR);
- int v = vf;
- value -= v;
- if (value < min) {
- value = min;
- }
- if (value > max) {
- value = max;
- }
- if (updateLiveFunc != NULL) {
- updateLiveFunc(value);
- }
- display();
- }
- if (smi.click) {
- if (updateFunc != NULL) {
- updateFunc(value);
- }
- states_go_to(getParent());
- }
- }
-
- template class StateValue<int>;
- template class StateValue<float>;
-
- // --------------------------------------
-
- template <typename T, size_t N>
- StateValues<T, N>::StateValues(State *_parent) : State(_parent) {
- heading = NULL;
- onEnterFunc = NULL;
- updateFunc = NULL;
- updateLiveFunc = NULL;
- pos = 0;
- editing = false;
- }
-
- template <typename T, size_t N>
- void StateValues<T, N>::setData(size_t index, const char *name, T *value, T min, T max) {
- if (index >= N) {
- return;
- }
- values[index] = value;
- mins[index] = min;
- maxs[index] = max;
- texts[index] = name;
- }
-
- template <typename T, size_t N>
- void StateValues<T, N>::setHeading(const char *_heading) {
- heading = _heading;
- }
-
- template <typename T, size_t N>
- void StateValues<T, N>::onEnter(EnterFuncPtr func) {
- onEnterFunc = func;
- }
-
- template <typename T, size_t N>
- void StateValues<T, N>::onUpdate(UpdateFuncPtr func) {
- updateFunc = func;
- }
-
- template <typename T, size_t N>
- void StateValues<T, N>::onLiveUpdate(UpdateFuncPtr func) {
- updateLiveFunc = func;
- }
-
- template <typename T, size_t N>
- void StateValues<T, N>::display(void) {
- lcd_clear();
-
- if (heading == NULL) {
- lcd_set_heading(getTitle());
- } else {
- lcd_set_heading(heading);
- }
-
- for (size_t i = 0; i < (N + 1); i++) {
- String s;
-
- if (i == pos) {
- if (editing) {
- s = F("# ");
- } else {
- s = F("> ");
- }
- } else {
- s = F(" ");
- }
-
- if (i < N) {
- s += texts[i] + String(*(values[i])) + F(" (") + String(mins[i]) + F("/") + String(maxs[i]) + F(")");
- } else {
- if (getChild() != NULL) {
- s += F("Continue");
- } else {
- s += F("Done");
- }
- }
-
- lcd_set_menu_text(i, s.c_str());
- }
- }
-
- template <typename T, size_t N>
- void StateValues<T, N>::enterState(void) {
- pos = 0;
- if (onEnterFunc != NULL) {
- onEnterFunc();
- }
- display();
- }
-
- template <typename T, size_t N>
- void StateValues<T, N>::inState(StateMachineInput smi) {
- if (editing) {
- if (smi.encoder != 0) {
- float vf = smi.encoder;
- vf *= 1.0 + ((float)smi.rpm / ENCODER_RPM_VALUE_FACTOR);
- int v = vf;
- *(values[pos]) -= v;
-
- if (*(values[pos]) < mins[pos]) {
- *(values[pos]) = mins[pos];
- }
-
- if (*(values[pos]) > maxs[pos]) {
- *(values[pos]) = maxs[pos];
- }
-
- if (updateLiveFunc != NULL) {
- updateLiveFunc(pos, *(values[pos]));
- }
-
- display();
- }
- if (smi.click) {
- editing = false;
- display();
- }
- } else {
- if (smi.encoder != 0) {
- int tmp = pos;
- tmp -= smi.encoder;
-
- while (tmp < 0) {
- tmp += N + 1;
- }
-
- while (tmp >= (N + 1)) {
- tmp -= N + 1;
- }
-
- pos = tmp;
-
- display();
- }
- if (smi.click) {
- if (pos < N) {
- editing = true;
- display();
- } else {
- if (updateFunc != NULL) {
- for (size_t i = 0; i < N; i++) {
- updateFunc(i, *(values[i]));
- }
- }
-
- if (getChild() != NULL) {
- states_go_to(getChild());
- } else if (getParent() != NULL) {
- states_go_to(getParent());
- }
- }
- }
- }
- }
-
- template class StateValues<uint8_t, 2>;
- template class StateValues<float, 2>;
-
- // --------------------------------------
-
- template <typename T, size_t N>
- void array_print(Array<T, N> *arr) {
- Serial.print(F("Array length: "));
- Serial.print(arr->size());
- Serial.println(F(" contents:"));
- for (int i = 0; i < arr->size(); i++) {
- Serial.print(i);
- Serial.print(F(": "));
- Serial.println(arr->at(i)->getTitle());
- }
- }
-
- template <typename T, size_t N>
- void array_insert_at_pos(Array<T, N> *arr, T value, size_t pos) {
- // make additional space
- arr->push_back(value);
-
- if ((pos >= arr->max_size()) || (pos >= arr->size())) {
- // we can not shift it to the given position
- return;
- }
-
- for (int i = arr->size() - 2; i >= pos; i--) {
- arr->at(i + 1) = arr->at(i);
- }
-
- arr->at(pos) = value;
- }
|