РЕШЕНО Привязка функции с параметром в библиотеке liquidmenu

Тема в разделе "Arduino & Shields", создана пользователем clkid, 8 май 2020.

  1. clkid

    clkid Нуб

    Добрый день!
    Использую библиотеку liquidmenu для создания меню, пытаюсь привязать к линиям функцию с аргументом
    Код (C++):
    void Group1_ON(int on)    {
      digitalWrite(SWG_1, HIGH);
      digitalWrite(on, HIGH); //SWR
      digitalWrite(SUO, HIGH);
      delay(100);
      digitalWrite(SWG_1, LOW);
      digitalWrite(on, LOW); //SWR
      digitalWrite(SUO, LOW);
      int c = on - 0;
      SK[c] = {digitalRead(SK_1)};
      if (SK[c] == 1) {
        K_STR[on] = K_STR[on] + "ON" + "\x94";
      }
      else   K_STR[on] = K_STR[on] + "ON" + "\x21";

      K9.attach_function(1, Group1_ON(1));
    При этом возникает ошибка:Invalid use of void exception.
    Как я понял, это связано с тем, что attach_function в классе liquidline не предусматривает аргумента:
    Код (C++):
    bool LiquidLine::attach_function(uint8_t number, void (*function)(void)) {
        print_me(reinterpret_cast<uintptr_t>(this));
        if (number <= MAX_FUNCTIONS) {
            _function[number - 1] = function;
            DEBUG(F("Attached function ")); DEBUGLN(number);
            _focusable = true;
            return true;
        } else {
            DEBUG(F("Attaching function ")); DEBUG(number);
            DEBUGLN(F(" failed, edit LiquidMenu_config.h to allow for more functions"));
            return false;
        }
    }
    Попробовал добавить этот аргумент, но на данном этапе я уже совсем не понимаю, что происходит и действую наобум :)
    Код (C++):
    bool LiquidLine::attach_function_int(uint8_t number, void (*function)(int)) {
    Собственно вопрос, как можно это реализовать?
     
  2. b707

    b707 Гуру

    в этой строчке
    Код (C++):
    K9.attach_function(1, Group1_ON(1));
    вы пытаетесь передать ссылку на функцию с конкретным аргументом "1" - это неверно. у ссылки на функцию нет аргументов.
    нужно передавать ссылку на функцию отдельно от параметров, например так
    Код (C++):
    K9.attach_function(1, 1, Group1_ON);
    где вторая единица в скобках - это аргумент для функции Group1_ON(int)

    Соответвенно и заголовок функции LiquidLine::attach_function() должно быть переписано как:
    Код (C++):
    bool LiquidLine::attach_function_int(uint8_t number, int par, void (*function)(int)) {
    ну и код функции соответственно
     
    Последнее редактирование: 8 май 2020
    clkid и arkadyf нравится это.
  3. clkid

    clkid Нуб

    Ошибку понял, как реализовать - не понимаю.
    В библиотеке в классе liquidline существует только функция liquidLine::attach_function(), с одним аргументом и ссылкой на void() функцию.
    Я добавил в liquidline.cpp строку и полностью скопировал тело liquidLine::attach_function() в LiquidLine::attach_function_int.
    Код (C++):
    bool LiquidLine::attach_function_int(uint8_t number, int par, void (*function)(int)) {
    Но компилятор пишет, ошибку 'class LiquidLine' has no member named 'attach_function_int'; did you mean 'attach_function'?.
    Второй вопрос, как теперь сослаться на int par при объявлении функции void Group1_ON(int on).
    Как указать, что int on=int par?
     
  4. AlexU

    AlexU Гуру

    Есть подозрение, что не правильно решаете свою задачу.
    Если в момент регистрации функции знаете с каким параметром её нужно вызвать, то регистрируйте функцию, которая будет работать с нужным параметром.
    Пример:
    Код (C++):
    void Group1_ON(int on)    {
      digitalWrite(SWG_1, HIGH);
      digitalWrite(on, HIGH); //SWR
      digitalWrite(SUO, HIGH);
      delay(100);
      digitalWrite(SWG_1, LOW);
      digitalWrite(on, LOW); //SWR
      digitalWrite(SUO, LOW);
      int c = on - 0;
      SK[c] = {digitalRead(SK_1)};
      if (SK[c] == 1) {
        K_STR[on] = K_STR[on] + "ON" + "\x94";
      }
      else   K_STR[on] = K_STR[on] + "ON" + "\x21";
    }

    void Group1_ON_1()    {
      Group1_ON(1);
    }

      K9.attach_function(1, Group1_ON_1);
    Если же, параметр функции меняется во время работы программы, то функция должна "уметь" получать значение параметра не через аргумент функции, а другим образом, например, через глобальную переменную. Т.е. функция без параметров читает глобальную переменную.
     
    SergeiL нравится это.
  5. b707

    b707 Гуру

    а в liquidline.h кто описание функции будет добавлять? Пушкин?
     
  6. clkid

    clkid Нуб

    В данной библиотеке liquidline.h нет, описание есть в liquidmenu.h, туда добавил, ошибка ушла.
    Но как сослаться на int par в void Group1_ON(int *par) я не понимаю, буду рад, если подскажете.
    В моем случае придется зарегистрировать 20 функций(будет задействовано 20 пинов), и потом еще столько же раз выполнить attach.function.
     
  7. b707

    b707 Гуру

    не надо ссылаться на параметр в ссылке на функцию, передавайте их отдельно. А уже в самом методе LiquidLine::attach_function() вызывайте функцию с нужным параметром.
    функции достаточно одной, а вот attach вам по любому придется выполнить столько раз. сколько у вас значений параметра
     
  8. AlexU

    AlexU Гуру

    В Вашем случае лучше сделать двадцать функций, которые будут вызывать функцию с определённым параметром (пример кода приводил в сообщении #4). И каждую функцию зарегистрировать через 'LiquidLine::attach_function()'.
    Меньше проблем соберёте на свою голову....
     
  9. AlexU

    AlexU Гуру

    В функцию 'LiquidLine::attach_function()' передаётся адрес функции, а не её вызов. Поэтому ни каких параметров передать нельзя.
    Для этого придётся переписать некоторое количество кода библиотеки 'liquidmenu', при этом не просто добавить заголовок и реализацию нужной функции, как Вы советовали.
    Не уверен, что автор темы это осилит.
     
  10. b707

    b707 Гуру

    Ну почему же нельзя? Вызов функции с аргументом - нельзя. а отдельным параметром ссылку на функцию и другим параметром аргумент - вполне себе можно
    да я ему вроде все уже описал в #2, что там осиливать. Да. придется добавить в библиотеку свою функцию 'LiquidLine::attach_function_int()' - но вряд ли это так сложно
     
  11. AlexU

    AlexU Гуру

    Можно, но этого мало. Нужно запомнить этот параметр (int) и при этом запомнить адрес функции. И в общем случае запомнить соотношение параметра (int) с адресом функции, в частном случае (нужно понимать в каком) достаточно запомнить параметры и адрес одной функции. Потом эти (эту) функции вызывать в нужном месте с правильным параметром.
    Ну добавите в класс метод 'attach_function_int', который будет регистрировать функцию с параметром, а вызывать эту зарегистрированную функцию в нужный момент с этим параметром кто будет? Впрочем, повторяюсь.....
    Судя по вопросам, автор не осилит.....
     
    clkid и SergeiL нравится это.
  12. clkid

    clkid Нуб

    Именно так, задачу вы поняли верно.
    И в этом вы правы, что нужно сделать, я понял. А вот как это сделать - для меня загадка, придется писать отдельную функцию на каждый пункт
    меню, как я в принципе и сделал это изначально:(
     
  13. AlexU

    AlexU Гуру

    Если используете язык C++, то можно немного упростить себе задачу, применив шаблоны:
    Код (C++):
    void Group1_ON(int on)    {
      digitalWrite(SWG_1, HIGH);
      digitalWrite(on, HIGH); //SWR
      digitalWrite(SUO, HIGH);
      delay(100);
      digitalWrite(SWG_1, LOW);
      digitalWrite(on, LOW); //SWR
      digitalWrite(SUO, LOW);
      int c = on - 0;
      SK[c] = {digitalRead(SK_1)};
      if (SK[c] == 1) {
        K_STR[on] = K_STR[on] + "ON" + "\x94";
      }
      else   K_STR[on] = K_STR[on] + "ON" + "\x21";
    }

    // Декларируем шаблон для всех функций
    // компилятор сам сделает нужное количество функций с заданными параметрами
    template<int I>
    void Group1_ON_i()    {
      Group1_ON(I);
    }

    // далее в коде регистрируем функции
    // в угловых скобках желаемый параметр
    // компилятор сделает функцию Group1_ON_i<1>,
    // в которой будет вызываться функция Group1_ON(1);
      K1.attach_function(1, Group1_ON_i<1>);

    // компилятор сделает функцию Group1_ON_i<9>,
    // в которой будет вызываться функция Group1_ON(9);
      K9.attach_function(1, Group1_ON_i<9>);

     
    Это чтобы в ручную не плодить декларации нужных функций -- пусть компилятор за нас поработает.
     
    clkid нравится это.