Помогите разобраться в коде (указатели, копирование данных и т.п.)

ustas
Offline
Зарегистрирован: 12.03.2012

Есть два устройства на ардуино, общаются по беспроводной технологии.

Для "общения" объявлены структуры:

typedef struct _AS_ANSWER
{
	byte   Status; //Статус
	float  Value; //Значение
	byte   Comment[CommentLen]; //Описание
}AS_Answer;

typedef struct _AS_SENSORSTATUS
{
	byte   Status; //Статус
	float  Value; //Значение
	byte   Comment[CommentLen]; //Описание
}AS_SensorStatus;

СommentLen - определена (20, для определенности).

На стороне передатчика есть вот такой массив:

AS_SensorStatus MySensors[NumSensors] = {
  0,0,"DHT_temp(C)",
  0,0,"DHT_hidm(%)",
  0,0,"Batt_pow(V)",
  0,0,"Moisture(?)"};

И при передаче используется вот такой код:

        MyAnswer.Status = MySensors[MyCommand.Parametr].Status;
        MyAnswer.Value  = MySensors[MyCommand.Parametr].Value;    
        memcpy(&MyAnswer.Comment,&MySensors[MyCommand.Parametr].Comment, CommentLen);

Теперь перейдем к приемнику... Когда данные приходят их просто пуляем на ком-порт (или выводим на дисплей, суть не в этом):

Serial.print(MyAnswer.Value);
Serial.print((char *)MyAnswer.Comment);

А теперь собственно, сама проблема: комментарий не выводится.

Числовые данные передаются без проблем (статусы и значения), а вот строки - еще ни разу не видел. К сожалению, сам с этим пока разобратся не могу, поэтому прошу "помощь зала".

leshak
Offline
Зарегистрирован: 29.09.2011

 Похоже дело не в выводе коментария, а в том как данные отправляются/принимаются.

Вот такой код

#define CommentLen 20

typedef struct _AS_ANSWER
{
	byte   Status; //Статус
	float  Value; //Значение
	byte   Comment[CommentLen]; //Описание
}AS_Answer;

_AS_ANSWER ans;

byte testText[]="my test comment";




void setup(){
  Serial.begin(9600);
    Serial.println("Ready");



  memcpy(ans.Comment,testText,CommentLen);
  
  //Убеждаемся что копирование прошло правильно
  for(int i=0;i<CommentLen;i++){
    Serial.print(testText[i]);
    Serial.print("=");
    Serial.print(ans.Comment[i]);
    Serial.print(",  ");
  }
  
  Serial.println();
  Serial.println("Try output1");
  Serial.println((char *)ans.Comment);
}

void loop(){
}

 

У меня нормально выводит "my test comment".

Как видите, при memcpy (строка 23) я не использовал &, но и с ним - работает также. Видимо компилятор сам догадывается о его необходимости.

Кстати, если поле коммент, объявить не как "byte Comment[CommentLen]", а "char byte Comment[CommentLen]", то можно будет выводить просто  "Serial.println(ans.Comment);" без необхоимости засорять код "char *".

Если это текст, символы, то зачем его объявлять byte?

 

Вообщем нужно смотреть как "отправляет/принимает". Особено "отправляет".

Направления "копания":

  1. Когда вы объявляете в тексте строку типа a="my text", то компилятор, в неявном виде добавляет в конце \0. То есть в реальности  строка на один символ больше чем вы написали (то есть "my text" имеет длину 8, а 7-мь символов).
  2. Когда вы заполняете массив MySensors, есть подозрение что тексты не "дополняются" до полной длинны. То есть данные и текст второго сенсора, в памяти, "влазят" в комментарий первого сенсора. Возможно строки коментариев нужно "дополнять" до длинны CommentLen (учитывая предыдущий пункт). 
  3. Опять таки, нужно смотреть как вы "читаете". Возможно комментарий просто не передатся, а вы уже пытаетесь его вывести.

Цитата:

СommentLen - определена (20, для определенности).

Набрать тут в имени переменной первую букву  русской эС, вместо латинской Cи - это был тонкий садизм. Взял copy-past-том и чуть мозги не вывихнул пытась понять почему же "константа не определена". 

 

 

ustas
Offline
Зарегистрирован: 12.03.2012

leshak пишет:

 Похоже дело не в выводе коментария, а в том как данные отправляются/принимаются. 


Так и оказалось - проблема была в том, что отправлялась посылка меньшей длинны, поэтому комментарию банально н хватало "места" при отправке.
leshak пишет:
 

Кстати, если поле коммент, объявить не как "byte Comment[CommentLen]", а "char byte Comment[CommentLen]", то можно будет выводить просто  "Serial.println(ans.Comment);" без необхоимости засорять код "char *".

Если это текст, символы, то зачем его объявлять byte?


Это связано с тем, что передатчик отправляет именно байты:

Mirf.send((byte *) &MyAnswer);

leshak пишет:
 

Вообщем нужно смотреть как "отправляет/принимает". Особено "отправляет".

Направления "копания":

  1. Когда вы объявляете в тексте строку типа a="my text", то компилятор, в неявном виде добавляет в конце \0. То есть в реальности  строка на один символ больше чем вы написали (то есть "my text" имеет длину 8, а 7-мь символов).
  2. Когда вы заполняете массив MySensors, есть подозрение что тексты не "дополняются" до полной длинны. То есть данные и текст второго сенсора, в памяти, "влазят" в комментарий первого сенсора. Возможно строки коментариев нужно "дополнять" до длинны CommentLen (учитывая предыдущий пункт). 
  3. Опять таки, нужно смотреть как вы "читаете". Возможно комментарий просто не передатся, а вы уже пытаетесь его вывести.

Цитата:

СommentLen - определена (20, для определенности).

Набрать тут в имени переменной первую букву  русской эС, вместо латинской Cи - это был тонкий садизм. Взял copy-past-том и чуть мозги не вывихнул пытась понять почему же "константа не определена".  

Это я не специально, сорри :)

Спасибо за помощь! Направления мысли были очень правильные!

leshak
Offline
Зарегистрирован: 29.09.2011

ustas пишет:

leshak пишет:

Кстати, если поле коммент, объявить не как "byte Comment[CommentLen]", а "char byte Comment[CommentLen]", то можно будет выводить просто  "Serial.println(ans.Comment);" без необхоимости засорять код "char *".

Если это текст, символы, то зачем его объявлять byte?


Это связано с тем, что передатчик отправляет именно байты:

Это не важно. Принимающий скетч все равно ничего не знает об типах данных в отправляющем.

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

Когда вы в Serial.println передаете массив byte ans.Comment[], и впереди дописываете (char *), вы, фактически говорите: "вот массив. это массив символов. я раньше, зачем-то, сказал что там будут числовые значения, но в данном случае не обращай внимания на то что я говорил раньше. их нужно обрабатывать как символы". Поэтому можно сразу сказать "тут будут символы".

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

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