Форум Микро-Чип
Поиск и заказ электронных компонентов
 

Вернуться   Форум Микро-Чип > Cетевые протоколы и технологии

Cетевые протоколы и технологии TCP/IP стек

Ответ
 
Опции темы Опции просмотра
Старый 12.08.2016, 17:58   #1
_Alexandr_
Member
 
Регистрация: 28.11.2013
Сообщений: 43
Вес репутации: 100/13
_Alexandr_ will become famous soon enough_Alexandr_ will become famous soon enough
Exclamation LwIP_не работает callback function

Доброго времени суток!

Хочу написать RTP клиент на основе LwIP. Как положено, написал функцию обратного вызова (callback function), в которой буду разгребать пакет после UDP:
Код:
void rtp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
if (Tone == 0)
{
Tone += 2;
pbuf_free(p);
}
}
Назначил порт, в который будет приходить RTP трафик, и привязал функцию к этому порту:
Код:
void rtp_init(void)
{
rtp_pcb = udp_new();

if (rtp_pcb != NULL)
{
udp_recv(rtp_pcb, rtp_recv, (void *)UDP_PORT_RTP);
udp_bind(rtp_pcb, IP_ADDR_ANY, UDP_PORT_RTP);
}
}
При отправке пакета функция вызывается и работает. При повторной отправке того же пакета стек застревает где-то на MAC уровне и приём пакетов прекращается. SNMP и пинг в моём проекте работают, но после отправки RTP пакета пакеты не принимаются.

Пробовал изменить настройки стека в части памяти: увеличил MEMP_NUM_PBUF - не работает; увеличил MEM_SIZE, сократил PBUF_POOL_BUFSIZE - то же самое.

Англоязычные сайты говорят: The callback function is responsible for deallocating the pbuf. Я использую pbuf_free. У коллег, писавших свои обработчики RTP, при таком подходе работает.

Использую "голый" LwIP (без операционки), функция-обработчик описана и привязана в отдельном файле.

Подскажите, в каком направлении копать. LwIP`ом пользуюсь впервые.

Последний раз редактировалось _Alexandr_; 12.08.2016 в 18:12.
_Alexandr_ вне форума   Ответить с цитированием
Старый 15.08.2016, 09:52   #2
Рак
Senior Member
 
Регистрация: 02.04.2008
Адрес: Кременчуг
Возраст: 31
Сообщений: 1,239
Вес репутации: 2022/65
Рак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond reputeРак has a reputation beyond repute
По умолчанию Re: LwIP_не работает callback function

Сильно не вникал, но глянул свой код, у меня первой вызывается udp_bind а потом udp_recv в инициализации. Может это?
Рак вне форума   Ответить с цитированием
Старый 22.08.2016, 07:14   #3
_Alexandr_
Member
 
Регистрация: 28.11.2013
Сообщений: 43
Вес репутации: 100/13
_Alexandr_ will become famous soon enough_Alexandr_ will become famous soon enough
По умолчанию Re: LwIP_не работает callback function

Сначала тоже на это грешил. Оказалось, что ставил точку останова так, что программа до неё доходила только раз за время выполнения.

Ещё вопрос к знатокам LwIP`а. Допустим, мне приходит сообщение. Я должен поменять первый байт заголовка и вернуть соообщение отправителю. С этим проблем нет.

Теперь задача сложнее. При определённом формате сообщения мне нужно вдобавок ответить отправителю (послать ещё одно сообщение). Почему-то отправляется только одно сообщение (с изменённым первым байтом). Пока отправляю то же сообщение, что и принял. После отправки второго сообщения очищаю буфер (pbuf_free(p)). Посмотрел отладчиком - проблем не обнаружил.

Возможно ли отправить два подряд сообщения не очищая буфер? Может есть какие-то настройки для этого? Или нужно формировать буфер по новой? Какими функциями пользоваться в этом случае?
_Alexandr_ вне форума   Ответить с цитированием
Старый 23.08.2016, 13:19   #4
_Alexandr_
Member
 
Регистрация: 28.11.2013
Сообщений: 43
Вес репутации: 100/13
_Alexandr_ will become famous soon enough_Alexandr_ will become famous soon enough
По умолчанию

Вопрос создания и отправки буфера решился просто:
Код:
p = pbuf_alloc(PBUF_TRANSPORT, 13, PBUF_RAM);
memcpy(p->payload, xml_mess, 13);
udp_sendto(xml_pcb, p, addr, port);
pbuf_free(p);
Получение сообщения и отправка ответа происходят стабильно. Для определения типа сообщения пользовался стандартной функцией strstr. До того, как создавал свой pbuf, работало как надо, теперь отказывается. Почему - ума не приложу.

Для создания своего сообщения пользовался strcat, но она записывала данные начиная с первого попавшегося символа 0x00 (в ASCII). Пока не получилось заставить её писать куда надо, поэтому пользуюсь memcpy.

Вот полный текст моей функции. Может что посоветуете:
Код:
void xml_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
char xml_mess[100];  // в сумме максимум 97 байт
memcpy(xml_mess, p->payload, p->len); 
pbuf_free(p);

if (xml_mess[0] == 0x53)
{
xml_mess[0] = 0x4B;
p = pbuf_alloc(PBUF_TRANSPORT, 13, PBUF_RAM);
memcpy(p->payload, xml_mess, 13);
udp_sendto(xml_pcb, p, addr, port);
pbuf_free(p);

// _____ДО СЮДА ВСЁ РАБОТАЕТ СТАБИЛЬНО_____

if (strstr(xml_mess, TxDataLoaded) != NULL)
{
  xml_mess[0] = 0x53; // создать сообщение
  
  memcpy(xml_mess + 13, Teg_Mess, strlen(Teg_Mess));
  memcpy(xml_mess + 13 + strlen(Teg_Mess), StopSendingData, strlen(StopSendingData));
  memcpy(xml_mess + 13 + strlen(Teg_Mess) + strlen(StopSendingData), Teg_Mess_End, strlen(Teg_Mess_End));
  
 // начало сообщения - "S" (0x53), конец сообщения - ">" (0x3E)

  p = pbuf_alloc(PBUF_TRANSPORT, strrchr(xml_mess, 0x3E) - strchr(xml_mess, 0x53), PBUF_RAM);
  memcpy(p->payload, xml_mess, strrchr(xml_mess, 0x3E) - strchr(xml_mess, 0x53));

  udp_sendto(xml_pcb, p, addr, port); // и отправить его
  pbuf_free(p);
}
else {;} 
}
}
_Alexandr_ вне форума   Ответить с цитированием
Старый 25.08.2016, 12:23   #5
Petr
Senior Member
 
Аватар для Petr
 
Регистрация: 25.02.2007
Возраст: 46
Сообщений: 1,734
Вес репутации: 3438/88
Petr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond reputePetr has a reputation beyond repute
По умолчанию Re: LwIP_не работает callback function

Цитата:
Сообщение от _Alexandr_ Посмотреть сообщение
До того, как создавал свой pbuf, работало как надо, теперь отказывается. Почему - ума не приложу.
Я не пользовался пока функцией udp_sendto
Но предполагаю, что она работает точно так же,
как и все функции отправки пакетов в LwIP - ставит пакет в очередь на отправку,
но не отправляет немедленно!!!
Поэтому после выгрузки pbuf из памяти следующим оператором отправлять больше нечего.
Petr вне форума   Ответить с цитированием
Старый 25.08.2016, 15:01   #6
_Alexandr_
Member
 
Регистрация: 28.11.2013
Сообщений: 43
Вес репутации: 100/13
_Alexandr_ will become famous soon enough_Alexandr_ will become famous soon enough
По умолчанию Re: LwIP_не работает callback function

Цитата:
Сообщение от Petr Посмотреть сообщение
Я не пользовался пока функцией udp_sendto
Но предполагаю, что она работает точно так же,
как и все функции отправки пакетов в LwIP - ставит пакет в очередь на отправку, но не отправляет немедленно!!!
У меня длина очереди 1 пакет. Да и не в этом было дело. Я пользовался функцией strstr, которая работает со строками, а в качестве одного из аргументов передавал в нее массив xml_mess, поэтому она возвращала NULL. До этого писал иначе, но не помню как.

В принципе можно определять тип сообщения путем проверки значений отдельных элементов xml_mess, благо я знаю, где должна находиться интересующая меня информация. Метод примитивный, но работающий. Теперь все отправляется как надо, оба сообщения.
_Alexandr_ вне форума   Ответить с цитированием
Старый 08.09.2016, 17:49   #7
_Alexandr_
Member
 
Регистрация: 28.11.2013
Сообщений: 43
Вес репутации: 100/13
_Alexandr_ will become famous soon enough_Alexandr_ will become famous soon enough
По умолчанию Re: LwIP_не работает callback function

Неожиданно столкнулся с проблемой. При получении сообщения типа BeginLoadTxData отправляется квитанция (как и должно быть), при последующем получении запроса состояния буфера отправляется только квитанция (должен отправляться ещё и ответ).

Если сначала получаю запрос состояния буфера, то отправляю квитанцию и ответ, как должно быть. Если сначала получаю сообщение типа TxDataLoaded, всё тоже работает как надо.

Сообщения типа BeginLoadTxData и TxDataLoaded на первый взгляд обрабатываю одинаково. Может кто заметит ошибку?

Код:
#include <udp.h>
#include <string.h>
#include <xml.h>
#include <pbuf.h>
#include <ip.h>

const char BeginLoadTxData[] = "<COND_SEND>1";
// Запрос состояния буфера определять путём анализа заголовка сообщения (0x48 в определённом месте)
const char TxDataLoaded[] = "<COND_SEND>2";

const char Teg_Mess[] = "<MESS>";
const char Teg_Mess_End[] = "</MESS>";
const char BeginSendingData[] = "<COND_SEND>3</COND_SEND>";
const char StopSendingData[] = "<COND_SEND>4</COND_SEND>";
const char Teg_Cond_Buffer[] = "<COND_BUFFER>";
const char Teg_Cond_Buffer_End[] = "</COND_BUFFER>";

// Хранятся в xml_mess[2]
unsigned char CondBufMessNum;         // номер сообщения о состоянии буфера
unsigned char CondBufMessNumEnd;      // номер сообщения о состоянии буфера в конце обмена

// для временного хранения типа и номера устройства отправителя
char TempSenderType;       // тип устройства отправителя - xml_mess[5]
char TempSenderNum;        // номер устройства отправителя - xml_mess[6]

s8_t n; // длина XML сообщения (использовать len или tot_len payload`а?)
char xml_mess[100];  // заголовок + тело XML-сообщения в сумме максимум 97 байт
u16_t CurrentPort;   // хранит номер UDP- порта для отправки сообщения после опустошения буфера SSC
struct ip_addr *CurrentAddr;

struct udp_pcb *xml_pcb;

#define UDP_PORT_XML 10011

void xml_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
CurrentPort = port;
CurrentAddr->addr = addr->addr;

memcpy(xml_mess, p->payload, p->len);  // скопировать строку
pbuf_free(p);

// если пришло сообщение
if (xml_mess[0] == 0x53)
{
// сформировать квитанцию
xml_mess[0] = 0x4B;

// как оставить в payload`е только 13 байт XML-заголовка?
p = pbuf_alloc(PBUF_TRANSPORT, 13, PBUF_RAM);
memcpy(p->payload, xml_mess, 13);

udp_sendto(xml_pcb, p, addr, port);   // и отправить её
pbuf_free(p);


// проанализировать содержимое сообщения - вдруг нужно ответить?

// если началась загрузка данных для передачи (<COND_SEND>1)
if ((xml_mess[19] == 0x3C) && (xml_mess[20] == 0x43) && (xml_mess[21] == 0x4F) && (xml_mess[22] == 0x4E) &&
    (xml_mess[23] == 0x44) && (xml_mess[24] == 0x5F) && (xml_mess[25] == 0x53) && (xml_mess[26] == 0x45) &&
    (xml_mess[27] == 0x4E) && (xml_mess[28] == 0x44) && (xml_mess[29] == 0x3E) && (xml_mess[30] == 0x31))
{;}

else if (xml_mess[1] == 0x48)// если запрос состояния буфера
{
  // сформировать сообщение о состоянии буфера
  xml_mess[0] = 0x53;
  
  // изменить номер сообщения
  if (xml_mess[2] == 0xFF)
    xml_mess[2] = 0x00;
  else
    xml_mess[2]++;
  CondBufMessNum = xml_mess[2];
  
  // поменять местами тип и номер устройств отправителя и получателя
  TempSenderType = xml_mess[5]; // запомнить тип отправителя
  TempSenderNum = xml_mess[6];  // запомнить номер отправителя
  xml_mess[5] = xml_mess[3];
  xml_mess[6] = xml_mess[4];    // теперь я отправитель
  xml_mess[3] = TempSenderType;
  xml_mess[4] = TempSenderNum;  //
  
  // добавить тело XML-сообщения к его заголовку
  n = 13;
  
  memcpy(xml_mess + n, Teg_Mess, strlen(Teg_Mess));
  n += strlen(Teg_Mess);
  memcpy(xml_mess + n, Teg_Cond_Buffer, strlen(Teg_Cond_Buffer));
  n += strlen(Teg_Cond_Buffer);
  
  xml_mess[n] = 0;
  n++;
  
  memcpy(xml_mess + n, Teg_Cond_Buffer_End, strlen(Teg_Cond_Buffer_End));
  n += strlen(Teg_Cond_Buffer_End);
  
  memcpy(xml_mess + n, Teg_Mess_End, strlen(Teg_Mess_End));
  n += strlen(Teg_Mess_End);
  
  p = pbuf_alloc(PBUF_TRANSPORT, n, PBUF_RAM);
  memcpy(p->payload, xml_mess, n);
  
  udp_sendto(xml_pcb, p, addr, port); // и отправить его
  pbuf_free(p);
}

// если информация на передачу загружена (<COND_SEND>2)
else if ((xml_mess[19] == 0x3C) && (xml_mess[20] == 0x43) && (xml_mess[21] == 0x4F) && (xml_mess[22] == 0x4E) &&
         (xml_mess[23] == 0x44) && (xml_mess[24] == 0x5F) && (xml_mess[25] == 0x53) && (xml_mess[26] == 0x45) &&
         (xml_mess[27] == 0x4E) && (xml_mess[28] == 0x44) && (xml_mess[29] == 0x3E) && (xml_mess[30] == 0x32))
{;}

else {;}  // сообщения других типов ко мне не приходят

} // конец обработки сообщений


//  если пришла квитанция
else if (xml_mess[0] == 0x4B)
{
 // если это квитанция на сообщение о состоянии буфера
 if (xml_mess[2] == CondBufMessNum)
 {;}  
 
 // если это квитанция на сообщение о состоянии буфера в конце обмена
 else if (xml_mess[2] == CondBufMessNumEnd)
 {;}
 
 else {;} // другие квитанции ко мне не приходят
}

else {;} // ко мне приходят только сообщения или квитанции
}


void xml_init(void)
{
xml_pcb = udp_new();
if (xml_pcb != NULL)
{
udp_recv(xml_pcb, xml_recv, (void *)UDP_PORT_XML);
udp_bind(xml_pcb, IP_ADDR_ANY, UDP_PORT_XML);
}
}
_Alexandr_ вне форума   Ответить с цитированием
Ответ

Метки
callback function, lwip, udp


Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 
Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
12F675, работает не так, как запрограммировано oleg-star Вопросы начинающих 11 30.11.2014 19:31
Проблема mikroC + OSA? Gera82 Продукция MICROCHIP 49 23.09.2009 15:14
dsPICDEM 2 Евгений Новый Продукция MICROCHIP 34 31.12.2008 00:56
modbus and ccs picc gladkih Вопросы начинающих 1 03.10.2008 09:34
Глюк с выходом из SLEEP по TMR1IF Yura333 Продукция MICROCHIP 6 08.04.2008 11:58


Часовой пояс GMT +3, время: 16:30.


Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd. Перевод: zCarot