lwIP: вывод отладочных сообщений |
Добавил(а) microsin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Есть несколько разных методов, обычно используемых для отладки lwIP, стиля printf и с использованием внешнего отладчика. [Внешний отладчик] Возможно самый очевидный метод поиска проблем, связанных с сетевым стеком - с помощью отладчика / точки останова начать пошаговую отладку выполняемого кода. Однако поскольку lwIP обычно используется для встраиваемых платформ (микроконтроллеров) с ограниченным объемом ресурсов, то в случае включенной оптимизации запустить отладку по исходному коду может быть затруднительно. Кроме того, должен быть специально реализован способ соединения отладчика с отлаживаемой системой. Часто это решается через сетевое соединение, когда работает сетевой стек и сервер GDB, или какой-то другой демон, позволяющий отладчику общаться с целевой системой. Поскольку отлаживается сам сетевой стек, то очевидно, что отладчик не сможет работать через то же самое сетевое соединение, и нужен какой-то другой способ обмена данными. Для этого есть несколько решений. Для самой лучшей производительности хорошей идеей будет запустить другой стабильный экземпляр lwIP, или другой сетевой стек, рядом с отлаживаемым стеком lwIP. Это может быть довольно замысловатым способом отладки, в зависимости от определенной архитектуры целевой системы, однако вполне выполнимо и полезно для устранения проблем, возникающих с начальным портированием. Когда стек запущен и заработал, отладчик становится гораздо менее полезен, поскольку большинство проблем создают уже внешние компоненты (чаще всего это компонент, блокирующий выполнение на слишком большое время). Здесь уже поможет старый, традиционный метод вывода отладочных printf-сообщений. [Встроенная отладка в стиле printf] Стек lwIP разработан с хорошей поддержкой вывода различных отладочных сообщений, с богатыми опциями настройки этого вывода. Опции отладки разрешаются во время сборки. Это различные xxx_DEBUG опции, которые перечислены в файле opt.h. Измените настройки по умолчанию (в которых отладка выключена) файла opts.h путем добавления в файл lwipopts.h: #define LWIP_DEBUG 1
#define xxx_DEBUG LWIP_DBG_ON
...
Здесь xxx обозначает отлаживаемую подсистему стека - например, IP_DEBUG, DHCP_DEBUG и т. д. Пример вывода отлдочных сообщений с включенной опцией NETIF_DEBUG: netif: netmask of interface netif: GW address of interface netif_set_ipaddr: netif address being changed netif: IP address of interface netif: added interface st IP addr 192.168.0.208 netmask 255.255.255.0 gw 192.168.0.1 netif: setting default interface st В следующей таблице перечислены все отлаживаемые подсистемы стека, краткая информация по этим опциям приведена также в файле opt.h.
Чтобы разрешить отладочный код в LWIP, нужно определить флаг (макрос) LWIP_DEBUG в момент компиляции кода LWIP. Флаги компиляции обычно передаются с опцией "-D" как один из аргументов командной строки компилятора. [Keil] Например, при компиляции средствами разработки Keil можно добавить целевые опции компилятора на закладке "define C/C++" целевых опций проекта. Чтобы разрешить определенные отладочные сообщения LWIP, просто установите соответствующее значение для макросов *_DEBUG в " LWIP_DBG_ON". Выполните копию необходимых для отладки опций, и вставьте их в файл lwipopts.h. Например: // Строки, добавленные в lwipopts.h:
#define TCP_DEBUG LWIP_DBG_ON
#define ETHARP_DEBUG LWIP_DBG_ON
#define PBUF_DEBUG LWIP_DBG_ON
[IAR] Зайдите в свойства проекта, раздел C/C++ Compiler, и на закладке Preprocessor в поле ввода "Defined symbols: (one per line)" добавьте строку LWIP_DEBUG: После этого в файл lwipopts.h включите опции xxx_DEBUG, необходимые для отладки. [Конфигурирование типов отладочных сообщений] Стек lwIP поддерживает разные типы отладочных сообщений. Символическая константа LWIP_DBG_TYPES_ON (находится в файле lwipopts.h) может быть изменена, чтобы разрешить или запретить некоторые виды сообщений. Следующие 4 значения могут быть объединены операцией ИЛИ, и назначены для константы LWIP_DBG_TYPES_ON: /* Флаг для LWIP_DEBUGF, показывающий сообщение трассировки
* (для выполняющихся операций программы): */
#define LWIP_DBG_TRACE 0x40U
/* Флаг для LWIP_DEBUGF, показывающий состояние отладочного сообщения
* (для отслеживания состояний модуля): */
#define LWIP_DBG_STATE 0x20U
/* Флаг для LWIP_DEBUGF, показывающий только что добавленный код,
* это пока еще тщательно не протестировано: */
#define LWIP_DBG_FRESH 0x10U
/* Флаг для LWIP_DEBUGF, вызывающий остановку выполнения после
* вывода на печать этого отладочного сообщения: */
#define LWIP_DBG_HALT 0x08U
[Реализация LWIP_DEBUGF] Код, который выводит отладочные сообщения, реализован макросом LWIP_DEBUGF. По умолчанию он использует стандартный вывод printf: #define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#define LWIP_DEBUGF(debug, message) do { \
if ( \
((debug) & LWIP_DBG_ON) && \
((debug) & LWIP_DBG_TYPES_ON) && \
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
LWIP_PLATFORM_DIAG(message); \
if ((debug) & LWIP_DBG_HALT) { \
while(1); \
} \
} \
} while(0)
Вы можете переопределить макрос LWIP_PLATFORM_DIAG, заменив вызов printf на любую функцию, поддерживающую аргументы __VA_ARGS__. Ниже приведен кусок кода, где реализован вывод отладочных сообщений в USART1 микроконтроллера STM32F429 (плата 32F429IDISCAVERY). Функцию uprintf можно использовать вместо printf в макросе LWIP_PLATFORM_DIAG(x): //#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#define LWIP_PLATFORM_DIAG(x) do {uprintf x;} while(0)
Важный момент: аргумент x в вызове функции uprintf макроса LWIP_PLATFORM_DIAG не надо заключать в скобки, иначе компилятор будет выдавать ошибку "... argument of type "u16_t" is incompatible with parameter of type 'char const *'". #include < stdio.h>
#include < stdarg.h>
#include < string.h>
#include "bufcheck.h"
#include "UsartIO.h"
#include "USARTconsole.h"
#include "settings.h"
#include "pins.h"
#include "errors.h"
#include "cmsis_os.h"
char usartbuftx[USART_TXBUFSIZE];
static char strbuf[UPRINTF_BUF_SIZE]; static USART_HandleTypeDef husart1;
uint16_t usartinTX = 0; uint16_t usartoutTX = 0; SemaphoreHandle_t usarttxSemaphore; void MX_USART1_Init(void) { husart1.Instance = USART1; husart1.Init.BaudRate = 115200; husart1.Init.WordLength = USART_WORDLENGTH_8B; husart1.Init.StopBits = USART_STOPBITS_1; husart1.Init.Parity = USART_PARITY_NONE; husart1.Init.Mode = USART_MODE_TX_RX; if (HAL_USART_Init(&husart1) != HAL_OK) { HALerrorHandler(); } } void StartUSART1txtask(void const * argument) { for(;;) { ////////////////////////////////////////////// // Обработка передачи while(usartinTX != usartoutTX) { while (0 == __HAL_USART_GET_FLAG(&husart1, USART_FLAG_TXE)); husart1.Instance->DR = usartbuftx[usartoutTX]; usartoutTX++; usartoutTX &= USART_TXBUFMASK; } xSemaphoreTake(usarttxSemaphore, portMAX_DELAY); } } void usartputc(char c) { usartbuftx[usartinTX++] = c; usartinTX &= USART_TXBUFMASK; } //Замена \n (LF 0A) на \r\n (CRLF 0D0A),
// \r во входной строке пропускается.
static void usartputs(const char *c) { while (*c) { if (*c == '\n') usartputc('\r'); // 0x0D = insert carriage return usartputc(*c); c++; } } int16_t uprintf (const char *fmt, ...) { int16_t outsize; va_list ap; // Вернет ошибку, если формат является указателем NULL: if (!fmt) { return -1; } // Вернет ошибку, если строка превышает размер буфера, с учетом // необходимых дополнительных 2 символов: CR и нулевой терминатор ASCIIZ: if (UPRINTF_BUF_SIZE-2 < strlen(fmt)) { return -1; } va_start (ap,fmt); outsize = vsprintf(strbuf,fmt,ap); strbuf[outsize+1] = 0; va_end (ap); usartputs(strbuf);
xSemaphoreGive(usarttxSemaphore);
return outsize;
}
Весь проект целиком можно скачать по ссылке [3]. [Ссылки] 1. Enabling debug output in LWIP site:community.nxp.com. |