Используя Wire.onRequest, передав метод класса? - PullRequest
0 голосов
/ 16 февраля 2019

У меня есть эскиз Arduino, который будет работать на Arduino UNO, и я пытаюсь заставить uno общаться через соединение i2c с малиновым пи.Проблема заключается в использовании библиотеки wire.h , где метод Wire.onRequest работает нормально, когда я использую его следующим образом.

#include <Wire.h>
#define COMM_DELAY 50
#define SLAVE_ADDRESS 0x04

int current_rule = 0;

void initI2c() {
  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);

  // define callbacks for i2c communication
  Wire.onReceive(receiveData);
}

// callback for received data
void receiveData(int byteCount) {
  while (Wire.available()) {
    current_rule = Wire.read();
  }
}

, но когда я пытаюсь получить этот точный результат с классомметод, я получаю сообщение об ошибке: invalid use of non-static member functionWire.onRequest(this->receiveData) строка становится отмеченной красным)

Точно так же:


void (*funptr)();
typedef void (*Callback)(byte);
class Comm{
public:
  int callback_list_size = 0;
  bool option_debug;
  byte option_address;
  int option_comm_delay;
  void(*callback_list[256]);
  byte *rules;

  // function for receiving data. raspberry -> arduino
  // Whenever the master sends new data, this method will call the appropriate callback.
  void receiveData()
  {
    byte data;
    Serial.println("[INFO] Received new data from master");
    while (Wire.available())
    {
      data = Wire.read();
    }
    for (int i = 0; i < callback_list_size; i++)
    {
      if (rules[i] == data){
        funptr = callback_list[i];
        funptr();
        }
    }
  }

  // function for sending data. Called when raspberry request data. arduino -> raspberry
  // Whenever the master requests data, this method will be called. For now we don't need this but anyway.
  void sendData(int s)
  {
    if (option_debug)
      Serial.println("[INFO] Master requests data!");
  }

  /* Constructor that takes 3 parameters at max. Only the adress is mandatory others are optional and will be filled with default values
     :address - adress of slave(arduino) - Example 0x04
     :delay - a delay is needed because I2C clock is quite slow compared to the CPU clock - 50
     :debug - for debug purposes if true debug info will be sent to Serial interface - true/false 
  */
  Comm(byte address, int delay = 50, bool debug = false)
  {
    option_address = address;
    option_comm_delay = delay;
    option_debug = debug;
    if (debug)
      Serial.println("[INFO] Comm Object Created!");
  }

  // Function needs to be called to initialize the communication channel.
  void initI2c()
  {
    Wire.begin(option_address);
    Wire.onReceive(this->sendData);
    Wire.onRequest(this->receiveData);
    if (option_debug)
      Serial.println("[INFO] I2C channel initialized");
  }

  // Function to add new callback for a rule.
  // This function returns id of passed callback
  int addCallback(Callback func, byte rule)
  {
    callback_list_size++;
    // Enlarge rules array to keep 1 more byte
    byte *temp = new byte[callback_list_size];       // create new bigger array.
    for (int i = 0; i + 1 < callback_list_size; i++) // reason fo i+1 is if callback_list_size is 1 than this is the first initializition so we don't need any copying.
    {
      temp[i] = rules[i]; // copy rules to newer array.
    }
    delete[] rules; // free old array memory.
    rules = temp;   // now rules points to new array.
    callback_list[callback_list_size - 1] = &func;
    rules[callback_list_size - 1] = rule;
    return callback_list_size;
  }
};

Comm *i2c_comm;
void loop()
{
}
void setup()
{
  Serial.begin(9600);
  initI2C();
}


void initI2C()
{
  i2c_comm = new Comm(0x04, 50, true);
  i2c_comm->initI2c();

  //Callback Definitions
  i2c_comm->addCallback(&rule_1, 0x01);
      i2c_comm->addCallback(&rule_2, 0x02);
          i2c_comm->addCallback(&rule_3, 0x03);
              i2c_comm->addCallback(&rule_4, 0x04);
}

Я также пытался сделать receiveDataметод быть статичным.Но в этом случае у меня появляется ошибка, подобная этой: invalid use of member Com::callback_list_size in static member function

, которая имеет смысл для меня, так как статический метод не будет знать, о каком callback_list_size я говорю.

, поэтому я в замешательствео том, как я могу справиться с такой проблемой?

1 Ответ

0 голосов
/ 16 февраля 2019

Ты почти у цели.Вообще говоря, в C ++ вам нужно передать метод статического класса для функций обратного вызова.

Ошибка, которую вы получили после изменения метода на статический, ожидается, когда вы пытаетесь получить доступ к члену экземпляра класса Comm , что не может быть сделанов статическом методе, в котором нет 'this'.

Вот один из многих методов, которые следует рассмотреть, но, пожалуйста, прочтите статью SO Использование функции-члена класса C ++ в качестве функции обратного вызова C .

В любом случае, подход заключается в том, чтобы использовать статический указатель на экземпляр .

class Comm {
private:
    static Comm* pSingletonInstance;

    static void OnReceiveHandler() {
        if (pSingletonInstance)
            pSingletonInstance->receiveData();
    }
    static void OnSendHandler(int s) {
        if (pSingletonInstance)
            pSingletonInstance->sendData(s);
    }
    void initI2c() {
        Comm::pSingletonInstance = this; // Assign the static singleton used in the static handlers.
        Wire.onReceive(Comm::OnSendHandler);
        Wire.onRequest(Comm::OnReceiveHandler);
        Wire.begin(option_address);
    }
}
// static initializer for the static member.
Comm* Comm::pSingletonInstance = 0;

Опять же есть множество способов обойти этоПроблема, но выше, является простой и, вероятно, подходит для вашего проекта.Если вам нужно управлять несколькими экземплярами Comm, вам придется сделать что-то совсем другое.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...