Помогите с кодом

pilnikov
pilnikov аватар
Offline
Зарегистрирован: 28.08.2015

народ, подскажите пожалуйста новичку как правильно вызвать функцию, параметром для которой являются несколько структур

моя подпрограмма

bool Rcv (byte node, uint8_t type) {
  bool ok = false;
  network.update();
  RF24NetworkHeader header(node, type);

  if      (type == TYPE_PING)   ok = network.read(header, p, sizeof(p));
  else if (type == TYPE_METEO1) ok = network.read(header, s, sizeof(s));
  else if (type == TYPE_TABLO1) ok = network.read(header, t, sizeof(t));
  else if (type == TYPE_TIME1)  ok = network.read(header, c, sizeof(c));

  Serial.print("Read from ");
  Serial.print(node, HEX);
  Serial.print(" type ");
  Serial.print(type, HEX);
  if (ok)Serial.println(" OK");
  else   Serial.println(" Fail");
  return ok;
}

здесь p, s, t, c - указатели на 4 различные структуры.

как избавиться от перечислителя, подставив структуру как параметр?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не до конца понял, чего Вы хотите.

Вы хотите написать некую функцию, которую можно вызывать с любым из значений p, s, t, c?

Или Вы хотите ЭТОЙ функции передавать параметром одно из p, s, t, c ?

------------

Кстати, если  p, s, t, c действительно указатели, то Ваша sizeof(c) означает не размер структуры с, а размер указателя (т.е. всегда 2). Если Вы хотите, чтобы там был размер стрктуры, то пишите  sizeof(*c).

pilnikov
pilnikov аватар
Offline
Зарегистрирован: 28.08.2015

хотим ЭТОЙ функции передавать параметром одно из p, s, t, c 

pilnikov
pilnikov аватар
Offline
Зарегистрирован: 28.08.2015

чтобы было примерно так 

ok = network.read(header, param, sizeof(*param));

где param - параметр (структура), указываемая в вызывающей подпрограме

Rcv(0x2, TYPE_METEO1, param)

так примерно

чтобы избавиться от 4 строк

  if      (type == TYPE_PING)   ok = network.read(header, p, sizeof(p));
  else if (type == TYPE_METEO1) ok = network.read(header, s, sizeof(s));
  else if (type == TYPE_TABLO1) ok = network.read(header, t, sizeof(t));
  else if (type == TYPE_TIME1)  ok = network.read(header, c, sizeof(c));

заменив их одной 

ok = network.read(header, param, sizeof(*param));

 

Radjah
Offline
Зарегистрирован: 06.08.2014

Прочитай про switch...case еще. ;)

Ну и передавай тогда type и твой param в параметрах. Или количество параметров критично?

pilnikov
pilnikov аватар
Offline
Зарегистрирован: 28.08.2015

switch case не при делах, количество параметров не критично.

я не умею правильно написать вызов 

разжуйте на примере

для этой конструкции необходимы заголовок (header) сообщение (param) и макс размер сообщения (sizeof (*param)

network.read(header, param, sizeof(*param));

т.к. сообщения в моем случае м.б. разными я и хочу их передавать функции rcv как параметры  

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Самое тупое передавать указатель на структуру и её длину, поскольку длина и есть sizeof. Однако нам по барабану какая структура.
Указатель может быть передан, например как byte * или char *
Это навскидку
UPD и да, тип передавать не нужно.

pilnikov
pilnikov аватар
Offline
Зарегистрирован: 28.08.2015

пример приведите пожалуйста

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

pilnikov, есть много способов это сделать и у каждого свои ++ и --. Рассмотрим два способа.

Способ 1 (как Вам советовал kisoft)

В функции объявляем, что она принимает универсальный указатель "на что-нибудь", а при вызове передаём реальный указатель и длину структуры.

struct S {                  
    int field;
//	la-la-la
} * s;

struct P {                  
    char c;
//	la-la-la
} * p;

void MyFunction(void *p, int nSize) {
	// здесь нам пофиг что за структура, 
	// знаем только, что p указывает на буфер длины nSize
	// la-la-la
}

void setup() {
	// Правильные вызовы выглядят так
	MyFunction(p, sizeof(*p));
	MyFunction(s, sizeof(*s));

	// А вот такие вызовы компилятор пропустит, но у нас буду с ними проблемы
	MyFunction(p, sizeof(*s));
	MyFunction(0, sizeof(*s));

//...
}


void loop() {
//...
}

Плюсы этого метода: никакого дополнительного кода, всё чисто.

Минусы: мы выключили механизм контроля типа и если по ошибке передадим функции вместо указателя что-то недопустимое (или просто передадим указатель на одну структуру, а sizeof по ошибке напишем от другой), то компилятор это пропустит и Вам придётся вылавливать труднодиагностируемую ошибку при выполнении.

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

Второй способ

сохраняет котроль типов и делает это за счёт т.н. "перегрузки операций". Т.е. мы объявляем несколько функций с одинаковым именем и разными параметрами. Компилятор сам разберётся какую вызывать (по типу аргумента), а если мы передадим левый тип - будет сильно ругаться и т.о. убережёт нас от поиска ошибки времени выполнения. Смотрите.

struct S {                  
    int field;
//	la-la-la
} * s;

struct P {                  
    char c;
//	la-la-la
} * p;

void MyFunction(struct P *ptr) {	// 1
	// здесь работаем только со структурой P
	// её длина нам известна, - sizeof(struct P)
	// la-la-la
}
void MyFunction(struct S *ptr) {	// 2
	// здесь работаем только со структурой S
	// её длина нам известна, - sizeof(struct S)
	// la-la-la
}

void setup() {
	// Правильные вызовы выглядят так
	MyFunction(p);	// вызовется 1
	MyFunction(s);	// вызовется 2

	// А вот такие вызовы обругает компилятор
	int n;
	MyFunction(&n);
	MyFunction(0);

//...
}


void loop() {
//...
}

Минус тут - лишний код.

Выбирайте.

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Можно объединить оба метода. Сделать универсальную функцию и вызывать её из оберток второго метода, плюс обёртки сделать инлайном, тогда вообще будет шоколад.

pilnikov
pilnikov аватар
Offline
Зарегистрирован: 28.08.2015

вообщем начал пробовать

функция слегка преобразилась и стала такой

bool Lnk (bool mode, byte node, uint8_t type, void *u, int nSize) {
  bool ok = false;
  network.update();
  RF24NetworkHeader header(node, type);
  if (mode) {
    ok = network.write(header, u, nSize);
    Serial.print("Send to ");
  }
  else      {
    ok = network.read (header, u, nSize);
    Serial.print("Read from ");
  }

  Serial.print(node, HEX);
  Serial.print(" type ");
  Serial.print(type, HEX);
  Serial.print(" Size ");
  Serial.print(nSize, DEC);
  if (ok) Serial.println(" OK");
  else    Serial.println(" Fail");
  return ok;
}

вызов этой функции

void loop() {

  //Отправляем инфу часовым клиентам (NRF24L01)

  if ( millis() - int1 < 0 || millis() - int1 > 20000 ) {
    int1 = millis();
    p->Pn = 5;
    Lnk(true, 0x2, TYPE_PING, p, sizeof(*p));
    if (Lnk(false, 0x2, TYPE_METEO1, s, sizeof(*s))) snrDisplay();
  }
  if ( millis() - int2 < 0 || millis() - int2 > 25000 ) {
    int2 = millis();

    c->Time = now();
    
    digitalClockDisplay();
    
    Lnk(true, 0x3, TYPE_TIME1,  c, sizeof(*c));
    Lnk(true, 0x4, TYPE_TIME1,  c, sizeof(*c));
    Lnk(true, 0x4, TYPE_METEO1, s, sizeof(*s));
    Lnk(true, 0x4, TYPE_TABLO1, t, sizeof(*t));
  }
}

результат работы

Current System Time Is...18:58:14 29 8 2015
Send to 3 type 20 Size 4 Fail
Send to 4 type 20 Size 4 OK
Send to 4 type 11 Size 20 OK
Send to 4 type 13 Size 20 OK
Send to 2 type 1 Size 1 Fail
Read from 2 type 11 Size 20 Fail
 
вроде работает
спасибо за подсказки огромное
еще хотелочка махотная -  как в консоль вывести имя структуры (чтобы окончательно убедиться что все правильно работает)
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так имя Вы уже потеряли, Вы ведь решили передавать только указатель и длину структуры. Если длины разные - выводите длину и убеждайтесь по ней. Или заведите ещё параметр и передавайте имя как строку.

pilnikov
pilnikov аватар
Offline
Зарегистрирован: 28.08.2015

ну и бог с ним с именем 

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

У Вас есть тип, это и есть имя, нет?

pilnikov
pilnikov аватар
Offline
Зарегистрирован: 28.08.2015

нет немного не так

#ifndef ClassCoder_h
#define ClassCoder_h

// Адрес NRF24L01 для сервера
const uint16_t nrf24_server_node = 0x0;
const uint8_t  nrf24_channel     = 90;

// Адреса узлов
const uint16_t nrf24_chasy_node = 0x3;
const uint16_t nrf24_sensor_node = 0x2;
const uint16_t nrf24_tablo_node = 0x4;

// Адреса 1-10 сенсоры температуры

// Тип пакета RF24NetworkHeader.type
#define TYPE_PING        0x01  //Пакет с PING
#define TYPE_METEO1      0x11  //Метеосенсор 1-го типа
#define TYPE_TABLO1      0x13  //Погода из интернета
#define TYPE_TIME1       0x20  //Время

//Структура данных для проверки доступности абонента
struct TSPng {
  uint8_t       Pn;      //Номер пакета
}*p;

//Структура данных для метеосенсора
struct TSSnr {
  float         iT;      //Температура (внутри)
  float         P;       //Давление
  float         iH;      //Влажность (внутри)
  float         oT;      //Температура (снаружи)
  float         oH;      //Влажность (снаружи)
}*s;

//Структура данных для часов
struct TSClk {
  time_t        Time;    //Время
}*c;

//Структура данных для табла
struct TSTbl {
  float         pT;      //Температура (прогноз)
  float         pP;      //Давление (прогноз)
  float         pH;      //Влажность (прогноз)
  unsigned long wind;    //Направление и скорость ветра
  unsigned long prec;    //Осадки и облачность
}*t;
#endif