mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-01-30 03:30:26 +08:00
Merge branch 'master' of https://github.com/RT-Thread/rt-thread into fixed
This commit is contained in:
commit
94e1935f1f
63
bsp/stm32f10x/drivers/gpio.c
Normal file → Executable file
63
bsp/stm32f10x/drivers/gpio.c
Normal file → Executable file
@ -8,8 +8,9 @@
|
||||
* http://www.rt-thread.org/license/LICENSE
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-03-24 Bright the first version
|
||||
* Date Author Notes
|
||||
* 2015-03-24 Bright the first version
|
||||
* 2016-05-23 Margguo@gmail.com Add 48 pins IC define
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
@ -19,7 +20,7 @@
|
||||
|
||||
#ifdef RT_USING_PIN
|
||||
|
||||
#define STM32F10X_PIN_NUMBERS 100 //[ 64, 100, 144 ]
|
||||
#define STM32F10X_PIN_NUMBERS 100 //[48, 64, 100, 144 ]
|
||||
|
||||
#define __STM32_PIN(index, rcc, gpio, gpio_index) { 0, RCC_##rcc##Periph_GPIO##gpio, GPIO##gpio, GPIO_Pin_##gpio_index}
|
||||
#define __STM32_PIN_DEFAULT {-1, 0, 0, 0}
|
||||
@ -35,6 +36,58 @@ struct pin_index
|
||||
|
||||
static const struct pin_index pins[] =
|
||||
{
|
||||
#if (STM32F10X_PIN_NUMBERS == 48)
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN(2, APB2, C, 13),
|
||||
__STM32_PIN(3, APB2, C, 14),
|
||||
__STM32_PIN(4, APB2, C, 15),
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN(10, APB2, A, 0),
|
||||
__STM32_PIN(11, APB2, A, 1),
|
||||
__STM32_PIN(12, APB2, A, 2),
|
||||
__STM32_PIN(13, APB2, A, 3),
|
||||
__STM32_PIN(14, APB2, A, 4),
|
||||
__STM32_PIN(15, APB2, A, 5),
|
||||
__STM32_PIN(16, APB2, A, 6),
|
||||
__STM32_PIN(17, APB2, A, 7),
|
||||
__STM32_PIN(18, APB2, B, 0),
|
||||
__STM32_PIN(19, APB2, B, 1),
|
||||
__STM32_PIN(20, APB2, B, 2),
|
||||
__STM32_PIN(21, APB2, B, 10),
|
||||
__STM32_PIN(22, APB2, B, 11),
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN(25, APB2, B, 12),
|
||||
__STM32_PIN(26, APB2, B, 13),
|
||||
__STM32_PIN(27, APB2, B, 14),
|
||||
__STM32_PIN(28, APB2, B, 15),
|
||||
__STM32_PIN(29, APB2, A, 8),
|
||||
__STM32_PIN(30, APB2, A, 9),
|
||||
__STM32_PIN(31, APB2, A, 10),
|
||||
__STM32_PIN(32, APB2, A, 11),
|
||||
__STM32_PIN(33, APB2, A, 12),
|
||||
__STM32_PIN(34, APB2, A, 13),
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN(37, APB2, A, 14),
|
||||
__STM32_PIN(38, APB2, A, 15),
|
||||
__STM32_PIN(39, APB2, B, 3),
|
||||
__STM32_PIN(40, APB2, B, 4),
|
||||
__STM32_PIN(41, APB2, B, 5),
|
||||
__STM32_PIN(42, APB2, B, 6),
|
||||
__STM32_PIN(43, APB2, B, 7),
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN(45, APB2, B, 8),
|
||||
__STM32_PIN(46, APB2, B, 9),
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
|
||||
#endif
|
||||
#if (STM32F10X_PIN_NUMBERS == 64)
|
||||
__STM32_PIN_DEFAULT,
|
||||
__STM32_PIN_DEFAULT,
|
||||
@ -216,7 +269,7 @@ static const struct pin_index pins[] =
|
||||
__STM32_PIN(7, APB2, C, 13),
|
||||
__STM32_PIN(8, APB2, C, 14),
|
||||
__STM32_PIN(9, APB2, C, 15),
|
||||
|
||||
|
||||
__STM32_PIN(10, APB2, F, 0),
|
||||
__STM32_PIN(11, APB2, F, 1),
|
||||
__STM32_PIN(12, APB2, F, 2),
|
||||
@ -472,7 +525,7 @@ const static struct rt_pin_ops _stm32_pin_ops =
|
||||
int stm32_hw_pin_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
|
||||
result = rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
|
||||
return result;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
* 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode
|
||||
* 2013-05-13 aozima update for kehong-lingtai.
|
||||
* 2015-01-31 armink make sure the serial transmit complete in putc()
|
||||
* 2016-05-13 armink add DMA Rx mode
|
||||
*/
|
||||
|
||||
#include "stm32f10x.h"
|
||||
@ -44,10 +45,22 @@
|
||||
/* STM32 uart driver */
|
||||
struct stm32_uart
|
||||
{
|
||||
USART_TypeDef* uart_device;
|
||||
USART_TypeDef *uart_device;
|
||||
IRQn_Type irq;
|
||||
struct stm32_uart_dma {
|
||||
/* dma channel */
|
||||
DMA_Channel_TypeDef *rx_ch;
|
||||
/* dma global flag */
|
||||
uint32_t rx_gl_flag;
|
||||
/* dma irq channel */
|
||||
uint8_t rx_irq_ch;
|
||||
/* last receive index */
|
||||
rt_size_t last_recv_len;
|
||||
} dma;
|
||||
};
|
||||
|
||||
static void DMA_Configuration(struct rt_serial_device *serial);
|
||||
|
||||
static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
|
||||
{
|
||||
struct stm32_uart* uart;
|
||||
@ -93,6 +106,7 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c
|
||||
static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
|
||||
{
|
||||
struct stm32_uart* uart;
|
||||
rt_uint32_t ctrl_arg = (rt_uint32_t)(arg);
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
uart = (struct stm32_uart *)serial->parent.user_data;
|
||||
@ -113,8 +127,13 @@ static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *ar
|
||||
/* enable interrupt */
|
||||
USART_ITConfig(uart->uart_device, USART_IT_RXNE, ENABLE);
|
||||
break;
|
||||
/* USART config */
|
||||
case RT_DEVICE_CTRL_CONFIG :
|
||||
if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX) {
|
||||
DMA_Configuration(serial);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
@ -148,6 +167,91 @@ static int stm32_getc(struct rt_serial_device *serial)
|
||||
return ch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serial port receive idle process. This need add to uart idle ISR.
|
||||
*
|
||||
* @param serial serial device
|
||||
*/
|
||||
static void dma_uart_rx_idle_isr(struct rt_serial_device *serial) {
|
||||
struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data;
|
||||
rt_size_t recv_total_len, recv_len;
|
||||
/* disable dma, stop receive data */
|
||||
DMA_Cmd(uart->dma.rx_ch, DISABLE);
|
||||
|
||||
recv_total_len = serial->config.bufsz - DMA_GetCurrDataCounter(uart->dma.rx_ch);
|
||||
if (recv_total_len > uart->dma.last_recv_len) {
|
||||
recv_len = recv_total_len - uart->dma.last_recv_len;
|
||||
} else {
|
||||
recv_len = recv_total_len;
|
||||
}
|
||||
uart->dma.last_recv_len = recv_total_len;
|
||||
|
||||
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
|
||||
|
||||
/* read a data for clear receive idle interrupt flag */
|
||||
USART_ReceiveData(uart->uart_device);
|
||||
DMA_ClearFlag(uart->dma.rx_gl_flag);
|
||||
DMA_Cmd(uart->dma.rx_ch, ENABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* DMA receive done process. This need add to DMA receive done ISR.
|
||||
*
|
||||
* @param serial serial device
|
||||
*/
|
||||
static void dma_rx_done_isr(struct rt_serial_device *serial) {
|
||||
struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data;
|
||||
rt_size_t recv_total_len, recv_len;
|
||||
/* disable dma, stop receive data */
|
||||
DMA_Cmd(uart->dma.rx_ch, DISABLE);
|
||||
|
||||
recv_total_len = serial->config.bufsz - DMA_GetCurrDataCounter(uart->dma.rx_ch);
|
||||
if (recv_total_len > uart->dma.last_recv_len) {
|
||||
recv_len = recv_total_len - uart->dma.last_recv_len;
|
||||
} else {
|
||||
recv_len = recv_total_len;
|
||||
}
|
||||
uart->dma.last_recv_len = recv_total_len;
|
||||
|
||||
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));
|
||||
|
||||
DMA_ClearFlag(uart->dma.rx_gl_flag);
|
||||
/* reload */
|
||||
DMA_SetCurrDataCounter(uart->dma.rx_ch, serial->config.bufsz);
|
||||
DMA_Cmd(uart->dma.rx_ch, ENABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uart common interrupt process. This need add to uart ISR.
|
||||
*
|
||||
* @param serial serial device
|
||||
*/
|
||||
static void uart_isr(struct rt_serial_device *serial) {
|
||||
struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data;
|
||||
|
||||
RT_ASSERT(uart != RT_NULL);
|
||||
|
||||
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
|
||||
}
|
||||
if(USART_GetITStatus(uart->uart_device, USART_IT_IDLE) != RESET)
|
||||
{
|
||||
dma_uart_rx_idle_isr(serial);
|
||||
}
|
||||
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
|
||||
{
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
|
||||
}
|
||||
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
|
||||
{
|
||||
stm32_getc(serial);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops stm32_uart_ops =
|
||||
{
|
||||
stm32_configure,
|
||||
@ -162,70 +266,68 @@ struct stm32_uart uart1 =
|
||||
{
|
||||
USART1,
|
||||
USART1_IRQn,
|
||||
{
|
||||
DMA1_Channel5,
|
||||
DMA1_FLAG_GL5,
|
||||
DMA1_Channel5_IRQn,
|
||||
0,
|
||||
},
|
||||
};
|
||||
struct rt_serial_device serial1;
|
||||
|
||||
void USART1_IRQHandler(void)
|
||||
{
|
||||
struct stm32_uart* uart;
|
||||
|
||||
uart = &uart1;
|
||||
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
rt_hw_serial_isr(&serial1, RT_SERIAL_EVENT_RX_IND);
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
|
||||
}
|
||||
|
||||
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
|
||||
{
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
|
||||
}
|
||||
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
|
||||
{
|
||||
stm32_getc(&serial1);
|
||||
}
|
||||
uart_isr(&serial1);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void DMA1_Channel5_IRQHandler(void) {
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
dma_rx_done_isr(&serial1);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* RT_USING_UART1 */
|
||||
|
||||
#if defined(RT_USING_UART2)
|
||||
/* UART1 device driver structure */
|
||||
/* UART2 device driver structure */
|
||||
struct stm32_uart uart2 =
|
||||
{
|
||||
USART2,
|
||||
USART2_IRQn,
|
||||
{
|
||||
DMA1_Channel6,
|
||||
DMA1_FLAG_GL6,
|
||||
DMA1_Channel6_IRQn,
|
||||
0,
|
||||
},
|
||||
};
|
||||
struct rt_serial_device serial2;
|
||||
|
||||
void USART2_IRQHandler(void)
|
||||
{
|
||||
struct stm32_uart* uart;
|
||||
|
||||
uart = &uart2;
|
||||
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND);
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
|
||||
}
|
||||
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
|
||||
{
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
|
||||
}
|
||||
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
|
||||
{
|
||||
stm32_getc(&serial2);
|
||||
}
|
||||
|
||||
uart_isr(&serial2);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void DMA1_Channel6_IRQHandler(void) {
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
dma_rx_done_isr(&serial2);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
@ -238,32 +340,31 @@ struct stm32_uart uart3 =
|
||||
{
|
||||
USART3,
|
||||
USART3_IRQn,
|
||||
{
|
||||
DMA1_Channel3,
|
||||
DMA1_FLAG_GL3,
|
||||
DMA1_Channel3_IRQn,
|
||||
0,
|
||||
},
|
||||
};
|
||||
struct rt_serial_device serial3;
|
||||
|
||||
void USART3_IRQHandler(void)
|
||||
{
|
||||
struct stm32_uart* uart;
|
||||
|
||||
uart = &uart3;
|
||||
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
rt_hw_serial_isr(&serial3, RT_SERIAL_EVENT_RX_IND);
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
|
||||
}
|
||||
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
|
||||
{
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
|
||||
}
|
||||
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
|
||||
{
|
||||
stm32_getc(&serial3);
|
||||
}
|
||||
|
||||
uart_isr(&serial3);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void DMA1_Channel3_IRQHandler(void) {
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
dma_rx_done_isr(&serial3);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
@ -276,69 +377,66 @@ struct stm32_uart uart4 =
|
||||
{
|
||||
UART4,
|
||||
UART4_IRQn,
|
||||
{
|
||||
DMA2_Channel3,
|
||||
DMA2_FLAG_GL3,
|
||||
DMA2_Channel3_IRQn,
|
||||
0,
|
||||
},
|
||||
};
|
||||
struct rt_serial_device serial4;
|
||||
|
||||
void UART4_IRQHandler(void)
|
||||
{
|
||||
struct stm32_uart* uart;
|
||||
|
||||
uart = &uart4;
|
||||
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
rt_hw_serial_isr(&serial4, RT_SERIAL_EVENT_RX_IND);
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE);
|
||||
}
|
||||
if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET)
|
||||
{
|
||||
/* clear interrupt */
|
||||
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
|
||||
}
|
||||
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
|
||||
{
|
||||
stm32_getc(&serial4);
|
||||
}
|
||||
|
||||
uart_isr(&serial4);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* RT_USING_UART3 */
|
||||
|
||||
void DMA2_Channel3_IRQHandler(void) {
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
dma_rx_done_isr(&serial4);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* RT_USING_UART4 */
|
||||
|
||||
static void RCC_Configuration(void)
|
||||
{
|
||||
#if defined(RT_USING_UART1)
|
||||
/* Enable UART GPIO clocks */
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
|
||||
/* Enable UART clock */
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
||||
#endif /* RT_USING_UART1 */
|
||||
|
||||
#if defined(RT_USING_UART2)
|
||||
/* Enable UART GPIO clocks */
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
|
||||
/* Enable UART clock */
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
|
||||
#endif /* RT_USING_UART2 */
|
||||
|
||||
#if defined(RT_USING_UART3)
|
||||
/* Enable UART GPIO clocks */
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
|
||||
/* Enable UART clock */
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
|
||||
#endif /* RT_USING_UART3 */
|
||||
|
||||
#if defined(RT_USING_UART4)
|
||||
/* Enable UART GPIO clocks */
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
|
||||
/* Enable UART clock */
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
|
||||
#endif /* RT_USING_UART4 */
|
||||
|
||||
}
|
||||
|
||||
static void GPIO_Configuration(void)
|
||||
@ -390,7 +488,6 @@ static void GPIO_Configuration(void)
|
||||
GPIO_InitStructure.GPIO_Pin = UART4_GPIO_TX;
|
||||
GPIO_Init(UART4_GPIO, &GPIO_InitStructure);
|
||||
#endif /* RT_USING_UART4 */
|
||||
|
||||
}
|
||||
|
||||
static void NVIC_Configuration(struct stm32_uart* uart)
|
||||
@ -405,6 +502,46 @@ static void NVIC_Configuration(struct stm32_uart* uart)
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
}
|
||||
|
||||
static void DMA_Configuration(struct rt_serial_device *serial) {
|
||||
struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data;
|
||||
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
||||
DMA_InitTypeDef DMA_InitStructure;
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
/* enable transmit idle interrupt */
|
||||
USART_ITConfig(uart->uart_device, USART_IT_IDLE , ENABLE);
|
||||
|
||||
/* DMA clock enable */
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
|
||||
|
||||
/* rx dma config */
|
||||
DMA_DeInit(uart->dma.rx_ch);
|
||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(uart->uart_device->DR);
|
||||
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) rx_fifo->buffer;
|
||||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
|
||||
DMA_InitStructure.DMA_BufferSize = serial->config.bufsz;
|
||||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
||||
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
||||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||||
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
||||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||||
DMA_Init(uart->dma.rx_ch, &DMA_InitStructure);
|
||||
DMA_ClearFlag(uart->dma.rx_gl_flag);
|
||||
DMA_ITConfig(uart->dma.rx_ch, DMA_IT_TC, ENABLE);
|
||||
USART_DMACmd(uart->uart_device, USART_DMAReq_Rx, ENABLE);
|
||||
DMA_Cmd(uart->dma.rx_ch, ENABLE);
|
||||
|
||||
/* rx dma interrupt config */
|
||||
NVIC_InitStructure.NVIC_IRQChannel = uart->dma.rx_irq_ch;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
}
|
||||
|
||||
void rt_hw_usart_init(void)
|
||||
{
|
||||
struct stm32_uart* uart;
|
||||
@ -420,11 +557,11 @@ void rt_hw_usart_init(void)
|
||||
serial1.ops = &stm32_uart_ops;
|
||||
serial1.config = config;
|
||||
|
||||
NVIC_Configuration(&uart1);
|
||||
NVIC_Configuration(uart);
|
||||
|
||||
/* register UART1 device */
|
||||
rt_hw_serial_register(&serial1, "uart1",
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX ,
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX,
|
||||
uart);
|
||||
#endif /* RT_USING_UART1 */
|
||||
|
||||
@ -435,11 +572,11 @@ void rt_hw_usart_init(void)
|
||||
serial2.ops = &stm32_uart_ops;
|
||||
serial2.config = config;
|
||||
|
||||
NVIC_Configuration(&uart2);
|
||||
NVIC_Configuration(uart);
|
||||
|
||||
/* register UART1 device */
|
||||
/* register UART2 device */
|
||||
rt_hw_serial_register(&serial2, "uart2",
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX,
|
||||
uart);
|
||||
#endif /* RT_USING_UART2 */
|
||||
|
||||
@ -451,11 +588,11 @@ void rt_hw_usart_init(void)
|
||||
serial3.ops = &stm32_uart_ops;
|
||||
serial3.config = config;
|
||||
|
||||
NVIC_Configuration(&uart3);
|
||||
NVIC_Configuration(uart);
|
||||
|
||||
/* register UART1 device */
|
||||
/* register UART3 device */
|
||||
rt_hw_serial_register(&serial3, "uart3",
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX,
|
||||
uart);
|
||||
#endif /* RT_USING_UART3 */
|
||||
|
||||
@ -467,12 +604,11 @@ void rt_hw_usart_init(void)
|
||||
serial4.ops = &stm32_uart_ops;
|
||||
serial4.config = config;
|
||||
|
||||
NVIC_Configuration(&uart4);
|
||||
NVIC_Configuration(uart);
|
||||
|
||||
/* register UART4 device */
|
||||
rt_hw_serial_register(&serial4, "uart4",
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX,
|
||||
uart);
|
||||
#endif /* RT_USING_UART4 */
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,6 @@ cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_LWIP'], CPPPATH = CPPPATH)
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_NET'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* File : dfs_lwip.c
|
||||
* File : dfs_net.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2015, RT-Thread Development Team
|
||||
* COPYRIGHT (C) 2015-2016, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -20,15 +20,16 @@
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-02-17 Bernard First version
|
||||
* 2016-05-07 Bernard Rename dfs_lwip to dfs_net
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
|
||||
#include "dfs_lwip.h"
|
||||
#include "dfs_net.h"
|
||||
|
||||
int dfs_lwip_getsocket(int fd)
|
||||
int dfs_net_getsocket(int fd)
|
||||
{
|
||||
struct dfs_fd *_dfs_fd;
|
||||
|
||||
@ -40,12 +41,12 @@ int dfs_lwip_getsocket(int fd)
|
||||
return (int)_dfs_fd->data;
|
||||
}
|
||||
|
||||
int dfs_lwip_ioctl(struct dfs_fd* file, int cmd, void* args)
|
||||
int dfs_net_ioctl(struct dfs_fd* file, int cmd, void* args)
|
||||
{
|
||||
return -DFS_STATUS_EIO;
|
||||
}
|
||||
|
||||
int dfs_lwip_read(struct dfs_fd* file, void *buf, rt_size_t count)
|
||||
int dfs_net_read(struct dfs_fd* file, void *buf, rt_size_t count)
|
||||
{
|
||||
int sock;
|
||||
|
||||
@ -55,7 +56,7 @@ int dfs_lwip_read(struct dfs_fd* file, void *buf, rt_size_t count)
|
||||
return count;
|
||||
}
|
||||
|
||||
int dfs_lwip_write(struct dfs_fd *file, const void *buf, rt_size_t count)
|
||||
int dfs_net_write(struct dfs_fd *file, const void *buf, rt_size_t count)
|
||||
{
|
||||
int sock;
|
||||
|
||||
@ -65,7 +66,7 @@ int dfs_lwip_write(struct dfs_fd *file, const void *buf, rt_size_t count)
|
||||
return count;
|
||||
}
|
||||
|
||||
int dfs_lwip_close(struct dfs_fd* file)
|
||||
int dfs_net_close(struct dfs_fd* file)
|
||||
{
|
||||
int sock;
|
||||
int result;
|
||||
@ -78,9 +79,9 @@ int dfs_lwip_close(struct dfs_fd* file)
|
||||
return -result;
|
||||
}
|
||||
|
||||
static const struct dfs_filesystem_operation _lwip_fs_ops =
|
||||
static const struct dfs_filesystem_operation _net_fs_ops =
|
||||
{
|
||||
"lwip",
|
||||
"net",
|
||||
DFS_FS_FLAG_DEFAULT,
|
||||
RT_NULL, /* mount */
|
||||
RT_NULL, /* unmont */
|
||||
@ -88,10 +89,10 @@ static const struct dfs_filesystem_operation _lwip_fs_ops =
|
||||
RT_NULL, /* statfs */
|
||||
|
||||
RT_NULL, /* open */
|
||||
dfs_lwip_close,
|
||||
dfs_lwip_ioctl,
|
||||
dfs_lwip_read,
|
||||
dfs_lwip_write,
|
||||
dfs_net_close,
|
||||
dfs_net_ioctl,
|
||||
dfs_net_read,
|
||||
dfs_net_write,
|
||||
RT_NULL,
|
||||
RT_NULL, /* lseek */
|
||||
RT_NULL, /* getdents */
|
||||
@ -100,28 +101,28 @@ static const struct dfs_filesystem_operation _lwip_fs_ops =
|
||||
RT_NULL, /* rename */
|
||||
};
|
||||
|
||||
static struct dfs_filesystem _lwip_fs =
|
||||
static struct dfs_filesystem _net_fs =
|
||||
{
|
||||
0, /* dev_id */
|
||||
RT_NULL, /* path */
|
||||
&_lwip_fs_ops,
|
||||
&_net_fs_ops,
|
||||
RT_NULL /* data */
|
||||
};
|
||||
|
||||
struct dfs_filesystem* dfs_lwip_get_fs(void)
|
||||
struct dfs_filesystem* dfs_net_get_fs(void)
|
||||
{
|
||||
return &_lwip_fs;
|
||||
return &_net_fs;
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE: Beause we don't need to mount lwIP file system, the filesystem_ops is not
|
||||
registered to the system.
|
||||
|
||||
int dfs_lwip_system_init(void)
|
||||
int dfs_net_system_init(void)
|
||||
{
|
||||
dfs_register(&_lwip_fs_ops);
|
||||
dfs_register(&_net_fs_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_FS_EXPORT(dfs_lwip_system_init);
|
||||
INIT_FS_EXPORT(dfs_net_system_init);
|
||||
*/
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* File : dfs_lwip.h
|
||||
* File : dfs_net.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2015, RT-Thread Development Team
|
||||
* COPYRIGHT (C) 2015-2016, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -20,10 +20,11 @@
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-02-17 Bernard First version
|
||||
* 2016-05-05 Bernard rename dfs_lwip to dfs_net.
|
||||
*/
|
||||
|
||||
#ifndef DFS_LWIP_H__
|
||||
#define DFS_LWIP_H__
|
||||
#ifndef DFS_NET_H__
|
||||
#define DFS_NET_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -31,10 +32,10 @@ extern "C" {
|
||||
|
||||
#include <lwip/sockets.h>
|
||||
|
||||
struct dfs_filesystem* dfs_lwip_get_fs(void);
|
||||
int dfs_lwip_getsocket(int fd);
|
||||
struct dfs_filesystem* dfs_net_get_fs(void);
|
||||
int dfs_net_getsocket(int fd);
|
||||
|
||||
int dfs_lwip_system_init(void);
|
||||
int dfs_net_system_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
@ -27,7 +27,7 @@
|
||||
|
||||
#ifdef RT_USING_LWIP
|
||||
|
||||
#include "dfs_lwip.h"
|
||||
#include "dfs_net.h"
|
||||
|
||||
int
|
||||
select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
||||
@ -48,7 +48,7 @@ select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
||||
for (index = 0; index < maxfdp1; index ++)
|
||||
{
|
||||
/* convert fd to sock */
|
||||
sock = dfs_lwip_getsocket(index);
|
||||
sock = dfs_net_getsocket(index);
|
||||
if (sock == -1) continue;
|
||||
|
||||
if (sock > maxfd) maxfd = sock;
|
@ -28,12 +28,12 @@
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "dfs_lwip.h"
|
||||
#include "dfs_net.h"
|
||||
|
||||
int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
int new_client = -1;
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
new_client = lwip_accept(sock, addr, addrlen);
|
||||
if (new_client != -1)
|
||||
@ -58,7 +58,7 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
d->type = FT_SOCKET;
|
||||
d->path = RT_NULL;
|
||||
|
||||
d->fs = dfs_lwip_get_fs();
|
||||
d->fs = dfs_net_get_fs();
|
||||
|
||||
d->flags = DFS_O_RDWR; /* set flags as read and write */
|
||||
d->size = 0;
|
||||
@ -79,7 +79,7 @@ RTM_EXPORT(accept);
|
||||
|
||||
int bind(int s, const struct sockaddr *name, socklen_t namelen)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_bind(sock, name, namelen);
|
||||
}
|
||||
@ -98,7 +98,7 @@ int shutdown(int s, int how)
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock = dfs_lwip_getsocket(s);
|
||||
sock = dfs_net_getsocket(s);
|
||||
if (lwip_shutdown(sock, how) == 0)
|
||||
{
|
||||
/* socket has been closed, delete it from file system fd */
|
||||
@ -114,7 +114,7 @@ RTM_EXPORT(shutdown);
|
||||
|
||||
int getpeername(int s, struct sockaddr *name, socklen_t *namelen)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_getpeername(sock, name, namelen);
|
||||
}
|
||||
@ -122,7 +122,7 @@ RTM_EXPORT(getpeername);
|
||||
|
||||
int getsockname(int s, struct sockaddr *name, socklen_t *namelen)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_getsockname(sock, name, namelen);
|
||||
}
|
||||
@ -130,7 +130,7 @@ RTM_EXPORT(getsockname);
|
||||
|
||||
int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_getsockopt(sock, level, optname, optval, optlen);
|
||||
}
|
||||
@ -138,7 +138,7 @@ RTM_EXPORT(getsockopt);
|
||||
|
||||
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_setsockopt(sock, level, optname, optval, optlen);
|
||||
}
|
||||
@ -146,7 +146,7 @@ RTM_EXPORT(setsockopt);
|
||||
|
||||
int connect(int s, const struct sockaddr *name, socklen_t namelen)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_connect(sock, name, namelen);
|
||||
}
|
||||
@ -154,7 +154,7 @@ RTM_EXPORT(connect);
|
||||
|
||||
int listen(int s, int backlog)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_listen(sock, backlog);
|
||||
}
|
||||
@ -162,7 +162,7 @@ RTM_EXPORT(listen);
|
||||
|
||||
int recv(int s, void *mem, size_t len, int flags)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_recv(sock, mem, len, flags);
|
||||
}
|
||||
@ -171,7 +171,7 @@ RTM_EXPORT(recv);
|
||||
int recvfrom(int s, void *mem, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_recvfrom(sock, mem, len, flags, from, fromlen);
|
||||
}
|
||||
@ -179,7 +179,7 @@ RTM_EXPORT(recvfrom);
|
||||
|
||||
int send(int s, const void *dataptr, size_t size, int flags)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_send(sock, dataptr, size, flags);
|
||||
}
|
||||
@ -188,7 +188,7 @@ RTM_EXPORT(send);
|
||||
int sendto(int s, const void *dataptr, size_t size, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen)
|
||||
{
|
||||
int sock = dfs_lwip_getsocket(s);
|
||||
int sock = dfs_net_getsocket(s);
|
||||
|
||||
return lwip_sendto(sock, dataptr, size, flags, to, tolen);
|
||||
}
|
||||
@ -219,7 +219,7 @@ int socket(int domain, int type, int protocol)
|
||||
d->type = FT_SOCKET;
|
||||
d->path = RT_NULL;
|
||||
|
||||
d->fs = dfs_lwip_get_fs();
|
||||
d->fs = dfs_net_get_fs();
|
||||
|
||||
d->flags = DFS_O_RDWR; /* set flags as read and write */
|
||||
d->size = 0;
|
@ -220,6 +220,10 @@ rt_inline rt_uint32_t fls(rt_uint32_t val)
|
||||
return bit;
|
||||
}
|
||||
|
||||
#define MMCSD_HOST_PLUGED 0
|
||||
#define MMCSD_HOST_UNPLUGED 1
|
||||
|
||||
int mmcsd_wait_cd_changed(rt_int32_t timeout);
|
||||
void mmcsd_host_lock(struct rt_mmcsd_host *host);
|
||||
void mmcsd_host_unlock(struct rt_mmcsd_host *host);
|
||||
void mmcsd_req_complete(struct rt_mmcsd_host *host);
|
||||
|
@ -33,12 +33,15 @@
|
||||
#define BAUD_RATE_2400 2400
|
||||
#define BAUD_RATE_4800 4800
|
||||
#define BAUD_RATE_9600 9600
|
||||
#define BAUD_RATE_19200 19200
|
||||
#define BAUD_RATE_38400 38400
|
||||
#define BAUD_RATE_57600 57600
|
||||
#define BAUD_RATE_115200 115200
|
||||
#define BAUD_RATE_230400 230400
|
||||
#define BAUD_RATE_460800 460800
|
||||
#define BAUD_RATE_921600 921600
|
||||
#define BAUD_RATE_2000000 2000000
|
||||
#define BAUD_RATE_3000000 3000000
|
||||
|
||||
#define DATA_BITS_5 5
|
||||
#define DATA_BITS_6 6
|
||||
@ -106,7 +109,7 @@ struct serial_configure
|
||||
rt_uint32_t parity :2;
|
||||
rt_uint32_t bit_order :1;
|
||||
rt_uint32_t invert :1;
|
||||
rt_uint32_t bufsz :16;
|
||||
rt_uint32_t bufsz :16;
|
||||
rt_uint32_t reserved :4;
|
||||
};
|
||||
|
||||
@ -115,15 +118,15 @@ struct serial_configure
|
||||
*/
|
||||
struct rt_serial_rx_fifo
|
||||
{
|
||||
/* software fifo */
|
||||
rt_uint8_t *buffer;
|
||||
/* software fifo */
|
||||
rt_uint8_t *buffer;
|
||||
|
||||
rt_uint16_t put_index, get_index;
|
||||
rt_uint16_t put_index, get_index;
|
||||
};
|
||||
|
||||
struct rt_serial_tx_fifo
|
||||
{
|
||||
struct rt_completion completion;
|
||||
struct rt_completion completion;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -131,13 +134,13 @@ struct rt_serial_tx_fifo
|
||||
*/
|
||||
struct rt_serial_rx_dma
|
||||
{
|
||||
rt_bool_t activated;
|
||||
rt_bool_t activated;
|
||||
};
|
||||
|
||||
struct rt_serial_tx_dma
|
||||
{
|
||||
rt_bool_t activated;
|
||||
struct rt_data_queue data_queue;
|
||||
rt_bool_t activated;
|
||||
struct rt_data_queue data_queue;
|
||||
};
|
||||
|
||||
struct rt_serial_device
|
||||
@ -147,8 +150,8 @@ struct rt_serial_device
|
||||
const struct rt_uart_ops *ops;
|
||||
struct serial_configure config;
|
||||
|
||||
void *serial_rx;
|
||||
void *serial_tx;
|
||||
void *serial_rx;
|
||||
void *serial_tx;
|
||||
};
|
||||
typedef struct rt_serial_device rt_serial_t;
|
||||
|
||||
@ -163,7 +166,7 @@ struct rt_uart_ops
|
||||
int (*putc)(struct rt_serial_device *serial, char c);
|
||||
int (*getc)(struct rt_serial_device *serial);
|
||||
|
||||
rt_size_t (*dma_transmit)(struct rt_serial_device *serial, const rt_uint8_t *buf, rt_size_t size, int direction);
|
||||
rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
|
||||
};
|
||||
|
||||
void rt_hw_serial_isr(struct rt_serial_device *serial, int event);
|
||||
@ -174,4 +177,3 @@ rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
|
||||
void *data);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -44,6 +44,8 @@ static struct rt_thread mmcsd_detect_thread;
|
||||
static rt_uint8_t mmcsd_stack[RT_MMCSD_STACK_SIZE];
|
||||
static struct rt_mailbox mmcsd_detect_mb;
|
||||
static rt_uint32_t mmcsd_detect_mb_pool[4];
|
||||
static struct rt_mailbox mmcsd_hotpluge_mb;
|
||||
static rt_uint32_t mmcsd_hotpluge_mb_pool[4];
|
||||
|
||||
void mmcsd_host_lock(struct rt_mmcsd_host *host)
|
||||
{
|
||||
@ -594,6 +596,24 @@ static void mmcsd_power_off(struct rt_mmcsd_host *host)
|
||||
mmcsd_set_iocfg(host);
|
||||
}
|
||||
|
||||
int mmcsd_wait_cd_changed(rt_int32_t timeout)
|
||||
{
|
||||
struct rt_mmcsd_host *host;
|
||||
if (rt_mb_recv(&mmcsd_hotpluge_mb, (rt_uint32_t*)&host, timeout) == RT_EOK)
|
||||
{
|
||||
if(host->card == RT_NULL)
|
||||
{
|
||||
return MMCSD_HOST_UNPLUGED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MMCSD_HOST_PLUGED;
|
||||
}
|
||||
}
|
||||
return -RT_ETIMEOUT;
|
||||
}
|
||||
RTM_EXPORT(mmcsd_wait_cd_changed);
|
||||
|
||||
void mmcsd_change(struct rt_mmcsd_host *host)
|
||||
{
|
||||
rt_mb_send(&mmcsd_detect_mb, (rt_uint32_t)host);
|
||||
@ -647,6 +667,7 @@ void mmcsd_detect(void *param)
|
||||
if (init_mmc(host, ocr))
|
||||
mmcsd_power_off(host);
|
||||
mmcsd_host_unlock(host);
|
||||
rt_mb_send(&mmcsd_hotpluge_mb, (rt_uint32_t)host);
|
||||
continue;
|
||||
}
|
||||
mmcsd_host_unlock(host);
|
||||
@ -667,6 +688,7 @@ void mmcsd_detect(void *param)
|
||||
host->card = RT_NULL;
|
||||
}
|
||||
mmcsd_host_unlock(host);
|
||||
rt_mb_send(&mmcsd_hotpluge_mb, (rt_uint32_t)host);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -711,11 +733,15 @@ void rt_mmcsd_core_init(void)
|
||||
/* initialize detect SD cart thread */
|
||||
/* initialize mailbox and create detect SD card thread */
|
||||
ret = rt_mb_init(&mmcsd_detect_mb, "mmcsdmb",
|
||||
&mmcsd_detect_mb_pool[0], sizeof(mmcsd_detect_mb_pool),
|
||||
&mmcsd_detect_mb_pool[0], sizeof(mmcsd_detect_mb_pool) / sizeof(mmcsd_detect_mb_pool[0]),
|
||||
RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
|
||||
ret = rt_thread_init(&mmcsd_detect_thread, "mmcsd_detect", mmcsd_detect, RT_NULL,
|
||||
ret = rt_mb_init(&mmcsd_hotpluge_mb, "mmcsdhotplugmb",
|
||||
&mmcsd_hotpluge_mb_pool[0], sizeof(mmcsd_hotpluge_mb_pool) / sizeof(mmcsd_hotpluge_mb_pool[0]),
|
||||
RT_IPC_FLAG_FIFO);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
ret = rt_thread_init(&mmcsd_detect_thread, "mmcsd_detect", mmcsd_detect, RT_NULL,
|
||||
&mmcsd_stack[0], RT_MMCSD_STACK_SIZE, RT_MMCSD_THREAD_PREORITY, 20);
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
|
@ -27,9 +27,10 @@
|
||||
* the size of ring buffer.
|
||||
* 2014-07-10 bernard rewrite serial framework
|
||||
* 2014-12-31 bernard use open_flag for poll_tx stream mode.
|
||||
* 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
|
||||
* 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG
|
||||
* in open function.
|
||||
* 2015-11-10 bernard fix the poll rx issue when there is no data.
|
||||
* 2016-05-10 armink add fifo mode to DMA rx when serial->config.bufsz != 0.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
@ -37,13 +38,13 @@
|
||||
#include <rtdevice.h>
|
||||
|
||||
/*
|
||||
* Serial poll routines
|
||||
* Serial poll routines
|
||||
*/
|
||||
rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
|
||||
{
|
||||
int ch;
|
||||
int size;
|
||||
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
size = length;
|
||||
|
||||
@ -52,7 +53,7 @@ rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data,
|
||||
ch = serial->ops->getc(serial);
|
||||
if (ch == -1) break;
|
||||
|
||||
*data = ch;
|
||||
*data = ch;
|
||||
data ++; length --;
|
||||
|
||||
if (ch == '\n') break;
|
||||
@ -77,9 +78,9 @@ rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t
|
||||
{
|
||||
serial->ops->putc(serial, '\r');
|
||||
}
|
||||
|
||||
|
||||
serial->ops->putc(serial, *data);
|
||||
|
||||
|
||||
++ data;
|
||||
-- length;
|
||||
}
|
||||
@ -96,8 +97,8 @@ rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data,
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
size = length;
|
||||
|
||||
size = length;
|
||||
|
||||
rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
@ -136,7 +137,7 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
|
||||
{
|
||||
int size;
|
||||
struct rt_serial_tx_fifo *tx;
|
||||
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
|
||||
size = length;
|
||||
@ -157,32 +158,136 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
|
||||
return size - length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate DMA received data length.
|
||||
*
|
||||
* @param serial serial device
|
||||
*
|
||||
* @return length
|
||||
*/
|
||||
static rt_size_t rt_dma_calc_recved_len(struct rt_serial_device *serial) {
|
||||
static rt_size_t rx_length;
|
||||
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
||||
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
|
||||
(serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
|
||||
return rx_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data finish by DMA mode then update the gut index for receive fifo.
|
||||
*
|
||||
* @param serial serial device
|
||||
* @param len get data length for this operate
|
||||
*/
|
||||
static void rt_dma_recv_update_get_index(struct rt_serial_device *serial, rt_size_t len) {
|
||||
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
||||
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
RT_ASSERT(len <= rt_dma_calc_recved_len(serial));
|
||||
|
||||
rx_fifo->get_index += len;
|
||||
if (rx_fifo->get_index > serial->config.bufsz ) {
|
||||
rx_fifo->get_index -= serial->config.bufsz;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DMA received finish then update put index for receive fifo.
|
||||
*
|
||||
* @param serial serial device
|
||||
* @param len received length for this transmit
|
||||
*/
|
||||
static void rt_dma_recv_update_put_index(struct rt_serial_device *serial, rt_size_t len) {
|
||||
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
|
||||
rt_size_t i;
|
||||
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
if (rx_fifo->get_index <= rx_fifo->put_index) {
|
||||
rx_fifo->put_index += len;
|
||||
/* beyond the fifo end */
|
||||
if (rx_fifo->put_index >= serial->config.bufsz) {
|
||||
for (i = 0; i <= len / serial->config.bufsz; i++) {
|
||||
rx_fifo->put_index -= serial->config.bufsz;
|
||||
}
|
||||
/* force overwrite get index */
|
||||
if (rx_fifo->put_index >= rx_fifo->get_index) {
|
||||
rx_fifo->get_index = rx_fifo->put_index + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rx_fifo->put_index += len;
|
||||
if(rx_fifo->put_index >= rx_fifo->get_index) {
|
||||
/* beyond the fifo end */
|
||||
if(rx_fifo->put_index >= serial->config.bufsz) {
|
||||
for (i = 0; i <= len / serial->config.bufsz; i++) {
|
||||
rx_fifo->put_index -= serial->config.bufsz;
|
||||
}
|
||||
}
|
||||
/* force overwrite get index */
|
||||
rx_fifo->get_index = rx_fifo->put_index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Serial DMA routines
|
||||
*/
|
||||
rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
|
||||
{
|
||||
rt_base_t level;
|
||||
int result = RT_EOK;
|
||||
struct rt_serial_rx_dma *rx_dma;
|
||||
|
||||
RT_ASSERT((serial != RT_NULL) && (data != RT_NULL));
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (rx_dma->activated != RT_TRUE)
|
||||
{
|
||||
rx_dma->activated = RT_TRUE;
|
||||
serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX);
|
||||
|
||||
if (serial->config.bufsz == 0) {
|
||||
int result = RT_EOK;
|
||||
struct rt_serial_rx_dma *rx_dma;
|
||||
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
|
||||
if (rx_dma->activated != RT_TRUE)
|
||||
{
|
||||
rx_dma->activated = RT_TRUE;
|
||||
RT_ASSERT(serial->ops->dma_transmit != RT_NULL);
|
||||
serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX);
|
||||
}
|
||||
else result = -RT_EBUSY;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (result == RT_EOK) return length;
|
||||
|
||||
rt_set_errno(result);
|
||||
return 0;
|
||||
} else {
|
||||
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx;
|
||||
rt_size_t recv_len = 0, fifo_recved_len = rt_dma_calc_recved_len(serial);
|
||||
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
if (length < fifo_recved_len) {
|
||||
recv_len = length;
|
||||
} else {
|
||||
recv_len = fifo_recved_len;
|
||||
}
|
||||
|
||||
if (rx_fifo->get_index + recv_len < serial->config.bufsz) {
|
||||
rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index, recv_len);
|
||||
} else {
|
||||
rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index,
|
||||
serial->config.bufsz - rx_fifo->get_index);
|
||||
rt_memcpy(data + serial->config.bufsz - rx_fifo->get_index, rx_fifo->buffer,
|
||||
recv_len + rx_fifo->get_index - serial->config.bufsz);
|
||||
}
|
||||
rt_dma_recv_update_get_index(serial, recv_len);
|
||||
rt_hw_interrupt_enable(level);
|
||||
return recv_len;
|
||||
}
|
||||
else result = -RT_EBUSY;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (result == RT_EOK) return length;
|
||||
|
||||
rt_set_errno(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
|
||||
@ -192,8 +297,8 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
|
||||
struct rt_serial_tx_dma *tx_dma;
|
||||
|
||||
tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx);
|
||||
|
||||
result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER);
|
||||
|
||||
result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
@ -203,7 +308,7 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* make a DMA transfer */
|
||||
serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_TX);
|
||||
serial->ops->dma_transmit(serial, (rt_uint8_t *)data, length, RT_SERIAL_DMA_TX);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -250,7 +355,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
serial = (struct rt_serial_device *)dev;
|
||||
|
||||
/* check device flag with the open flag */
|
||||
if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
|
||||
if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX))
|
||||
return -RT_EIO;
|
||||
if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
|
||||
return -RT_EIO;
|
||||
@ -261,26 +366,41 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
|
||||
/* get open flags */
|
||||
dev->open_flag = oflag & 0xff;
|
||||
|
||||
|
||||
/* initialize the Rx/Tx structure according to open flag */
|
||||
if (serial->serial_rx == RT_NULL)
|
||||
{
|
||||
if (oflag & RT_DEVICE_FLAG_DMA_RX)
|
||||
{
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
if (serial->config.bufsz == 0) {
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
|
||||
rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
rx_dma->activated = RT_FALSE;
|
||||
rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
rx_dma->activated = RT_FALSE;
|
||||
|
||||
serial->serial_rx = rx_dma;
|
||||
serial->serial_rx = rx_dma;
|
||||
} else {
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
|
||||
rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
|
||||
serial->config.bufsz);
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
|
||||
rt_memset(rx_fifo->buffer, 0, serial->config.bufsz);
|
||||
rx_fifo->put_index = 0;
|
||||
rx_fifo->get_index = 0;
|
||||
serial->serial_rx = rx_fifo;
|
||||
/* configure fifo address and length to low level device */
|
||||
serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *) RT_DEVICE_FLAG_DMA_RX);
|
||||
}
|
||||
dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
|
||||
}
|
||||
else if (oflag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
|
||||
rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
|
||||
rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
|
||||
serial->config.bufsz);
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1);
|
||||
@ -308,7 +428,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
|
||||
RT_ASSERT(tx_dma != RT_NULL);
|
||||
tx_dma->activated = RT_FALSE;
|
||||
|
||||
|
||||
rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
|
||||
serial->serial_tx = tx_dma;
|
||||
|
||||
@ -346,7 +466,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
|
||||
|
||||
/* this device has more reference count */
|
||||
if (dev->ref_count > 1) return RT_EOK;
|
||||
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
@ -362,12 +482,23 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
|
||||
}
|
||||
else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX)
|
||||
{
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
if (serial->config.bufsz == 0) {
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_tx;
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
|
||||
rt_free(rx_dma);
|
||||
rt_free(rx_dma);
|
||||
} else {
|
||||
struct rt_serial_rx_fifo* rx_fifo;
|
||||
|
||||
rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
rt_free(rx_fifo);
|
||||
}
|
||||
/* configure low level device */
|
||||
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *) RT_DEVICE_FLAG_DMA_RX);
|
||||
serial->serial_rx = RT_NULL;
|
||||
dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
|
||||
}
|
||||
@ -376,7 +507,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
|
||||
{
|
||||
struct rt_serial_tx_fifo* tx_fifo;
|
||||
|
||||
tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_rx;
|
||||
tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx;
|
||||
RT_ASSERT(tx_fifo != RT_NULL);
|
||||
|
||||
rt_free(tx_fifo);
|
||||
@ -534,30 +665,30 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
|
||||
ch = serial->ops->getc(serial);
|
||||
if (ch == -1) break;
|
||||
|
||||
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
|
||||
rx_fifo->buffer[rx_fifo->put_index] = ch;
|
||||
rx_fifo->put_index += 1;
|
||||
if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;
|
||||
|
||||
|
||||
/* if the next position is read index, discard this 'read char' */
|
||||
if (rx_fifo->put_index == rx_fifo->get_index)
|
||||
{
|
||||
rx_fifo->get_index += 1;
|
||||
if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
|
||||
}
|
||||
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
|
||||
/* invoke callback */
|
||||
if (serial->parent.rx_indicate != RT_NULL)
|
||||
{
|
||||
rt_size_t rx_length;
|
||||
|
||||
|
||||
/* get rx length */
|
||||
level = rt_hw_interrupt_disable();
|
||||
rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
|
||||
@ -584,19 +715,19 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
|
||||
struct rt_serial_tx_dma* tx_dma;
|
||||
|
||||
tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
|
||||
|
||||
|
||||
rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0);
|
||||
if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK)
|
||||
{
|
||||
/* transmit next data node */
|
||||
tx_dma->activated = RT_TRUE;
|
||||
serial->ops->dma_transmit(serial, data_ptr, data_size, RT_SERIAL_DMA_TX);
|
||||
serial->ops->dma_transmit(serial, (rt_uint8_t *)data_ptr, data_size, RT_SERIAL_DMA_TX);
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_dma->activated = RT_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* invoke callback */
|
||||
if (serial->parent.tx_complete != RT_NULL)
|
||||
{
|
||||
@ -607,13 +738,27 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
|
||||
case RT_SERIAL_EVENT_RX_DMADONE:
|
||||
{
|
||||
int length;
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
|
||||
/* get DMA rx length */
|
||||
length = (event & (~0xff)) >> 8;
|
||||
serial->parent.rx_indicate(&(serial->parent), length);
|
||||
rx_dma->activated = RT_FALSE;
|
||||
|
||||
if (serial->config.bufsz == 0) {
|
||||
struct rt_serial_rx_dma* rx_dma;
|
||||
|
||||
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
|
||||
RT_ASSERT(rx_dma != RT_NULL);
|
||||
|
||||
RT_ASSERT(serial->parent.rx_indicate != RT_NULL);
|
||||
serial->parent.rx_indicate(&(serial->parent), length);
|
||||
rx_dma->activated = RT_FALSE;
|
||||
} else {
|
||||
/* update fifo put index */
|
||||
rt_dma_recv_update_put_index(serial, length);
|
||||
/* invoke callback */
|
||||
if (serial->parent.rx_indicate != RT_NULL) {
|
||||
serial->parent.rx_indicate(&(serial->parent), rt_dma_calc_recved_len(serial));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ if GetDepend('RT_USING_AT45DBXX'):
|
||||
if GetDepend('RT_USING_SST25VFXX'):
|
||||
src_device += ['spi_flash_sst25vfxx.c']
|
||||
|
||||
if GetDepend('RT_USING_GD'):
|
||||
src_device += ['spi_flash_gd.c']
|
||||
|
||||
src += src_device
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH)
|
||||
|
@ -675,7 +675,7 @@ static struct pbuf *enc28j60_rx(rt_device_t dev)
|
||||
else
|
||||
{
|
||||
/* allocation pbuf */
|
||||
p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM);
|
||||
p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
|
||||
if (p != RT_NULL)
|
||||
{
|
||||
struct pbuf* q;
|
||||
|
36
components/drivers/spi/spi_flash.h
Normal file
36
components/drivers/spi/spi_flash.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* File : spi_flash.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2016, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016/5/20 bernard the first version
|
||||
*/
|
||||
|
||||
#ifndef SPI_FLASH_H__
|
||||
#define SPI_FLASH_H__
|
||||
|
||||
struct spi_flash_device
|
||||
{
|
||||
struct rt_device flash_device;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
struct rt_spi_device * rt_spi_device;
|
||||
struct rt_mutex lock;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,11 +1,21 @@
|
||||
/*
|
||||
* File : rtdef.h
|
||||
* File : spi_flash_at45dbxx.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rt-thread.org/license/LICENSE
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
|
@ -1,3 +1,27 @@
|
||||
/*
|
||||
* File : spi_flash_at45dbxx.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-16 aozima the first version
|
||||
*/
|
||||
|
||||
#ifndef SPI_FLASH_AT45DBXX_H_INCLUDED
|
||||
#define SPI_FLASH_AT45DBXX_H_INCLUDED
|
||||
|
||||
|
346
components/drivers/spi/spi_flash_gd.c
Normal file
346
components/drivers/spi/spi_flash_gd.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* File : spi_flash_gd.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd.
|
||||
* All rights reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-10-11 fullhan copy from winbond flash
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include "spi_flash.h"
|
||||
#include "spi_flash_gd.h"
|
||||
|
||||
#define FLASH_DEBUG
|
||||
|
||||
#ifdef FLASH_DEBUG
|
||||
#define FLASH_TRACE rt_kprintf
|
||||
#else
|
||||
#define FLASH_TRACE(...)
|
||||
#endif /* #ifdef FLASH_DEBUG */
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
/* JEDEC Manufacturer's ID */
|
||||
#define MF_ID (0xC8)
|
||||
/* JEDEC Device ID: Memory type and Capacity */
|
||||
#define MTC_GD25Q128 (0x4018)
|
||||
|
||||
/* command list */
|
||||
#define CMD_WRSR (0x01) /* Write Status Register */
|
||||
#define CMD_PP (0x02) /* Page Program */
|
||||
#define CMD_READ (0x03) /* Read Data */
|
||||
#define CMD_WRDI (0x04) /* Write Disable */
|
||||
#define CMD_RDSR1 (0x05) /* Read Status Register-1 */
|
||||
#define CMD_WREN (0x06) /* Write Enable */
|
||||
#define CMD_FAST_READ (0x0B) /* Fast Read */
|
||||
#define CMD_ERASE_4K (0x20) /* Sector Erase:4K */
|
||||
#define CMD_RDSR2 (0x35) /* Read Status Register-2 */
|
||||
#define CMD_ERASE_32K (0x52) /* 32KB Block Erase */
|
||||
#define CMD_JEDEC_ID (0x9F) /* Read JEDEC ID */
|
||||
#define CMD_ERASE_full (0xC7) /* Chip Erase */
|
||||
#define CMD_ERASE_64K (0xD8) /* 64KB Block Erase */
|
||||
|
||||
#define DUMMY (0xFF)
|
||||
|
||||
static struct spi_flash_device spi_flash_device;
|
||||
|
||||
static void flash_lock(struct spi_flash_device * flash_device)
|
||||
{
|
||||
rt_mutex_take(&flash_device->lock, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
static void flash_unlock(struct spi_flash_device * flash_device)
|
||||
{
|
||||
rt_mutex_release(&flash_device->lock);
|
||||
}
|
||||
|
||||
static uint8_t w25qxx_read_status(void)
|
||||
{
|
||||
return rt_spi_sendrecv8(spi_flash_device.rt_spi_device, CMD_RDSR1);
|
||||
}
|
||||
|
||||
static void w25qxx_wait_busy(void)
|
||||
{
|
||||
while( w25qxx_read_status() & (0x01));
|
||||
}
|
||||
|
||||
/** \brief read [size] byte from [offset] to [buffer]
|
||||
*
|
||||
* \param offset uint32_t unit : byte
|
||||
* \param buffer uint8_t*
|
||||
* \param size uint32_t unit : byte
|
||||
* \return uint32_t byte for read
|
||||
*
|
||||
*/
|
||||
static uint32_t w25qxx_read(uint32_t offset, uint8_t * buffer, uint32_t size)
|
||||
{
|
||||
uint8_t send_buffer[4];
|
||||
|
||||
send_buffer[0] = CMD_WRDI;
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
|
||||
|
||||
send_buffer[0] = CMD_READ;
|
||||
send_buffer[1] = (uint8_t)(offset>>16);
|
||||
send_buffer[2] = (uint8_t)(offset>>8);
|
||||
send_buffer[3] = (uint8_t)(offset);
|
||||
|
||||
rt_spi_send_then_recv(spi_flash_device.rt_spi_device,
|
||||
send_buffer, 4,
|
||||
buffer, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/** \brief write N page on [page]
|
||||
*
|
||||
* \param page_addr uint32_t unit : byte (4096 * N,1 page = 4096byte)
|
||||
* \param buffer const uint8_t*
|
||||
* \return uint32_t
|
||||
*
|
||||
*/
|
||||
static uint32_t w25qxx_page_write(uint32_t page_addr, const uint8_t* buffer)
|
||||
{
|
||||
uint32_t index;
|
||||
uint8_t send_buffer[4];
|
||||
|
||||
RT_ASSERT((page_addr&0xFF) == 0); /* page addr must align to 256byte. */
|
||||
|
||||
send_buffer[0] = CMD_WREN;
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
|
||||
|
||||
send_buffer[0] = CMD_ERASE_4K;
|
||||
send_buffer[1] = (page_addr >> 16);
|
||||
send_buffer[2] = (page_addr >> 8);
|
||||
send_buffer[3] = (page_addr);
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 4);
|
||||
|
||||
w25qxx_wait_busy(); // wait erase done.
|
||||
|
||||
for(index=0; index < (PAGE_SIZE / 256); index++)
|
||||
{
|
||||
send_buffer[0] = CMD_WREN;
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
|
||||
|
||||
send_buffer[0] = CMD_PP;
|
||||
send_buffer[1] = (uint8_t)(page_addr >> 16);
|
||||
send_buffer[2] = (uint8_t)(page_addr >> 8);
|
||||
send_buffer[3] = (uint8_t)(page_addr);
|
||||
|
||||
rt_spi_send_then_send(spi_flash_device.rt_spi_device,
|
||||
send_buffer,
|
||||
4,
|
||||
buffer,
|
||||
256);
|
||||
|
||||
buffer += 256;
|
||||
page_addr += 256;
|
||||
w25qxx_wait_busy();
|
||||
}
|
||||
|
||||
send_buffer[0] = CMD_WRDI;
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
|
||||
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
|
||||
/* RT-Thread device interface */
|
||||
static rt_err_t w25qxx_flash_init(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t w25qxx_flash_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
uint8_t send_buffer[3];
|
||||
|
||||
flash_lock((struct spi_flash_device *)dev);
|
||||
|
||||
send_buffer[0] = CMD_WREN;
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 1);
|
||||
|
||||
send_buffer[0] = CMD_WRSR;
|
||||
send_buffer[1] = 0;
|
||||
send_buffer[2] = 0;
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, send_buffer, 3);
|
||||
|
||||
w25qxx_wait_busy();
|
||||
|
||||
flash_unlock((struct spi_flash_device *)dev);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t w25qxx_flash_close(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t w25qxx_flash_control(rt_device_t dev, rt_uint8_t cmd, void *args)
|
||||
{
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
|
||||
{
|
||||
struct rt_device_blk_geometry *geometry;
|
||||
|
||||
geometry = (struct rt_device_blk_geometry *)args;
|
||||
if (geometry == RT_NULL) return -RT_ERROR;
|
||||
|
||||
geometry->bytes_per_sector = spi_flash_device.geometry.bytes_per_sector;
|
||||
geometry->sector_count = spi_flash_device.geometry.sector_count;
|
||||
geometry->block_size = spi_flash_device.geometry.block_size;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_t w25qxx_flash_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void* buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
flash_lock((struct spi_flash_device *)dev);
|
||||
|
||||
w25qxx_read(pos*spi_flash_device.geometry.bytes_per_sector,
|
||||
buffer,
|
||||
size*spi_flash_device.geometry.bytes_per_sector);
|
||||
|
||||
flash_unlock((struct spi_flash_device *)dev);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_size_t w25qxx_flash_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void* buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t i = 0;
|
||||
rt_size_t block = size;
|
||||
const uint8_t * ptr = buffer;
|
||||
|
||||
flash_lock((struct spi_flash_device *)dev);
|
||||
|
||||
while(block--)
|
||||
{
|
||||
w25qxx_page_write((pos + i)*spi_flash_device.geometry.bytes_per_sector,
|
||||
ptr);
|
||||
ptr += PAGE_SIZE;
|
||||
i++;
|
||||
}
|
||||
|
||||
flash_unlock((struct spi_flash_device *)dev);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
rt_err_t gd_init(const char * flash_device_name, const char * spi_device_name)
|
||||
{
|
||||
struct rt_spi_device * rt_spi_device;
|
||||
|
||||
/* initialize mutex */
|
||||
if (rt_mutex_init(&spi_flash_device.lock, spi_device_name, RT_IPC_FLAG_FIFO) != RT_EOK)
|
||||
{
|
||||
rt_kprintf("init sd lock mutex failed\n");
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
|
||||
if(rt_spi_device == RT_NULL)
|
||||
{
|
||||
FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
spi_flash_device.rt_spi_device = rt_spi_device;
|
||||
|
||||
/* config spi */
|
||||
{
|
||||
struct rt_spi_configuration cfg;
|
||||
cfg.data_width = 8;
|
||||
cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
|
||||
cfg.max_hz = 50 * 1000 * 1000; /* 50M */
|
||||
rt_spi_configure(spi_flash_device.rt_spi_device, &cfg);
|
||||
}
|
||||
|
||||
/* init flash */
|
||||
{
|
||||
rt_uint8_t cmd;
|
||||
rt_uint8_t id_recv[3];
|
||||
uint16_t memory_type_capacity;
|
||||
|
||||
flash_lock(&spi_flash_device);
|
||||
|
||||
cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
|
||||
|
||||
cmd = CMD_WRDI;
|
||||
rt_spi_send(spi_flash_device.rt_spi_device, &cmd, 1);
|
||||
|
||||
/* read flash id */
|
||||
cmd = CMD_JEDEC_ID;
|
||||
rt_spi_send_then_recv(spi_flash_device.rt_spi_device, &cmd, 1, id_recv, 3);
|
||||
|
||||
flash_unlock(&spi_flash_device);
|
||||
|
||||
if(id_recv[0] != MF_ID)
|
||||
{
|
||||
FLASH_TRACE("Manufacturers ID error!\r\n");
|
||||
FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
spi_flash_device.geometry.bytes_per_sector = 4096;
|
||||
spi_flash_device.geometry.block_size = 4096; /* block erase: 4k */
|
||||
|
||||
/* get memory type and capacity */
|
||||
memory_type_capacity = id_recv[1];
|
||||
memory_type_capacity = (memory_type_capacity << 8) | id_recv[2];
|
||||
|
||||
if(memory_type_capacity == MTC_GD25Q128)
|
||||
{
|
||||
FLASH_TRACE("GD128 detection\r\n");
|
||||
spi_flash_device.geometry.sector_count = 4096;
|
||||
}
|
||||
else
|
||||
{
|
||||
FLASH_TRACE("Memory Capacity error!\r\n");
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
/* register device */
|
||||
spi_flash_device.flash_device.type = RT_Device_Class_Block;
|
||||
spi_flash_device.flash_device.init = w25qxx_flash_init;
|
||||
spi_flash_device.flash_device.open = w25qxx_flash_open;
|
||||
spi_flash_device.flash_device.close = w25qxx_flash_close;
|
||||
spi_flash_device.flash_device.read = w25qxx_flash_read;
|
||||
spi_flash_device.flash_device.write = w25qxx_flash_write;
|
||||
spi_flash_device.flash_device.control = w25qxx_flash_control;
|
||||
/* no private */
|
||||
spi_flash_device.flash_device.user_data = RT_NULL;
|
||||
|
||||
rt_device_register(&spi_flash_device.flash_device, flash_device_name,
|
||||
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
32
components/drivers/spi/spi_flash_gd.h
Normal file
32
components/drivers/spi/spi_flash_gd.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* File : spi_flash_gd.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2016, RT-Thread Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-10-11 fullhan copy from winbond flash
|
||||
*/
|
||||
|
||||
#ifndef SPI_FLASH_GD_H_
|
||||
#define SPI_FLASH_GD_H_
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
extern rt_err_t gd_init(const char * flash_device_name, const char * spi_device_name);
|
||||
|
||||
#endif /* SPI_FLASH_GD_H_ */
|
@ -1,11 +1,21 @@
|
||||
/*
|
||||
* File : rtdef.h
|
||||
* File : spi_flash_sst25vfxx.c
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rt-thread.org/license/LICENSE
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
|
@ -1,11 +1,21 @@
|
||||
/*
|
||||
* File : rtdef.h
|
||||
* File : spi_flash_sst25vxx.h
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rt-thread.org/license/LICENSE
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
|
@ -3,9 +3,19 @@
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rt-thread.org/license/LICENSE
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
@ -13,10 +23,12 @@
|
||||
* 2012-05-06 aozima can page write.
|
||||
* 2012-08-23 aozima add flash lock.
|
||||
* 2012-08-24 aozima fixed write status register BUG.
|
||||
* 2015-05-13 bernard add GD25Q flash ID.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include "spi_flash.h"
|
||||
#include "spi_flash_w25qxx.h"
|
||||
|
||||
#define FLASH_DEBUG
|
||||
@ -31,7 +43,6 @@
|
||||
|
||||
/* JEDEC Manufacturer<65><72>s ID */
|
||||
#define MF_ID (0xEF)
|
||||
#define GD_ID (0xC8)
|
||||
|
||||
/* JEDEC Device ID: Memory type and Capacity */
|
||||
#define MTC_W25Q80_BV (0x4014) /* W25Q80BV */
|
||||
@ -301,7 +312,7 @@ rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_nam
|
||||
|
||||
flash_unlock(&spi_flash_device);
|
||||
|
||||
if(id_recv[0] != MF_ID && id_recv[0] != GD_ID)
|
||||
if(id_recv[0] != MF_ID)
|
||||
{
|
||||
FLASH_TRACE("Manufacturers ID error!\r\n");
|
||||
FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
|
||||
|
@ -3,9 +3,19 @@
|
||||
* This file is part of RT-Thread RTOS
|
||||
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rt-thread.org/license/LICENSE
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
@ -17,18 +27,8 @@
|
||||
#define SPI_FLASH_W25QXX_H_INCLUDED
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <drivers/spi.h>
|
||||
|
||||
struct spi_flash_device
|
||||
{
|
||||
struct rt_device flash_device;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
struct rt_spi_device * rt_spi_device;
|
||||
struct rt_mutex lock;
|
||||
};
|
||||
|
||||
extern rt_err_t w25qxx_init(const char * flash_device_name,
|
||||
const char * spi_device_name);
|
||||
|
||||
|
||||
#endif // SPI_FLASH_W25QXX_H_INCLUDED
|
||||
|
6
components/external/cairo/SConscript
vendored
6
components/external/cairo/SConscript
vendored
@ -1,11 +1,9 @@
|
||||
Import('RTT_ROOT')
|
||||
Import('rtconfig')
|
||||
|
||||
from building import *
|
||||
import os
|
||||
|
||||
CAIRO_VERSION = '1.10.2'
|
||||
CAIRO_PATH = 'cairo-' + CAIRO_VERSION
|
||||
cwd = GetCurrentDir()
|
||||
|
||||
if GetDepend('RT_USING_CAIRO') and not os.path.exists(CAIRO_PATH):
|
||||
print '================ERROR============================'
|
||||
@ -99,7 +97,7 @@ cairo.c
|
||||
for item in range(len(src)):
|
||||
src[item] = CAIRO_PATH + '/src/' + src[item]
|
||||
|
||||
CPPPATH = [RTT_ROOT + '/components/external/cairo/' + CAIRO_PATH + '/src', RTT_ROOT + '/components/external/cairo/']
|
||||
CPPPATH = [cwd + '/' + CAIRO_PATH + '/src', cwd]
|
||||
group = DefineGroup('cairo', src, depend = ['RT_USING_CAIRO', 'RT_USING_NEWLIB', 'RTGUI_IMAGE_PNG', 'RT_USING_PTHREADS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
5
components/external/lzo/SConscript
vendored
5
components/external/lzo/SConscript
vendored
@ -1,12 +1,11 @@
|
||||
Import('RTT_ROOT')
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split('''
|
||||
minilzo.c
|
||||
lzo.c
|
||||
''')
|
||||
CPPPATH = [RTT_ROOT + '/components/external/lzo']
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('lzo', src, depend = ['RT_USING_LZO'], CPPPATH = CPPPATH)
|
||||
|
||||
|
5
components/external/nanopb/SConscript
vendored
5
components/external/nanopb/SConscript
vendored
@ -1,13 +1,12 @@
|
||||
Import('RTT_ROOT')
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split('''
|
||||
pb_common.c
|
||||
pb_decode.c
|
||||
pb_encode.c
|
||||
''')
|
||||
CPPPATH = [RTT_ROOT + '/components/external/nanopb']
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Nanopb', src, depend = ['RT_USING_NANOPB'], CPPPATH = CPPPATH)
|
||||
|
||||
|
@ -17,4 +17,7 @@ else:
|
||||
if rtconfig.PLATFORM == 'gcc' and rtconfig.ARCH != 'sim':
|
||||
objs = objs + SConscript('minilibc/SConscript')
|
||||
|
||||
objs = objs + SConscript('pthreads/SConscript')
|
||||
objs = objs + SConscript('libdl/SConscript')
|
||||
|
||||
Return('objs')
|
||||
|
@ -1,9 +1,9 @@
|
||||
Import('RTT_ROOT')
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [RTT_ROOT + '/components/libdl']
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('libdl', src, depend = ['RT_USING_MODULE', 'RT_USING_LIBDL'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
@ -447,3 +447,18 @@ void __libc_init_array(void)
|
||||
{
|
||||
/* we not use __libc init_aray to initialize C++ objects */
|
||||
}
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
if (rt_thread_self())
|
||||
{
|
||||
rt_thread_t self = rt_thread_self();
|
||||
|
||||
rt_kprintf("thread:%-8.*s abort!\n", RT_NAME_MAX, self->name);
|
||||
rt_thread_suspend(self);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [RTT_ROOT + '/components/pthreads']
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('pthreads', src, depend = ['RT_USING_PTHREADS', 'RT_USING_LIBC'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
@ -142,6 +142,20 @@ typedef struct pthread_barrier pthread_barrier_t;
|
||||
/* pthread thread interface */
|
||||
int pthread_attr_destroy(pthread_attr_t *attr);
|
||||
int pthread_attr_init(pthread_attr_t *attr);
|
||||
int pthread_attr_setdetachstate(pthread_attr_t *attr, int state);
|
||||
int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state);
|
||||
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
|
||||
int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy);
|
||||
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size);
|
||||
int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size);
|
||||
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr);
|
||||
int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr);
|
||||
int pthread_attr_setstack(pthread_attr_t *attr,
|
||||
void *stack_base,
|
||||
size_t stack_size);
|
||||
int pthread_attr_getstack(pthread_attr_t const *attr,
|
||||
void **stack_base,
|
||||
size_t *stack_size);
|
||||
|
||||
int pthread_system_init(void);
|
||||
int pthread_create (pthread_t *tid, const pthread_attr_t *attr,
|
@ -4,14 +4,15 @@ Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
objs = []
|
||||
list = os.listdir(os.path.join(RTT_ROOT, 'components', 'net'))
|
||||
cwd = GetCurrentDir()
|
||||
list = os.listdir(cwd)
|
||||
|
||||
# the default version of LWIP is 1.4.1
|
||||
if not GetDepend('RT_USING_LWIP132') and not GetDepend('RT_USING_LWIP140') and not GetDepend('RT_USING_LWIP_HEAD'):
|
||||
AddDepend('RT_USING_LWIP141')
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(RTT_ROOT, 'components', 'net', d)
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
|
||||
|
@ -76,7 +76,7 @@ typedef rt_uint32_t mem_ptr_t;
|
||||
#define LWIP_TIMEVAL_PRIVATE 1
|
||||
#endif
|
||||
|
||||
#if defined(RT_USING_DFS_LWIP)
|
||||
#if defined(RT_USING_DFS_NET)
|
||||
#define LWIP_COMPAT_SOCKETS 0
|
||||
#endif
|
||||
|
||||
|
@ -1248,6 +1248,12 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
|
||||
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
|
||||
/* concatenate unsent queue after unacked queue */
|
||||
seg->next = pcb->unsent;
|
||||
#if TCP_OVERSIZE && TCP_OVERSIZE_DBGCHECK
|
||||
/* if last unsent changed, we need to update unsent_oversize */
|
||||
if (pcb->unsent == NULL) {
|
||||
pcb->unsent_oversize = seg->oversize_left;
|
||||
}
|
||||
#endif /* TCP_OVERSIZE && TCP_OVERSIZE_DBGCHECK*/
|
||||
/* unsent queue is the concatenated queue (of unacked, unsent) */
|
||||
pcb->unsent = pcb->unacked;
|
||||
/* unacked queue is now empty */
|
||||
|
@ -139,6 +139,7 @@ PACK_STRUCT_END
|
||||
#define ETHTYPE_VLAN 0x8100U
|
||||
#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */
|
||||
#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */
|
||||
#define ETHTYPE_EAPOL 0x888eU /* EAPOL */
|
||||
|
||||
/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
|
||||
* or known to be 32-bit aligned within the protocol header. */
|
||||
|
@ -38,10 +38,6 @@
|
||||
#define LWIP_PLATFORM_BYTESWAP 0
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
/* Enable SO_RCVTIMEO/LWIP_SO_SNDTIMEO processing. */
|
||||
#define LWIP_SO_RCVTIMEO 1
|
||||
#define LWIP_SO_SNDTIMEO 1
|
||||
|
||||
/* #define RT_LWIP_DEBUG */
|
||||
|
||||
#ifdef RT_LWIP_DEBUG
|
||||
@ -355,5 +351,62 @@
|
||||
#include <stdlib.h>
|
||||
#define LWIP_RAND rand
|
||||
#endif
|
||||
/*
|
||||
------------------------------------
|
||||
---------- Socket options ----------
|
||||
------------------------------------
|
||||
*/
|
||||
/*
|
||||
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
|
||||
*/
|
||||
#ifndef LWIP_SOCKET
|
||||
#define LWIP_SOCKET 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names.
|
||||
* (only used if you use sockets.c)
|
||||
*/
|
||||
#ifndef LWIP_COMPAT_SOCKETS
|
||||
#define LWIP_COMPAT_SOCKETS 1
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and
|
||||
* SO_SNDTIMEO processing.
|
||||
*/
|
||||
#ifndef LWIP_SO_SNDTIMEO
|
||||
#define LWIP_SO_SNDTIMEO 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
|
||||
* SO_RCVTIMEO processing.
|
||||
*/
|
||||
#ifndef LWIP_SO_RCVTIMEO
|
||||
#define LWIP_SO_RCVTIMEO 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.
|
||||
*/
|
||||
#ifndef LWIP_SO_RCVBUF
|
||||
#define LWIP_SO_RCVBUF 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.
|
||||
*/
|
||||
#ifndef RECV_BUFSIZE_DEFAULT
|
||||
#define RECV_BUFSIZE_DEFAULT 8192
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SO_REUSE==1: Enable SO_REUSEADDR option.
|
||||
*/
|
||||
#ifndef SO_REUSE
|
||||
#define SO_REUSE 0
|
||||
#endif
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
src/ - The source code for the lwIP TCP/IP stack.
|
||||
doc/ - The documentation for lwIP.
|
||||
|
||||
See also the FILES file in each subdirectory.
|
@ -1,89 +0,0 @@
|
||||
INTRODUCTION
|
||||
|
||||
lwIP is a small independent implementation of the TCP/IP protocol
|
||||
suite that has been developed by Adam Dunkels at the Computer and
|
||||
Networks Architectures (CNA) lab at the Swedish Institute of Computer
|
||||
Science (SICS).
|
||||
|
||||
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
|
||||
while still having a full scale TCP. This making lwIP suitable for use
|
||||
in embedded systems with tens of kilobytes of free RAM and room for
|
||||
around 40 kilobytes of code ROM.
|
||||
|
||||
FEATURES
|
||||
|
||||
* IP (Internet Protocol) including packet forwarding over multiple network
|
||||
interfaces
|
||||
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
|
||||
* IGMP (Internet Group Management Protocol) for multicast traffic management
|
||||
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
|
||||
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
|
||||
and fast recovery/fast retransmit
|
||||
* Specialized raw/native API for enhanced performance
|
||||
* Optional Berkeley-like socket API
|
||||
* DNS (Domain names resolver)
|
||||
* SNMP (Simple Network Management Protocol)
|
||||
* DHCP (Dynamic Host Configuration Protocol)
|
||||
* AUTOIP (for IPv4, conform with RFC 3927)
|
||||
* PPP (Point-to-Point Protocol)
|
||||
* ARP (Address Resolution Protocol) for Ethernet
|
||||
|
||||
LICENSE
|
||||
|
||||
lwIP is freely available under a BSD license.
|
||||
|
||||
DEVELOPMENT
|
||||
|
||||
lwIP has grown into an excellent TCP/IP stack for embedded devices,
|
||||
and developers using the stack often submit bug fixes, improvements,
|
||||
and additions to the stack to further increase its usefulness.
|
||||
|
||||
Development of lwIP is hosted on Savannah, a central point for
|
||||
software development, maintenance and distribution. Everyone can
|
||||
help improve lwIP by use of Savannah's interface, CVS and the
|
||||
mailing list. A core team of developers will commit changes to the
|
||||
CVS source tree.
|
||||
|
||||
The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
|
||||
contributions (such as platform ports) are in the 'contrib' module.
|
||||
|
||||
See doc/savannah.txt for details on CVS server access for users and
|
||||
developers.
|
||||
|
||||
Last night's CVS tar ball can be downloaded from:
|
||||
http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]
|
||||
|
||||
The current CVS trees are web-browsable:
|
||||
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
|
||||
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
|
||||
|
||||
Submit patches and bugs via the lwIP project page:
|
||||
http://savannah.nongnu.org/projects/lwip/
|
||||
|
||||
|
||||
DOCUMENTATION
|
||||
|
||||
The original out-dated homepage of lwIP and Adam Dunkels' papers on
|
||||
lwIP are at the official lwIP home page:
|
||||
http://www.sics.se/~adam/lwip/
|
||||
|
||||
Self documentation of the source code is regularly extracted from the
|
||||
current CVS sources and is available from this web page:
|
||||
http://www.nongnu.org/lwip/
|
||||
|
||||
There is now a constantly growin wiki about lwIP at
|
||||
http://lwip.wikia.com/wiki/LwIP_Wiki
|
||||
|
||||
Also, there are mailing lists you can subscribe at
|
||||
http://savannah.nongnu.org/mail/?group=lwip
|
||||
plus searchable archives:
|
||||
http://lists.nongnu.org/archive/html/lwip-users/
|
||||
http://lists.nongnu.org/archive/html/lwip-devel/
|
||||
|
||||
Reading Adam's papers, the files in docs/, browsing the source code
|
||||
documentation and browsing the mailing list archives is a good way to
|
||||
become familiar with the design of lwIP.
|
||||
|
||||
Adam Dunkels <adam@sics.se>
|
||||
Leon Woestenberg <leon.woestenberg@gmx.net>
|
||||
|
@ -1,87 +0,0 @@
|
||||
Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
src = Split("""
|
||||
src/api/api_lib.c
|
||||
src/api/api_msg.c
|
||||
src/api/err.c
|
||||
src/api/netbuf.c
|
||||
src/api/netdb.c
|
||||
src/api/netifapi.c
|
||||
src/api/sockets.c
|
||||
src/api/tcpip.c
|
||||
src/arch/sys_arch.c
|
||||
src/core/def.c
|
||||
src/core/dhcp.c
|
||||
src/core/dns.c
|
||||
src/core/init.c
|
||||
src/core/memp.c
|
||||
src/core/netif.c
|
||||
src/core/pbuf.c
|
||||
src/core/raw.c
|
||||
src/core/stats.c
|
||||
src/core/sys.c
|
||||
src/core/tcp.c
|
||||
src/core/tcp_in.c
|
||||
src/core/tcp_out.c
|
||||
src/core/timers.c
|
||||
src/core/udp.c
|
||||
src/core/ipv4/autoip.c
|
||||
src/core/ipv4/icmp.c
|
||||
src/core/ipv4/igmp.c
|
||||
src/core/ipv4/inet.c
|
||||
src/core/ipv4/inet_chksum.c
|
||||
src/core/ipv4/ip.c
|
||||
src/core/ipv4/ip_addr.c
|
||||
src/core/ipv4/ip_frag.c
|
||||
src/netif/etharp.c
|
||||
src/netif/ethernetif.c
|
||||
src/netif/slipif.c
|
||||
""")
|
||||
|
||||
snmp_src = Split("""
|
||||
src/core/snmp/asn1_dec.c
|
||||
src/core/snmp/asn1_enc.c
|
||||
src/core/snmp/mib2.c
|
||||
src/core/snmp/mib_structs.c
|
||||
src/core/snmp/msg_in.c
|
||||
src/core/snmp/msg_out.c
|
||||
""")
|
||||
|
||||
ppp_src = Split("""
|
||||
src/netif/ppp/auth.c
|
||||
src/netif/ppp/chap.c
|
||||
src/netif/ppp/chpms.c
|
||||
src/netif/ppp/fsm.c
|
||||
src/netif/ppp/ipcp.c
|
||||
src/netif/ppp/lcp.c
|
||||
src/netif/ppp/magic.c
|
||||
src/netif/ppp/md5.c
|
||||
src/netif/ppp/pap.c
|
||||
src/netif/ppp/ppp.c
|
||||
src/netif/ppp/ppp_oe.c
|
||||
src/netif/ppp/randm.c
|
||||
src/netif/ppp/vj.c
|
||||
""")
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
path = [GetCurrentDir() + '/src',
|
||||
GetCurrentDir() + '/src/include',
|
||||
GetCurrentDir() + '/src/include/ipv4',
|
||||
GetCurrentDir() + '/src/arch/include',
|
||||
GetCurrentDir() + '/src/include/netif']
|
||||
|
||||
if GetDepend(['RT_LWIP_SNMP']):
|
||||
src += snmp_src
|
||||
|
||||
if GetDepend(['RT_LWIP_PPP']):
|
||||
src += ppp_src
|
||||
path += [GetCurrentDir() + '/src/netif/ppp']
|
||||
|
||||
# For testing apps
|
||||
if GetDepend(['RT_USING_NETUTILS']):
|
||||
src += Glob('./apps/*.c')
|
||||
|
||||
group = DefineGroup('LwIP', src, depend = ['RT_USING_LWIP', 'RT_USING_LWIP140'], CPPPATH = path)
|
||||
|
||||
Return('group')
|
@ -1,144 +0,0 @@
|
||||
This file lists major changes between release versions that require
|
||||
ports or applications to be changed. Use it to update a port or an
|
||||
application written for an older version of lwIP to correctly work
|
||||
with newer versions.
|
||||
|
||||
|
||||
(CVS HEAD)
|
||||
|
||||
* [Enter new changes just after this line - do not remove this line]
|
||||
|
||||
++ Application changes:
|
||||
|
||||
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
|
||||
compatibility to old applications, but will be removed in the future).
|
||||
|
||||
* Renamed mem_realloc() to mem_trim() to prevent confusion with realloc()
|
||||
|
||||
+++ Raw API:
|
||||
* Changed the semantics of tcp_close() (since it was rather a
|
||||
shutdown before): Now the application does *NOT* get any calls to the recv
|
||||
callback (aside from NULL/closed) after calling tcp_close()
|
||||
|
||||
* When calling tcp_abort() from a raw API TCP callback function,
|
||||
make sure you return ERR_ABRT to prevent accessing unallocated memory.
|
||||
(ERR_ABRT now means the applicaiton has called tcp_abort!)
|
||||
|
||||
+++ Netconn API:
|
||||
* Changed netconn_receive() and netconn_accept() to return
|
||||
err_t, not a pointer to new data/netconn.
|
||||
|
||||
+++ Socket API:
|
||||
* LWIP_SO_RCVTIMEO: when accept() or recv() time out, they
|
||||
now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT.
|
||||
|
||||
* Added a minimal version of posix fctl() to have a
|
||||
standardised way to set O_NONBLOCK for nonblocking sockets.
|
||||
|
||||
+++ all APIs:
|
||||
* correctly implemented SO(F)_REUSEADDR
|
||||
|
||||
++ Port changes
|
||||
|
||||
+++ new files:
|
||||
|
||||
* Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h:
|
||||
|
||||
* Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains
|
||||
the actual application programmer's API
|
||||
|
||||
* Separated timer implementation from sys.h/.c, moved to timers.h/.c;
|
||||
Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you
|
||||
still want to use your own timer implementation for NO_SYS==0 (as before).
|
||||
|
||||
+++ sys layer:
|
||||
|
||||
* Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/
|
||||
sys_sem_t;
|
||||
|
||||
* Converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
|
||||
|
||||
* Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use
|
||||
binary semaphores instead of mutexes - as before)
|
||||
|
||||
+++ new options:
|
||||
|
||||
* Don't waste memory when chaining segments, added option TCP_OVERSIZE to
|
||||
prevent creating many small pbufs when calling tcp_write with many small
|
||||
blocks of data. Instead, pbufs are allocated larger than needed and the
|
||||
space is used for later calls to tcp_write.
|
||||
|
||||
* Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs
|
||||
in tcp_write/udp_send.
|
||||
|
||||
* Added an additional option LWIP_ETHERNET to support ethernet without ARP
|
||||
(necessary for pure PPPoE)
|
||||
|
||||
* Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may
|
||||
be used to place these pools into user-defined memory by using external
|
||||
declaration.
|
||||
|
||||
* Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT
|
||||
|
||||
+++ new pools:
|
||||
|
||||
* Netdb uses a memp pool for allocating memory when getaddrinfo() is called,
|
||||
so MEMP_NUM_NETDB has to be set accordingly.
|
||||
|
||||
* DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so
|
||||
MEMP_NUM_LOCALHOSTLIST has to be set accordingly.
|
||||
|
||||
* Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have
|
||||
to be set accordingly.
|
||||
|
||||
* PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES
|
||||
has to be set accordingly
|
||||
|
||||
* Integrated loopif into netif.c - loopif does not have to be created by the
|
||||
port any more, just define LWIP_HAVE_LOOPIF to 1.
|
||||
|
||||
* Added define LWIP_RAND() for lwip-wide randomization (needs to be defined
|
||||
in cc.h, e.g. used by igmp)
|
||||
|
||||
* Added printf-formatter X8_F to printf u8_t as hex
|
||||
|
||||
* The heap now may be moved to user-defined memory by defining
|
||||
LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
|
||||
|
||||
* added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work
|
||||
with user-allocated structs instead of calling mem_malloc
|
||||
|
||||
* Added const char* name to mem- and memp-stats for easier debugging.
|
||||
|
||||
* Calculate the TCP/UDP checksum while copying to only fetch data once:
|
||||
Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum
|
||||
|
||||
* Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to
|
||||
more than one pcb.
|
||||
|
||||
* Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned
|
||||
off any more, if this is set to 0, only one packet (the most recent one) is
|
||||
queued (like demanded by RFC 1122).
|
||||
|
||||
|
||||
++ Major bugfixes/improvements
|
||||
|
||||
* Implemented tcp_shutdown() to only shut down one end of a connection
|
||||
* Implemented shutdown() at socket- and netconn-level
|
||||
* Added errorset support to select() + improved select speed overhead
|
||||
* Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x)
|
||||
* Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1
|
||||
* Use macros defined in ip_addr.h to work with IP addresses
|
||||
* Implemented many nonblocking socket/netconn functions
|
||||
* Fixed ARP input processing: only add a new entry if a request was directed as us
|
||||
* mem_realloc() to mem_trim() to prevent confusion with realloc()
|
||||
* Some improvements for AutoIP (don't route/forward link-local addresses, don't break
|
||||
existing connections when assigning a routable address)
|
||||
* Correctly handle remote side overrunning our rcv_wnd in ooseq case
|
||||
* Removed packing from ip_addr_t, the packed version is now only used in protocol headers
|
||||
* Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0
|
||||
* Added support for static ARP table entries
|
||||
|
||||
(STABLE-1.3.2)
|
||||
|
||||
* initial version of this file
|
@ -1,7 +0,0 @@
|
||||
Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
src = Glob('*.c')
|
||||
group = DefineGroup('netutils', src, depend = ['RT_USING_NETUTILS'])
|
||||
|
||||
Return('group')
|
@ -1,216 +0,0 @@
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#define MAX_SERV 32 /* Maximum number of chargen services. Don't need too many */
|
||||
#define CHARGEN_THREAD_NAME "chargen"
|
||||
#if RT_THREAD_PRIORITY_MAX == 32
|
||||
#define CHARGEN_PRIORITY 20 /* Really low priority */
|
||||
#else
|
||||
#define CHARGEN_PRIORITY 200 /* Really low priority */
|
||||
#endif
|
||||
#define CHARGEN_THREAD_STACKSIZE 1024
|
||||
struct charcb
|
||||
{
|
||||
struct charcb *next;
|
||||
int socket;
|
||||
struct sockaddr_in cliaddr;
|
||||
socklen_t clilen;
|
||||
char nextchar;
|
||||
};
|
||||
|
||||
static struct charcb *charcb_list = 0;
|
||||
static int do_read(struct charcb *p_charcb);
|
||||
static void close_chargen(struct charcb *p_charcb);
|
||||
|
||||
/**************************************************************
|
||||
* void chargen_thread(void *arg)
|
||||
*
|
||||
* chargen task. This server will wait for connections on well
|
||||
* known TCP port number: 19. For every connection, the server will
|
||||
* write as much data as possible to the tcp port.
|
||||
**************************************************************/
|
||||
static void chargen_thread(void *arg)
|
||||
{
|
||||
int listenfd;
|
||||
struct sockaddr_in chargen_saddr;
|
||||
fd_set readset;
|
||||
fd_set writeset;
|
||||
int i, maxfdp1;
|
||||
struct charcb *p_charcb;
|
||||
|
||||
/* First acquire our socket for listening for connections */
|
||||
listenfd = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0);
|
||||
memset(&chargen_saddr, 0, sizeof(chargen_saddr));
|
||||
chargen_saddr.sin_family = AF_INET;
|
||||
chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
chargen_saddr.sin_port = htons(19); // Chargen server port
|
||||
|
||||
if (lwip_bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1)
|
||||
LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0);
|
||||
|
||||
/* Put socket into listening mode */
|
||||
if (lwip_listen(listenfd, MAX_SERV) == -1)
|
||||
LWIP_ASSERT("chargen_thread(): Listen failed.", 0);
|
||||
|
||||
/* Wait forever for network input: This could be connections or data */
|
||||
for (;;)
|
||||
{
|
||||
maxfdp1 = listenfd+1;
|
||||
|
||||
/* Determine what sockets need to be in readset */
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&writeset);
|
||||
FD_SET(listenfd, &readset);
|
||||
for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
|
||||
{
|
||||
if (maxfdp1 < p_charcb->socket + 1)
|
||||
maxfdp1 = p_charcb->socket + 1;
|
||||
FD_SET(p_charcb->socket, &readset);
|
||||
FD_SET(p_charcb->socket, &writeset);
|
||||
}
|
||||
|
||||
/* Wait for data or a new connection */
|
||||
i = lwip_select(maxfdp1, &readset, &writeset, 0, 0);
|
||||
|
||||
if (i == 0) continue;
|
||||
|
||||
/* At least one descriptor is ready */
|
||||
if (FD_ISSET(listenfd, &readset))
|
||||
{
|
||||
/* We have a new connection request!!! */
|
||||
/* Lets create a new control block */
|
||||
p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb));
|
||||
if (p_charcb)
|
||||
{
|
||||
p_charcb->socket = lwip_accept(listenfd,
|
||||
(struct sockaddr *) &p_charcb->cliaddr,
|
||||
&p_charcb->clilen);
|
||||
if (p_charcb->socket < 0)
|
||||
rt_free(p_charcb);
|
||||
else
|
||||
{
|
||||
/* Keep this tecb in our list */
|
||||
p_charcb->next = charcb_list;
|
||||
charcb_list = p_charcb;
|
||||
p_charcb->nextchar = 0x21;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No memory to accept connection. Just accept and then close */
|
||||
int sock;
|
||||
struct sockaddr cliaddr;
|
||||
socklen_t clilen;
|
||||
|
||||
sock = lwip_accept(listenfd, &cliaddr, &clilen);
|
||||
if (sock >= 0)
|
||||
lwip_close(sock);
|
||||
}
|
||||
}
|
||||
/* Go through list of connected clients and process data */
|
||||
for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next)
|
||||
{
|
||||
if (FD_ISSET(p_charcb->socket, &readset))
|
||||
{
|
||||
/* This socket is ready for reading. This could be because someone typed
|
||||
* some characters or it could be because the socket is now closed. Try reading
|
||||
* some data to see. */
|
||||
if (do_read(p_charcb) < 0)
|
||||
break;
|
||||
}
|
||||
if (FD_ISSET(p_charcb->socket, &writeset))
|
||||
{
|
||||
char line[80];
|
||||
char setchar = p_charcb->nextchar;
|
||||
|
||||
for( i = 0; i < 59; i++)
|
||||
{
|
||||
line[i] = setchar;
|
||||
if (++setchar == 0x7f)
|
||||
setchar = 0x21;
|
||||
}
|
||||
line[i] = 0;
|
||||
strcat(line, "\n\r");
|
||||
if (lwip_write(p_charcb->socket, line, strlen(line)) < 0)
|
||||
{
|
||||
close_chargen(p_charcb);
|
||||
break;
|
||||
}
|
||||
if (++p_charcb->nextchar == 0x7f)
|
||||
p_charcb->nextchar = 0x21;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* void close_chargen(struct charcb *p_charcb)
|
||||
*
|
||||
* Close the socket and remove this charcb from the list.
|
||||
**************************************************************/
|
||||
static void close_chargen(struct charcb *p_charcb)
|
||||
{
|
||||
struct charcb *p_search_charcb;
|
||||
|
||||
/* Either an error or tcp connection closed on other
|
||||
* end. Close here */
|
||||
lwip_close(p_charcb->socket);
|
||||
|
||||
/* Free charcb */
|
||||
if (charcb_list == p_charcb)
|
||||
charcb_list = p_charcb->next;
|
||||
else
|
||||
for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next)
|
||||
{
|
||||
if (p_search_charcb->next == p_charcb)
|
||||
{
|
||||
p_search_charcb->next = p_charcb->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_free(p_charcb);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* void do_read(struct charcb *p_charcb)
|
||||
*
|
||||
* Socket definitely is ready for reading. Read a buffer from the socket and
|
||||
* discard the data. If no data is read, then the socket is closed and the
|
||||
* charcb is removed from the list and freed.
|
||||
**************************************************************/
|
||||
static int do_read(struct charcb *p_charcb)
|
||||
{
|
||||
char buffer[80];
|
||||
int readcount;
|
||||
|
||||
/* Read some data */
|
||||
readcount = lwip_read(p_charcb->socket, &buffer, 80);
|
||||
if (readcount <= 0)
|
||||
{
|
||||
close_chargen(p_charcb);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void chargen_init(void)
|
||||
{
|
||||
rt_thread_t chargen;
|
||||
|
||||
chargen = rt_thread_create(CHARGEN_THREAD_NAME,
|
||||
chargen_thread, RT_NULL,
|
||||
CHARGEN_THREAD_STACKSIZE,
|
||||
CHARGEN_PRIORITY, 5);
|
||||
if (chargen != RT_NULL) rt_thread_startup(chargen);
|
||||
}
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
void chargen()
|
||||
{
|
||||
chargen_init();
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(chargen, start chargen server);
|
||||
#endif
|
@ -1,985 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs_posix.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <time.h>
|
||||
|
||||
#define FTP_PORT 21
|
||||
#define FTP_SRV_ROOT "/"
|
||||
#define FTP_MAX_CONNECTION 2
|
||||
#define FTP_USER "rtt"
|
||||
#define FTP_PASSWORD "demo"
|
||||
#define FTP_WELCOME_MSG "220 welcome on RT-Thread FTP server.\r\n"
|
||||
#define FTP_BUFFER_SIZE 1024
|
||||
|
||||
#define INET_ADDRSTRLEN 16
|
||||
|
||||
|
||||
struct ftp_session
|
||||
{
|
||||
rt_bool_t is_anonymous;
|
||||
|
||||
int sockfd;
|
||||
struct sockaddr_in remote;
|
||||
struct sockaddr_in server;
|
||||
|
||||
char serveraddr[INET_ADDRSTRLEN];
|
||||
|
||||
/* pasv data */
|
||||
int pasv_listen_sockfd;
|
||||
char pasv_active;
|
||||
int pasv_sockfd;
|
||||
|
||||
unsigned short pasv_port;
|
||||
size_t offset;
|
||||
|
||||
/* current directory */
|
||||
char currentdir[256];
|
||||
|
||||
struct ftp_session* next;
|
||||
};
|
||||
static struct ftp_session* session_list = NULL;
|
||||
|
||||
int ftp_process_request(struct ftp_session* session, char * buf);
|
||||
int ftp_get_filesize(char *filename);
|
||||
|
||||
struct ftp_session* ftp_new_session()
|
||||
{
|
||||
struct ftp_session* session;
|
||||
|
||||
session = (struct ftp_session*)rt_malloc(sizeof(struct ftp_session));
|
||||
rt_memset((void *)session, 0, sizeof(struct ftp_session));
|
||||
|
||||
session->next = session_list;
|
||||
session_list = session;
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
void ftp_close_session(struct ftp_session* session)
|
||||
{
|
||||
struct ftp_session* list;
|
||||
|
||||
if (session_list == session)
|
||||
{
|
||||
session_list = session_list->next;
|
||||
session->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
list = session_list;
|
||||
while (list->next != session) list = list->next;
|
||||
|
||||
list->next = session->next;
|
||||
session->next = NULL;
|
||||
}
|
||||
|
||||
rt_free(session);
|
||||
}
|
||||
|
||||
static int open_data_connection(struct ftp_session* session)
|
||||
{
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
struct sockaddr_in sin;
|
||||
#if 0
|
||||
/* Previous PORT command from client */
|
||||
if (ctrl->data_address[0]) {
|
||||
ctrl->data_sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (-1 == ctrl->data_sd) {
|
||||
printf("Failed creating data socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(ctrl->data_port);
|
||||
inet_aton(ctrl->data_address, &(sin.sin_addr));
|
||||
|
||||
if (connect(ctrl->data_sd, (struct sockaddr *)&sin, len) == -1) {
|
||||
printf("Failed connecting data socket to client");
|
||||
close(ctrl->data_sd);
|
||||
ctrl->data_sd = -1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
DBG("Connected successfully to client's previously requested address:PORT %s:%d", ctrl->data_address, ctrl->data_port);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* Previous PASV command, accept connect from client */
|
||||
if (session->pasv_listen_sockfd > 0) {
|
||||
char client_ip[100];
|
||||
|
||||
session->pasv_sockfd = accept(session->pasv_listen_sockfd, (struct sockaddr *)&sin, &len);
|
||||
if (-1 == session->pasv_sockfd) {
|
||||
printf("Failed accepting connection from client");
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = sizeof(struct sockaddr);
|
||||
if (-1 == getpeername(session->pasv_sockfd, (struct sockaddr *)&sin, &len)) {
|
||||
printf("Cannot determine client address");
|
||||
closesocket(session->pasv_sockfd);
|
||||
session->pasv_sockfd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Client PASV data connection from %s\n", inet_ntoa(sin.sin_addr));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void close_data_connection(struct ftp_session* session)
|
||||
{
|
||||
/* PASV server listening socket */
|
||||
if (session->pasv_listen_sockfd > 0) {
|
||||
closesocket(session->pasv_listen_sockfd);
|
||||
session->pasv_listen_sockfd = -1;
|
||||
}
|
||||
|
||||
/* PASV client socket */
|
||||
if (session->pasv_sockfd > 0) {
|
||||
closesocket(session->pasv_sockfd);
|
||||
session->pasv_sockfd = -1;
|
||||
}
|
||||
#if 0
|
||||
/* PORT */
|
||||
if (ctrl->data_address[0]) {
|
||||
ctrl->data_address[0] = 0;
|
||||
ctrl->data_port = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int ftp_get_filesize(char * filename)
|
||||
{
|
||||
int pos;
|
||||
int end;
|
||||
int fd;
|
||||
|
||||
fd = open(filename, O_RDONLY, 0);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
pos = lseek(fd, 0, SEEK_CUR);
|
||||
end = lseek(fd, 0, SEEK_END);
|
||||
lseek (fd, pos, SEEK_SET);
|
||||
close(fd);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
rt_bool_t is_absolute_path(char* path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (path[0] == '\\' ||
|
||||
(path[1] == ':' && path[2] == '\\'))
|
||||
return RT_TRUE;
|
||||
#else
|
||||
if (path[0] == '/') return RT_TRUE;
|
||||
#endif
|
||||
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
int build_full_path(struct ftp_session* session, char* path, char* new_path, size_t size)
|
||||
{
|
||||
if (is_absolute_path(path) == RT_TRUE)
|
||||
strcpy(new_path, path);
|
||||
else
|
||||
{
|
||||
rt_sprintf(new_path, "%s/%s", session->currentdir, path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ftpd_thread_entry(void* parameter)
|
||||
{
|
||||
int numbytes;
|
||||
int sockfd, maxfdp1;
|
||||
struct sockaddr_in local;
|
||||
fd_set readfds, tmpfds;
|
||||
struct ftp_session* session;
|
||||
rt_uint32_t addr_len = sizeof(struct sockaddr);
|
||||
char * buffer = (char *) rt_malloc(FTP_BUFFER_SIZE);
|
||||
|
||||
local.sin_port=htons(FTP_PORT);
|
||||
local.sin_family=PF_INET;
|
||||
local.sin_addr.s_addr=INADDR_ANY;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&tmpfds);
|
||||
|
||||
sockfd=socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(sockfd < 0)
|
||||
{
|
||||
rt_kprintf("create socket failed\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
bind(sockfd, (struct sockaddr *)&local, addr_len);
|
||||
listen(sockfd, FTP_MAX_CONNECTION);
|
||||
|
||||
FD_SET(sockfd, &readfds);
|
||||
for(;;)
|
||||
{
|
||||
/* get maximum fd */
|
||||
maxfdp1 = sockfd + 1;
|
||||
session = session_list;
|
||||
while (session != RT_NULL)
|
||||
{
|
||||
if (maxfdp1 < session->sockfd + 1)
|
||||
maxfdp1 = session->sockfd + 1;
|
||||
|
||||
FD_SET(session->sockfd, &readfds);
|
||||
session = session->next;
|
||||
}
|
||||
|
||||
tmpfds=readfds;
|
||||
if (select(maxfdp1, &tmpfds, 0, 0, 0) == 0) continue;
|
||||
|
||||
if(FD_ISSET(sockfd, &tmpfds))
|
||||
{
|
||||
int com_socket;
|
||||
struct sockaddr_in remote;
|
||||
|
||||
com_socket = accept(sockfd, (struct sockaddr*)&remote, &addr_len);
|
||||
if(com_socket == -1)
|
||||
{
|
||||
rt_kprintf("Error on accept()\nContinuing...\n");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Got connection from %s\n", inet_ntoa(remote.sin_addr));
|
||||
send(com_socket, FTP_WELCOME_MSG, strlen(FTP_WELCOME_MSG), 0);
|
||||
FD_SET(com_socket, &readfds);
|
||||
|
||||
/* new session */
|
||||
session = ftp_new_session();
|
||||
if (session != NULL)
|
||||
{
|
||||
if (-1 == getsockname(com_socket, (struct sockaddr *)&session->server, &addr_len)) {
|
||||
printf("Cannot determine our address, need it if client should connect to us\n");
|
||||
}
|
||||
ipaddr_ntoa_r(&(session->server.sin_addr), session->serveraddr, sizeof(session->serveraddr));
|
||||
strcpy(session->currentdir, FTP_SRV_ROOT);
|
||||
session->sockfd = com_socket;
|
||||
session->remote = remote;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct ftp_session* next;
|
||||
|
||||
session = session_list;
|
||||
while (session != NULL)
|
||||
{
|
||||
next = session->next;
|
||||
if (FD_ISSET(session->sockfd, &tmpfds))
|
||||
{
|
||||
numbytes=recv(session->sockfd, buffer, FTP_BUFFER_SIZE, 0);
|
||||
if(numbytes==0 || numbytes==-1)
|
||||
{
|
||||
rt_kprintf("Client %s disconnected\n", inet_ntoa(session->remote.sin_addr));
|
||||
FD_CLR(session->sockfd, &readfds);
|
||||
closesocket(session->sockfd);
|
||||
session->sockfd = -1;
|
||||
ftp_close_session(session);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[numbytes]=0;
|
||||
if(ftp_process_request(session, buffer)==-1)
|
||||
{
|
||||
rt_kprintf("Client %s disconnected\r\n", inet_ntoa(session->remote.sin_addr));
|
||||
closesocket(session->sockfd);
|
||||
session->sockfd = -1;
|
||||
ftp_close_session(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rt_free(buffer);
|
||||
}
|
||||
|
||||
int do_list(char* directory, int sockfd)
|
||||
{
|
||||
DIR* dirp;
|
||||
struct dirent* entry;
|
||||
char line_buffer[256], line_length;
|
||||
#ifdef _WIN32
|
||||
struct _stat s;
|
||||
#else
|
||||
struct stat s;
|
||||
#endif
|
||||
|
||||
dirp = opendir(directory);
|
||||
if (dirp == NULL)
|
||||
{
|
||||
line_length = rt_sprintf(line_buffer, "500 Internal Error\r\n");
|
||||
send(sockfd, line_buffer, line_length, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
entry = readdir(dirp);
|
||||
if (entry == NULL) break;
|
||||
|
||||
rt_sprintf(line_buffer, "%s/%s", directory, entry->d_name);
|
||||
#ifdef _WIN32
|
||||
if (_stat(line_buffer, &s) ==0)
|
||||
#else
|
||||
if (stat(line_buffer, &s) == 0)
|
||||
#endif
|
||||
{
|
||||
if (s.st_mode & S_IFDIR)
|
||||
line_length = rt_sprintf(line_buffer, "drw-r--r-- 1 admin admin %d Jan 1 2000 %s\r\n", 0, entry->d_name);
|
||||
else
|
||||
line_length = rt_sprintf(line_buffer, "-rw-r--r-- 1 admin admin %d Jan 1 2000 %s\r\n", s.st_size, entry->d_name);
|
||||
|
||||
send(sockfd, line_buffer, line_length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Get directory entry error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_simple_list(char* directory, int sockfd)
|
||||
{
|
||||
DIR* dirp;
|
||||
struct dirent* entry;
|
||||
char line_buffer[256], line_length;
|
||||
|
||||
dirp = opendir(directory);
|
||||
if (dirp == NULL)
|
||||
{
|
||||
line_length = rt_sprintf(line_buffer, "500 Internal Error\r\n");
|
||||
send(sockfd, line_buffer, line_length, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
entry = readdir(dirp);
|
||||
if (entry == NULL) break;
|
||||
|
||||
line_length = rt_sprintf(line_buffer, "%s\r\n", entry->d_name);
|
||||
send(sockfd, line_buffer, line_length, 0);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int str_begin_with(char* src, char* match)
|
||||
{
|
||||
while (*match)
|
||||
{
|
||||
/* check source */
|
||||
if (*src == 0) return -1;
|
||||
|
||||
if (*match != *src) return -1;
|
||||
match ++; src ++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftp_process_request(struct ftp_session* session, char *buf)
|
||||
{
|
||||
int fd;
|
||||
struct timeval tv;
|
||||
fd_set readfds;
|
||||
char filename[256];
|
||||
int numbytes;
|
||||
char *sbuf;
|
||||
char *parameter_ptr, *ptr;
|
||||
rt_uint32_t addr_len = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in local, pasvremote;
|
||||
|
||||
sbuf =(char *)rt_malloc(FTP_BUFFER_SIZE);
|
||||
|
||||
tv.tv_sec=3, tv.tv_usec=0;
|
||||
local.sin_family=PF_INET;
|
||||
local.sin_addr.s_addr=INADDR_ANY;
|
||||
|
||||
/* remove \r\n */
|
||||
ptr = buf;
|
||||
while (*ptr)
|
||||
{
|
||||
if (*ptr == '\r' || *ptr == '\n') *ptr = 0;
|
||||
ptr ++;
|
||||
}
|
||||
|
||||
/* get request parameter */
|
||||
parameter_ptr = strchr(buf, ' '); if (parameter_ptr != NULL) parameter_ptr ++;
|
||||
|
||||
// debug:
|
||||
rt_kprintf("%s requested: \"%s\"\n", inet_ntoa(session->remote.sin_addr), buf);
|
||||
|
||||
//
|
||||
//-----------------------
|
||||
if(str_begin_with(buf, "USER")==0)
|
||||
{
|
||||
rt_kprintf("%s sent login \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
|
||||
// login correct
|
||||
if(strcmp(parameter_ptr, "anonymous") == 0)
|
||||
{
|
||||
session->is_anonymous = RT_TRUE;
|
||||
rt_sprintf(sbuf, "331 Anonymous login OK send e-mail address for password.\r\n", parameter_ptr);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if (strcmp(parameter_ptr, FTP_USER) == 0)
|
||||
{
|
||||
session->is_anonymous = RT_FALSE;
|
||||
rt_sprintf(sbuf, "331 Password required for %s\r\n", parameter_ptr);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// incorrect login
|
||||
rt_sprintf(sbuf, "530 Login incorrect. Bye.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if(str_begin_with(buf, "PASS")==0)
|
||||
{
|
||||
rt_kprintf("%s sent password \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
|
||||
if (strcmp(parameter_ptr, FTP_PASSWORD)==0 ||
|
||||
session->is_anonymous == RT_TRUE)
|
||||
{
|
||||
// password correct
|
||||
rt_sprintf(sbuf, "230 User logged in.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// incorrect password
|
||||
rt_sprintf(sbuf, "530 Login or Password incorrect. Bye!\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return -1;
|
||||
}
|
||||
else if(str_begin_with(buf, "LIST")==0 )
|
||||
{
|
||||
memset(sbuf,0,FTP_BUFFER_SIZE);
|
||||
open_data_connection(session);
|
||||
rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
do_list(session->currentdir, session->pasv_sockfd);
|
||||
close_data_connection(session);
|
||||
session->pasv_active = 0;
|
||||
rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "NLST")==0 )
|
||||
{
|
||||
memset(sbuf, 0, FTP_BUFFER_SIZE);
|
||||
rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
open_data_connection(session);
|
||||
do_simple_list(session->currentdir, session->pasv_sockfd);
|
||||
close_data_connection(session);
|
||||
session->pasv_active = 0;
|
||||
rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "PWD")==0 || str_begin_with(buf, "XPWD")==0)
|
||||
{
|
||||
rt_sprintf(sbuf, "257 \"%s\" is current directory.\r\n", session->currentdir);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "TYPE")==0)
|
||||
{
|
||||
// Ignore it
|
||||
if(strcmp(parameter_ptr, "I")==0)
|
||||
{
|
||||
rt_sprintf(sbuf, "200 Type set to binary.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sprintf(sbuf, "200 Type set to ascii.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
}
|
||||
else if(str_begin_with(buf, "PASV")==0)
|
||||
{
|
||||
int dig1, dig2;
|
||||
//int sockfd;
|
||||
int optval=1;
|
||||
int port;
|
||||
struct sockaddr_in data;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
char *msg, *p;
|
||||
|
||||
if (session->pasv_sockfd > 0) {
|
||||
closesocket(session->pasv_sockfd);
|
||||
session->pasv_sockfd = -1;
|
||||
}
|
||||
|
||||
if (session->pasv_listen_sockfd > 0)
|
||||
closesocket(session->pasv_listen_sockfd);
|
||||
|
||||
session->pasv_port = 10000;
|
||||
session->pasv_active = 1;
|
||||
local.sin_port=htons(session->pasv_port);
|
||||
local.sin_addr.s_addr=INADDR_ANY;
|
||||
|
||||
dig1 = (int)(session->pasv_port/256);
|
||||
dig2 = session->pasv_port % 256;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
if((session->pasv_listen_sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1)
|
||||
{
|
||||
rt_sprintf(sbuf, "425 Can't open data connection0.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
goto err1;
|
||||
}
|
||||
if(setsockopt(session->pasv_listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1)
|
||||
{
|
||||
rt_sprintf(sbuf, "425 Can't open data connection1.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
goto err1;
|
||||
}
|
||||
if(bind(session->pasv_listen_sockfd, (struct sockaddr *)&local, addr_len)==-1)
|
||||
{
|
||||
rt_sprintf(sbuf, "425 Can't open data connection2.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
goto err1;
|
||||
}
|
||||
if(listen(session->pasv_listen_sockfd, 1)==-1)
|
||||
{
|
||||
rt_sprintf(sbuf, "425 Can't open data connection3.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
goto err1;
|
||||
}
|
||||
if (-1 == getsockname(session->pasv_listen_sockfd, (struct sockaddr *)&data, &len)) {
|
||||
rt_kprintf("Cannot determine our address, need it if client should connect to us\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
port = ntohs(data.sin_port);
|
||||
rt_kprintf("Port %d\n", port);
|
||||
|
||||
/* Convert server IP address and port to comma separated list */
|
||||
msg = strdup(session->serveraddr);
|
||||
if (!msg) {
|
||||
rt_sprintf(sbuf, "426 Internal server error.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
goto err1;
|
||||
}
|
||||
p = msg;
|
||||
while ((p = strchr(p, '.')))
|
||||
*p++ = ',';
|
||||
|
||||
rt_kprintf("Listening %d seconds @ port %d\n", tv.tv_sec, session->pasv_port);
|
||||
rt_sprintf(sbuf, "227 Entering passive mode (%s,%d,%d)\r\n", msg, port / 256, port % 256);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
rt_free(msg);
|
||||
return 0;
|
||||
#if 0
|
||||
FD_SET(sockfd, &readfds);
|
||||
select(0, &readfds, 0, 0, &tv);
|
||||
if(FD_ISSET(sockfd, &readfds))
|
||||
{
|
||||
if((session->pasv_sockfd = accept(sockfd, (struct sockaddr*)&pasvremote, &addr_len))==-1)
|
||||
{
|
||||
rt_sprintf(sbuf, "425 Can't open data connection4.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
goto err1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Got Data(PASV) connection from %s\n", inet_ntoa(pasvremote.sin_addr));
|
||||
session->pasv_active = 1;
|
||||
closesocket(sockfd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err1:
|
||||
closesocket(session->pasv_sockfd);
|
||||
session->pasv_active = 0;
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
err1:
|
||||
close_data_connection(session);
|
||||
session->pasv_active = 0;
|
||||
rt_free(sbuf);
|
||||
rt_free(msg);
|
||||
return 0;
|
||||
|
||||
}
|
||||
else if (str_begin_with(buf, "RETR")==0)
|
||||
{
|
||||
int file_size;
|
||||
|
||||
open_data_connection(session);
|
||||
|
||||
strcpy(filename, buf + 5);
|
||||
|
||||
build_full_path(session, parameter_ptr, filename, 256);
|
||||
file_size = ftp_get_filesize(filename);
|
||||
if (file_size == -1)
|
||||
{
|
||||
rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
session->offset=0;
|
||||
close_data_connection(session);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = open(filename, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
close_data_connection(session);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(session->offset>0 && session->offset < file_size)
|
||||
{
|
||||
lseek(fd, session->offset, SEEK_SET);
|
||||
rt_sprintf(sbuf, "150 Opening binary mode data connection for partial \"%s\" (%d/%d bytes).\r\n",
|
||||
filename, file_size - session->offset, file_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\" (%d bytes).\r\n", filename, file_size);
|
||||
}
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
while((numbytes = read(fd, sbuf, FTP_BUFFER_SIZE))>0)
|
||||
{
|
||||
send(session->pasv_sockfd, sbuf, numbytes, 0);
|
||||
}
|
||||
rt_sprintf(sbuf, "226 Finished.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
close(fd);
|
||||
close_data_connection(session);
|
||||
}
|
||||
else if (str_begin_with(buf, "STOR")==0)
|
||||
{
|
||||
open_data_connection(session);
|
||||
if(session->is_anonymous == RT_TRUE)
|
||||
{
|
||||
rt_sprintf(sbuf, "550 Permission denied.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
close_data_connection(session);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
build_full_path(session, parameter_ptr, filename, 256);
|
||||
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
|
||||
if(fd < 0)
|
||||
{
|
||||
rt_sprintf(sbuf, "550 Cannot open \"%s\" for writing.\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
close_data_connection(session);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\".\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(session->pasv_sockfd, &readfds);
|
||||
rt_kprintf("Waiting %d seconds for data...\n", tv.tv_sec);
|
||||
while(select(session->pasv_sockfd+1, &readfds, 0, 0, &tv)>0 )
|
||||
{
|
||||
if((numbytes=recv(session->pasv_sockfd, sbuf, FTP_BUFFER_SIZE, 0))>0)
|
||||
{
|
||||
write(fd, sbuf, numbytes);
|
||||
}
|
||||
else if(numbytes==0)
|
||||
{
|
||||
close(fd);
|
||||
close_data_connection(session);
|
||||
rt_sprintf(sbuf, "226 Finished.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
break;
|
||||
}
|
||||
else if(numbytes==-1)
|
||||
{
|
||||
close(fd);
|
||||
close_data_connection(session);
|
||||
rt_free(sbuf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
close_data_connection(session);
|
||||
}
|
||||
else if(str_begin_with(buf, "SIZE")==0)
|
||||
{
|
||||
int file_size;
|
||||
|
||||
build_full_path(session, parameter_ptr, filename, 256);
|
||||
|
||||
file_size = ftp_get_filesize(filename);
|
||||
if( file_size == -1)
|
||||
{
|
||||
rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sprintf(sbuf, "213 %d\r\n", file_size);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
}
|
||||
else if(str_begin_with(buf, "MDTM")==0)
|
||||
{
|
||||
rt_sprintf(sbuf, "550 \"/\" : not a regular file\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "SYST")==0)
|
||||
{
|
||||
rt_sprintf(sbuf, "215 %s\r\n", "RT-Thread RTOS");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "CWD")==0)
|
||||
{
|
||||
build_full_path(session, parameter_ptr, filename, 256);
|
||||
|
||||
rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
strcpy(session->currentdir, filename);
|
||||
rt_kprintf("Changed to directory %s", filename);
|
||||
}
|
||||
else if(str_begin_with(buf, "CDUP")==0)
|
||||
{
|
||||
rt_sprintf(filename, "%s/%s", session->currentdir, "..");
|
||||
|
||||
rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
strcpy(session->currentdir, filename);
|
||||
rt_kprintf("Changed to directory %s", filename);
|
||||
}
|
||||
else if(str_begin_with(buf, "PORT")==0)
|
||||
{
|
||||
int i;
|
||||
int portcom[6];
|
||||
char tmpip[100];
|
||||
|
||||
i=0;
|
||||
portcom[i++]=atoi(strtok(parameter_ptr, ".,;()"));
|
||||
for(;i<6;i++)
|
||||
portcom[i]=atoi(strtok(0, ".,;()"));
|
||||
rt_sprintf(tmpip, "%d.%d.%d.%d", portcom[0], portcom[1], portcom[2], portcom[3]);
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
if((session->pasv_sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1)
|
||||
{
|
||||
rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
closesocket(session->pasv_sockfd);
|
||||
session->pasv_active = 0;
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
pasvremote.sin_addr.s_addr=inet_addr(tmpip);
|
||||
pasvremote.sin_port=htons(portcom[4] * 256 + portcom[5]);
|
||||
pasvremote.sin_family=PF_INET;
|
||||
if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1)
|
||||
{
|
||||
// is it only local address?try using gloal ip addr
|
||||
pasvremote.sin_addr=session->remote.sin_addr;
|
||||
if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1)
|
||||
{
|
||||
rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
closesocket(session->pasv_sockfd);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
session->pasv_active=1;
|
||||
session->pasv_port = portcom[4] * 256 + portcom[5];
|
||||
rt_kprintf("Connected to Data(PORT) %s @ %d\n", tmpip, portcom[4] * 256 + portcom[5]);
|
||||
rt_sprintf(sbuf, "200 Port Command Successful.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "REST")==0)
|
||||
{
|
||||
if(atoi(parameter_ptr)>=0)
|
||||
{
|
||||
session->offset=atoi(parameter_ptr);
|
||||
rt_sprintf(sbuf, "350 Send RETR or STOR to start transfert.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
}
|
||||
else if(str_begin_with(buf, "MKD")==0)
|
||||
{
|
||||
if (session->is_anonymous == RT_TRUE)
|
||||
{
|
||||
rt_sprintf(sbuf, "530 Permission denied.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
build_full_path(session, parameter_ptr, filename, 256);
|
||||
|
||||
if(mkdir(filename, 0) == -1)
|
||||
{
|
||||
rt_sprintf(sbuf, "550 File \"%s\" exists.\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sprintf(sbuf, "257 directory \"%s\" successfully created.\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
}
|
||||
else if(str_begin_with(buf, "DELE")==0)
|
||||
{
|
||||
if (session->is_anonymous == RT_TRUE)
|
||||
{
|
||||
rt_sprintf(sbuf, "530 Permission denied.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
build_full_path(session, parameter_ptr, filename, 256);
|
||||
|
||||
if(unlink(filename)==0)
|
||||
rt_sprintf(sbuf, "250 Successfully deleted file \"%s\".\r\n", filename);
|
||||
else
|
||||
{
|
||||
rt_sprintf(sbuf, "550 Not such file or directory: %s.\r\n", filename);
|
||||
}
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "RMD")==0)
|
||||
{
|
||||
if (session->is_anonymous == RT_TRUE)
|
||||
{
|
||||
rt_sprintf(sbuf, "530 Permission denied.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
build_full_path(session, parameter_ptr, filename, 256);
|
||||
|
||||
if(unlink(filename) == -1)
|
||||
{
|
||||
rt_sprintf(sbuf, "550 Directory \"%s\" doesn't exist.\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sprintf(sbuf, "257 directory \"%s\" successfully deleted.\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
}
|
||||
else if(str_begin_with(buf, "RNFR")==0)
|
||||
{
|
||||
if (session->is_anonymous == RT_TRUE)
|
||||
{
|
||||
rt_sprintf(sbuf, "530 Permission denied.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
build_full_path(session, parameter_ptr, filename, 256);
|
||||
|
||||
rt_sprintf(sbuf, "350 Successfully rececive old file \"%s\".\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "RNTO")==0)
|
||||
{
|
||||
char new_filename[256];
|
||||
if (session->is_anonymous == RT_TRUE)
|
||||
{
|
||||
rt_sprintf(sbuf, "530 Permission denied.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
build_full_path(session, parameter_ptr, new_filename, 256);
|
||||
|
||||
if(rename(filename, new_filename) == -1)
|
||||
{
|
||||
rt_sprintf(sbuf, "553 rename file \"%s\" error.\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sprintf(sbuf, "250 Successfully rename to new file \"%s\".\r\n", filename);
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
}
|
||||
else if((str_begin_with(buf, "NOOP")==0) || str_begin_with(buf, "noop")==0)
|
||||
{
|
||||
rt_sprintf(sbuf, "200 noop!\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
else if(str_begin_with(buf, "QUIT")==0)
|
||||
{
|
||||
rt_sprintf(sbuf, "221 Bye!\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
rt_free(sbuf);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sprintf(sbuf, "502 Not Implemented.\r\n");
|
||||
send(session->sockfd, sbuf, strlen(sbuf), 0);
|
||||
}
|
||||
rt_free(sbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ftpd_start()
|
||||
{
|
||||
rt_thread_t tid;
|
||||
|
||||
tid = rt_thread_create("ftpd",
|
||||
ftpd_thread_entry, RT_NULL,
|
||||
4096, 30, 5);
|
||||
if (tid != RT_NULL) rt_thread_startup(tid);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
FINSH_FUNCTION_EXPORT(ftpd_start, start ftp server);
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
int cmd_ftpd_start(int argc, char** argv)
|
||||
{
|
||||
ftpd_start();
|
||||
return 0;
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(cmd_ftpd_start, __cmd_ftpd_start, start ftp server.);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,370 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* MetIO Server
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
*/
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_TCP
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
/*
|
||||
* This implements a netio server.
|
||||
* The client sends a command word (4 bytes) then a data length word (4 bytes).
|
||||
* If the command is "receive", the server is to consume "data length" bytes into
|
||||
* a circular buffer until the first byte is non-zero, then it is to consume
|
||||
* another command/data pair.
|
||||
* If the command is "send", the server is to send "data length" bytes from a circular
|
||||
* buffer with the first byte being zero, until "some time" (6 seconds in the
|
||||
* current netio126.zip download) has passed and then send one final buffer with
|
||||
* the first byte being non-zero. Then it is to consume another command/data pair.
|
||||
*/
|
||||
|
||||
/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */
|
||||
|
||||
/* implementation options */
|
||||
#define NETIO_BUF_SIZE (4 * 1024)
|
||||
#define NETIO_USE_STATIC_BUF 0
|
||||
|
||||
/* NetIO server state definition */
|
||||
#define NETIO_STATE_WAIT_FOR_CMD 0
|
||||
#define NETIO_STATE_RECV_DATA 1
|
||||
#define NETIO_STATE_SEND_DATA 2
|
||||
#define NETIO_STATE_SEND_DATA_LAST 3
|
||||
#define NETIO_STATE_DONE 4
|
||||
|
||||
struct netio_state {
|
||||
u32_t state;
|
||||
u32_t cmd;
|
||||
u32_t data_len;
|
||||
u32_t cntr;
|
||||
u8_t * buf_ptr;
|
||||
u32_t buf_pos;
|
||||
u32_t first_byte;
|
||||
u32_t time_stamp;
|
||||
};
|
||||
|
||||
/* NetIO command protocol definition */
|
||||
#define NETIO_CMD_QUIT 0
|
||||
#define NETIO_CMD_C2S 1
|
||||
#define NETIO_CMD_S2C 2
|
||||
#define NETIO_CMD_RES 3
|
||||
|
||||
static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
|
||||
|
||||
static void
|
||||
netio_close(void *arg, struct tcp_pcb *pcb)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
struct netio_state *ns = arg;
|
||||
ns->state = NETIO_STATE_DONE;
|
||||
tcp_recv(pcb, NULL);
|
||||
err = tcp_close(pcb);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
/* closing failed, try again later */
|
||||
tcp_recv(pcb, netio_recv);
|
||||
} else {
|
||||
/* closing succeeded */
|
||||
#if NETIO_USE_STATIC_BUF != 1
|
||||
if(ns->buf_ptr != NULL){
|
||||
mem_free(ns->buf_ptr);
|
||||
}
|
||||
#endif
|
||||
tcp_arg(pcb, NULL);
|
||||
tcp_poll(pcb, NULL, 0);
|
||||
tcp_sent(pcb, NULL);
|
||||
if (arg != NULL) {
|
||||
mem_free(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static err_t
|
||||
netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||
{
|
||||
struct netio_state *ns = arg;
|
||||
u8_t * data_ptr;
|
||||
u32_t data_cntr;
|
||||
struct pbuf *q = p;
|
||||
u16_t len;
|
||||
|
||||
if (p != NULL) {
|
||||
tcp_recved(pcb, p->tot_len);
|
||||
}
|
||||
|
||||
if (err == ERR_OK && q != NULL) {
|
||||
|
||||
while (q != NULL) {
|
||||
data_cntr = q->len;
|
||||
data_ptr = q->payload;
|
||||
while (data_cntr--) {
|
||||
if (ns->state == NETIO_STATE_DONE){
|
||||
netio_close(ns, pcb);
|
||||
break;
|
||||
} else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) {
|
||||
if (ns->cntr < 4) {
|
||||
/* build up the CMD field */
|
||||
ns->cmd <<= 8;
|
||||
ns->cmd |= *data_ptr++;
|
||||
ns->cntr++;
|
||||
} else if (ns->cntr < 8) {
|
||||
/* build up the DATA field */
|
||||
ns->data_len <<= 8;
|
||||
ns->data_len |= *data_ptr++;
|
||||
ns->cntr++;
|
||||
|
||||
if (ns->cntr == 8) {
|
||||
/* now we have full command and data words */
|
||||
ns->cntr = 0;
|
||||
ns->buf_pos = 0;
|
||||
ns->buf_ptr[0] = 0;
|
||||
if (ns->cmd == NETIO_CMD_C2S) {
|
||||
ns->state = NETIO_STATE_RECV_DATA;
|
||||
} else if (ns->cmd == NETIO_CMD_S2C) {
|
||||
ns->state = NETIO_STATE_SEND_DATA;
|
||||
/* start timer */
|
||||
ns->time_stamp = rt_tick_get();
|
||||
/* send first round of data */
|
||||
|
||||
len = tcp_sndbuf(pcb);
|
||||
len = LWIP_MIN(len, ns->data_len - ns->cntr);
|
||||
len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
|
||||
|
||||
do {
|
||||
err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
|
||||
if (err == ERR_MEM) {
|
||||
len /= 2;
|
||||
}
|
||||
} while ((err == ERR_MEM) && (len > 1));
|
||||
|
||||
ns->buf_pos += len;
|
||||
ns->cntr += len;
|
||||
|
||||
} else {
|
||||
/* unrecognized command, punt */
|
||||
ns->cntr = 0;
|
||||
ns->buf_pos = 0;
|
||||
ns->buf_ptr[0] = 0;
|
||||
netio_close(ns, pcb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* in trouble... shouldn't be in this state! */
|
||||
}
|
||||
|
||||
} else if (ns->state == NETIO_STATE_RECV_DATA) {
|
||||
|
||||
if(ns->cntr == 0){
|
||||
/* save the first byte of this new round of data
|
||||
* this will not match ns->buf_ptr[0] in the case that
|
||||
* NETIO_BUF_SIZE is less than ns->data_len.
|
||||
*/
|
||||
ns->first_byte = *data_ptr;
|
||||
}
|
||||
|
||||
ns->buf_ptr[ns->buf_pos++] = *data_ptr++;
|
||||
ns->cntr++;
|
||||
|
||||
if (ns->buf_pos == NETIO_BUF_SIZE) {
|
||||
/* circularize the buffer */
|
||||
ns->buf_pos = 0;
|
||||
}
|
||||
|
||||
if(ns->cntr == ns->data_len){
|
||||
ns->cntr = 0;
|
||||
if (ns->first_byte != 0) {
|
||||
/* if this last round did not start with 0,
|
||||
* go look for another command */
|
||||
ns->state = NETIO_STATE_WAIT_FOR_CMD;
|
||||
ns->data_len = 0;
|
||||
ns->cmd = 0;
|
||||
/* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
|
||||
} else {
|
||||
/* stay here and wait on more data */
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ns->state == NETIO_STATE_SEND_DATA
|
||||
|| ns->state == NETIO_STATE_SEND_DATA_LAST) {
|
||||
/* I don't think this should happen... */
|
||||
} else {
|
||||
/* done / quit */
|
||||
netio_close(ns, pcb);
|
||||
break;
|
||||
} /* end of ns->state condition */
|
||||
} /* end of while data still in this pbuf */
|
||||
|
||||
q = q->next;
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
|
||||
} else {
|
||||
|
||||
/* error or closed by other side */
|
||||
if (p != NULL) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
/* close the connection */
|
||||
netio_close(ns, pcb);
|
||||
|
||||
}
|
||||
return ERR_OK;
|
||||
|
||||
}
|
||||
|
||||
static err_t
|
||||
netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
|
||||
{
|
||||
struct netio_state *ns = arg;
|
||||
err_t err = ERR_OK;
|
||||
|
||||
if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) {
|
||||
/* done with this round of sending */
|
||||
ns->buf_pos = 0;
|
||||
ns->cntr = 0;
|
||||
|
||||
/* check if timer expired */
|
||||
if (rt_tick_get() - ns->time_stamp > 600) {
|
||||
ns->buf_ptr[0] = 1;
|
||||
ns->state = NETIO_STATE_SEND_DATA_LAST;
|
||||
} else {
|
||||
ns->buf_ptr[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){
|
||||
len = tcp_sndbuf(pcb);
|
||||
len = LWIP_MIN(len, ns->data_len - ns->cntr);
|
||||
len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
|
||||
|
||||
if(ns->cntr < ns->data_len){
|
||||
do {
|
||||
err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
|
||||
if (err == ERR_MEM) {
|
||||
len /= 2;
|
||||
}
|
||||
} while ((err == ERR_MEM) && (len > 1));
|
||||
|
||||
ns->buf_pos += len;
|
||||
if(ns->buf_pos >= NETIO_BUF_SIZE){
|
||||
ns->buf_pos = 0;
|
||||
}
|
||||
|
||||
ns->cntr += len;
|
||||
}
|
||||
}
|
||||
|
||||
if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){
|
||||
/* we have buffered up all our data to send this last round, go look for a command */
|
||||
ns->state = NETIO_STATE_WAIT_FOR_CMD;
|
||||
ns->cntr = 0;
|
||||
/* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
netio_poll(void *arg, struct tcp_pcb *pcb)
|
||||
{
|
||||
struct netio_state * ns = arg;
|
||||
if(ns->state == NETIO_STATE_SEND_DATA){
|
||||
|
||||
} else if(ns->state == NETIO_STATE_DONE){
|
||||
netio_close(ns, pcb);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
|
||||
}
|
||||
|
||||
#if NETIO_USE_STATIC_BUF == 1
|
||||
static u8_t netio_buf[NETIO_BUF_SIZE];
|
||||
#endif
|
||||
|
||||
static err_t
|
||||
netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
|
||||
{
|
||||
struct netio_state * ns;
|
||||
|
||||
LWIP_UNUSED_ARG(err);
|
||||
|
||||
ns = mem_malloc(sizeof(struct netio_state));
|
||||
|
||||
if(ns == NULL){
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
ns->state = NETIO_STATE_WAIT_FOR_CMD;
|
||||
ns->data_len = 0;
|
||||
ns->cmd = 0;
|
||||
ns->cntr = 0;
|
||||
ns->buf_pos = 0;
|
||||
#if NETIO_USE_STATIC_BUF == 1
|
||||
ns->buf_ptr = netio_buf;
|
||||
#else
|
||||
ns->buf_ptr = mem_malloc(NETIO_BUF_SIZE);
|
||||
|
||||
if(ns->buf_ptr == NULL){
|
||||
mem_free(ns);
|
||||
return ERR_MEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
ns->buf_ptr[0] = 0;
|
||||
|
||||
tcp_arg(pcb, ns);
|
||||
tcp_sent(pcb, netio_sent);
|
||||
tcp_recv(pcb, netio_recv);
|
||||
tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void netio_init(void)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
|
||||
pcb = tcp_new();
|
||||
tcp_bind(pcb, IP_ADDR_ANY, 18767);
|
||||
pcb = tcp_listen(pcb);
|
||||
tcp_accept(pcb, netio_accept);
|
||||
}
|
||||
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
FINSH_FUNCTION_EXPORT(netio_init, netio server);
|
||||
#endif
|
@ -1,180 +0,0 @@
|
||||
/*
|
||||
* netutils: ping implementation
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/ip.h"
|
||||
|
||||
/**
|
||||
* PING_DEBUG: Enable debugging for PING.
|
||||
*/
|
||||
#ifndef PING_DEBUG
|
||||
#define PING_DEBUG LWIP_DBG_ON
|
||||
#endif
|
||||
|
||||
/** ping receive timeout - in milliseconds */
|
||||
#define PING_RCV_TIMEO 1000
|
||||
/** ping delay - in milliseconds */
|
||||
#define PING_DELAY 100
|
||||
|
||||
/** ping identifier - must fit on a u16_t */
|
||||
#ifndef PING_ID
|
||||
#define PING_ID 0xAFAF
|
||||
#endif
|
||||
|
||||
/** ping additional data size to include in the packet */
|
||||
#ifndef PING_DATA_SIZE
|
||||
#define PING_DATA_SIZE 32
|
||||
#endif
|
||||
|
||||
/* ping variables */
|
||||
static u16_t ping_seq_num;
|
||||
struct _ip_addr
|
||||
{
|
||||
rt_uint8_t addr0, addr1, addr2, addr3;
|
||||
};
|
||||
|
||||
/** Prepare a echo ICMP request */
|
||||
static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
|
||||
{
|
||||
size_t i;
|
||||
size_t data_len = len - sizeof(struct icmp_echo_hdr);
|
||||
|
||||
ICMPH_TYPE_SET(iecho, ICMP_ECHO);
|
||||
ICMPH_CODE_SET(iecho, 0);
|
||||
iecho->chksum = 0;
|
||||
iecho->id = PING_ID;
|
||||
iecho->seqno = htons(++ping_seq_num);
|
||||
|
||||
/* fill the additional data buffer with some data */
|
||||
for(i = 0; i < data_len; i++)
|
||||
{
|
||||
((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
|
||||
}
|
||||
|
||||
iecho->chksum = inet_chksum(iecho, len);
|
||||
}
|
||||
|
||||
/* Ping using the socket ip */
|
||||
static err_t ping_send(int s, struct ip_addr *addr, int size)
|
||||
{
|
||||
int err;
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct sockaddr_in to;
|
||||
size_t ping_size = sizeof(struct icmp_echo_hdr) + size;
|
||||
LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
|
||||
|
||||
iecho = rt_malloc(ping_size);
|
||||
if (iecho == RT_NULL)
|
||||
{
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
ping_prepare_echo(iecho, (u16_t)ping_size);
|
||||
|
||||
to.sin_len = sizeof(to);
|
||||
to.sin_family = AF_INET;
|
||||
to.sin_addr.s_addr = addr->addr;
|
||||
|
||||
err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
|
||||
rt_free(iecho);
|
||||
|
||||
return (err ? ERR_OK : ERR_VAL);
|
||||
}
|
||||
|
||||
static void ping_recv(int s)
|
||||
{
|
||||
char buf[64];
|
||||
int fromlen, len;
|
||||
struct sockaddr_in from;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct _ip_addr *addr;
|
||||
|
||||
while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0)
|
||||
{
|
||||
if (len >= (sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr)))
|
||||
{
|
||||
addr = (struct _ip_addr *)&(from.sin_addr);
|
||||
rt_kprintf("ping: recv %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
|
||||
|
||||
iphdr = (struct ip_hdr *)buf;
|
||||
iecho = (struct icmp_echo_hdr *)(buf+(IPH_HL(iphdr) * 4));
|
||||
if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("ping: drop\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len <= 0)
|
||||
{
|
||||
rt_kprintf("ping: timeout\n");
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t ping(char* target, rt_uint32_t time, rt_size_t size)
|
||||
{
|
||||
int s;
|
||||
int timeout = PING_RCV_TIMEO;
|
||||
struct ip_addr ping_target;
|
||||
rt_uint32_t send_time;
|
||||
struct _ip_addr
|
||||
{
|
||||
rt_uint8_t addr0, addr1, addr2, addr3;
|
||||
} *addr;
|
||||
|
||||
send_time = 0;
|
||||
|
||||
if(size == 0)
|
||||
size = PING_DATA_SIZE;
|
||||
|
||||
if (inet_aton(target, (struct in_addr*)&ping_target) == 0) return -RT_ERROR;
|
||||
addr = (struct _ip_addr*)&ping_target;
|
||||
|
||||
if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0)
|
||||
{
|
||||
rt_kprintf("create socket failled\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (ping_send(s, &ping_target, size) == ERR_OK)
|
||||
{
|
||||
rt_kprintf("ping: send %d.%d.%d.%d\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
|
||||
ping_recv(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("ping: send %d.%d.%d.%d - error\n", addr->addr0, addr->addr1, addr->addr2, addr->addr3);
|
||||
}
|
||||
|
||||
send_time ++;
|
||||
if (send_time >= time) break; /* send ping times reached, stop */
|
||||
|
||||
rt_thread_delay(PING_DELAY); /* take a delay */
|
||||
}
|
||||
|
||||
lwip_close(s);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
FINSH_FUNCTION_EXPORT(ping, ping network host);
|
||||
#endif
|
@ -1,213 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* SNTP client module
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/** This is an example of a "SNTP" client (with socket API).
|
||||
*
|
||||
* For a list of some public NTP servers, see this link :
|
||||
* http://support.ntp.org/bin/view/Servers/NTPPoolServers
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SNTP_DEBUG: Enable debugging for SNTP.
|
||||
*/
|
||||
#ifndef SNTP_DEBUG
|
||||
#define SNTP_DEBUG LWIP_DBG_ON
|
||||
#endif
|
||||
|
||||
/** SNTP server port */
|
||||
#ifndef SNTP_PORT
|
||||
#define SNTP_PORT 123
|
||||
#endif
|
||||
|
||||
/** SNTP server address as IPv4 address in "u32_t" format */
|
||||
#ifndef SNTP_SERVER_ADDRESS
|
||||
#define SNTP_SERVER_ADDRESS inet_addr("213.161.194.93") /* pool.ntp.org */
|
||||
#endif
|
||||
|
||||
/** SNTP receive timeout - in milliseconds */
|
||||
#ifndef SNTP_RECV_TIMEOUT
|
||||
#define SNTP_RECV_TIMEOUT 3000
|
||||
#endif
|
||||
|
||||
/** SNTP update delay - in milliseconds */
|
||||
#ifndef SNTP_UPDATE_DELAY
|
||||
#define SNTP_UPDATE_DELAY 60000
|
||||
#endif
|
||||
|
||||
/** SNTP macro to change system time and/or the update the RTC clock */
|
||||
#ifndef SNTP_SYSTEM_TIME
|
||||
#define SNTP_SYSTEM_TIME(t)
|
||||
#endif
|
||||
|
||||
/* SNTP protocol defines */
|
||||
#define SNTP_MAX_DATA_LEN 48
|
||||
#define SNTP_RCV_TIME_OFS 32
|
||||
#define SNTP_LI_NO_WARNING 0x00
|
||||
#define SNTP_VERSION (4/* NTP Version 4*/<<3)
|
||||
#define SNTP_MODE_CLIENT 0x03
|
||||
#define SNTP_MODE_SERVER 0x04
|
||||
#define SNTP_MODE_BROADCAST 0x05
|
||||
#define SNTP_MODE_MASK 0x07
|
||||
|
||||
/* number of seconds between 1900 and 1970 */
|
||||
#define DIFF_SEC_1900_1970 (2208988800)
|
||||
|
||||
/**
|
||||
* SNTP processing
|
||||
*/
|
||||
static void sntp_process( time_t t)
|
||||
{
|
||||
/* change system time and/or the update the RTC clock */
|
||||
SNTP_SYSTEM_TIME(t);
|
||||
|
||||
/* display local time from GMT time */
|
||||
LWIP_DEBUGF( SNTP_DEBUG, ("sntp_process: %s", ctime(&t)));
|
||||
}
|
||||
|
||||
/**
|
||||
* SNTP request
|
||||
*/
|
||||
static void sntp_request()
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in local;
|
||||
struct sockaddr_in to;
|
||||
int tolen;
|
||||
int size;
|
||||
int timeout;
|
||||
u8_t sntp_request [SNTP_MAX_DATA_LEN];
|
||||
u8_t sntp_response[SNTP_MAX_DATA_LEN];
|
||||
u32_t sntp_server_address;
|
||||
u32_t timestamp;
|
||||
time_t t;
|
||||
|
||||
/* initialize SNTP server address */
|
||||
sntp_server_address = SNTP_SERVER_ADDRESS;
|
||||
|
||||
/* if we got a valid SNTP server address... */
|
||||
if (sntp_server_address!=0)
|
||||
{
|
||||
/* create new socket */
|
||||
sock = socket( AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock>=0)
|
||||
{
|
||||
/* prepare local address */
|
||||
memset(&local, 0, sizeof(local));
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = htons(INADDR_ANY);
|
||||
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
/* bind to local address */
|
||||
if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0)
|
||||
{
|
||||
/* set recv timeout */
|
||||
timeout = SNTP_RECV_TIMEOUT;
|
||||
setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
|
||||
/* prepare SNTP request */
|
||||
memset( sntp_request, 0, sizeof(sntp_request));
|
||||
sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;
|
||||
|
||||
/* prepare SNTP server address */
|
||||
memset(&to, 0, sizeof(to));
|
||||
to.sin_family = AF_INET;
|
||||
to.sin_port = htons(SNTP_PORT);
|
||||
to.sin_addr.s_addr = sntp_server_address;
|
||||
|
||||
/* send SNTP request to server */
|
||||
if (sendto( sock, sntp_request, sizeof(sntp_request), 0, (struct sockaddr *)&to, sizeof(to))>=0)
|
||||
{
|
||||
/* receive SNTP server response */
|
||||
tolen = sizeof(to);
|
||||
size = recvfrom( sock, sntp_response, sizeof(sntp_response), 0, (struct sockaddr *)&to, (socklen_t *)&tolen);
|
||||
|
||||
/* if the response size is good */
|
||||
if (size == SNTP_MAX_DATA_LEN)
|
||||
{
|
||||
/* if this is a SNTP response... */
|
||||
if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST))
|
||||
{
|
||||
/* extract GMT time from response */
|
||||
SMEMCPY( ×tamp, (sntp_response+SNTP_RCV_TIME_OFS), sizeof(timestamp));
|
||||
t = (ntohl(timestamp) - DIFF_SEC_1900_1970);
|
||||
|
||||
/* do time processing */
|
||||
sntp_process(t);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not response frame code\n"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not recvfrom==%i\n", errno));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not sendto==%i\n", errno));
|
||||
}
|
||||
}
|
||||
/* close the socket */
|
||||
closesocket(sock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SNTP thread
|
||||
*/
|
||||
static void
|
||||
sntp_thread(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
while(1)
|
||||
{
|
||||
sntp_request();
|
||||
sys_msleep(SNTP_UPDATE_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void sntp_init(void)
|
||||
{
|
||||
sys_thread_new("sntp_thread", sntp_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
#include <lwip/api.h>
|
||||
|
||||
#define TCP_ECHO_PORT 7
|
||||
|
||||
void tcpecho_entry(void *parameter)
|
||||
{
|
||||
struct netconn *conn, *newconn;
|
||||
err_t err;
|
||||
|
||||
/* Create a new connection identifier. */
|
||||
conn = netconn_new(NETCONN_TCP);
|
||||
|
||||
/* Bind connection to well known port number 7. */
|
||||
netconn_bind(conn, NULL, TCP_ECHO_PORT);
|
||||
|
||||
/* Tell connection to go into listening mode. */
|
||||
netconn_listen(conn);
|
||||
|
||||
while(1)
|
||||
{
|
||||
/* Grab new connection. */
|
||||
err = netconn_accept(conn, &newconn);
|
||||
/* Process the new connection. */
|
||||
if(err == ERR_OK)
|
||||
{
|
||||
struct netbuf *buf;
|
||||
void *data;
|
||||
u16_t len;
|
||||
|
||||
while(netconn_recv(newconn, &buf) == ERR_OK)
|
||||
{
|
||||
do
|
||||
{
|
||||
netbuf_data(buf, &data, &len);
|
||||
err = netconn_write(newconn, data, len, NETCONN_COPY);
|
||||
if(err != ERR_OK){}
|
||||
}
|
||||
while(netbuf_next(buf) >= 0);
|
||||
netbuf_delete(buf);
|
||||
}
|
||||
/* Close connection and discard connection identifier. */
|
||||
netconn_delete(newconn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
static rt_thread_t echo_tid = RT_NULL;
|
||||
void tcpecho(rt_uint32_t startup)
|
||||
{
|
||||
if (startup && echo_tid == RT_NULL)
|
||||
{
|
||||
echo_tid = rt_thread_create("echo",
|
||||
tcpecho_entry, RT_NULL,
|
||||
512, 30, 5);
|
||||
if (echo_tid != RT_NULL)
|
||||
rt_thread_startup(echo_tid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (echo_tid != RT_NULL)
|
||||
rt_thread_delete(echo_tid); /* delete thread */
|
||||
echo_tid = RT_NULL;
|
||||
}
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(tcpecho, startup or stop TCP echo server);
|
||||
#endif
|
@ -1,206 +0,0 @@
|
||||
#include <rtthread.h>
|
||||
#include <dfs_posix.h>
|
||||
#include <lwip/sockets.h>
|
||||
|
||||
#include <finsh.h>
|
||||
|
||||
#define TFTP_PORT 69
|
||||
/* opcode */
|
||||
#define TFTP_RRQ 1 /* read request */
|
||||
#define TFTP_WRQ 2 /* write request */
|
||||
#define TFTP_DATA 3 /* data */
|
||||
#define TFTP_ACK 4 /* ACK */
|
||||
#define TFTP_ERROR 5 /* error */
|
||||
|
||||
rt_uint8_t tftp_buffer[512 + 4];
|
||||
/* tftp client */
|
||||
void tftp_get(const char* host, const char* dir, const char* filename)
|
||||
{
|
||||
int fd, sock_fd, sock_opt;
|
||||
struct sockaddr_in tftp_addr, from_addr;
|
||||
rt_uint32_t length;
|
||||
socklen_t fromlen;
|
||||
|
||||
/* make local file name */
|
||||
rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
|
||||
"%s/%s", dir, filename);
|
||||
|
||||
/* open local file for write */
|
||||
fd = open((char*)tftp_buffer, O_RDWR | O_CREAT, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
rt_kprintf("can't open local filename\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* connect to tftp server */
|
||||
inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
|
||||
tftp_addr.sin_family = AF_INET;
|
||||
tftp_addr.sin_port = htons(TFTP_PORT);
|
||||
|
||||
sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
close(fd);
|
||||
rt_kprintf("can't create a socket\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
/* set socket option */
|
||||
sock_opt = 5000; /* 5 seconds */
|
||||
lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
|
||||
|
||||
/* make tftp request */
|
||||
tftp_buffer[0] = 0; /* opcode */
|
||||
tftp_buffer[1] = TFTP_RRQ; /* RRQ */
|
||||
length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
|
||||
tftp_buffer[length] = 0; length ++;
|
||||
length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
|
||||
tftp_buffer[length] = 0; length ++;
|
||||
|
||||
fromlen = sizeof(struct sockaddr_in);
|
||||
|
||||
/* send request */
|
||||
lwip_sendto(sock_fd, tftp_buffer, length, 0,
|
||||
(struct sockaddr *)&tftp_addr, fromlen);
|
||||
|
||||
do
|
||||
{
|
||||
length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0,
|
||||
(struct sockaddr *)&from_addr, &fromlen);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
write(fd, (char*)&tftp_buffer[4], length - 4);
|
||||
rt_kprintf("#");
|
||||
|
||||
/* make ACK */
|
||||
tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_ACK; /* opcode */
|
||||
/* send ACK */
|
||||
lwip_sendto(sock_fd, tftp_buffer, 4, 0,
|
||||
(struct sockaddr *)&from_addr, fromlen);
|
||||
}
|
||||
} while (length == 516);
|
||||
|
||||
if (length == 0) rt_kprintf("timeout\n");
|
||||
else rt_kprintf("done\n");
|
||||
|
||||
close(fd);
|
||||
lwip_close(sock_fd);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(tftp_get, get file from tftp server);
|
||||
|
||||
void tftp_put(const char* host, const char* dir, const char* filename)
|
||||
{
|
||||
int fd, sock_fd, sock_opt;
|
||||
struct sockaddr_in tftp_addr, from_addr;
|
||||
rt_uint32_t length, block_number = 0;
|
||||
socklen_t fromlen;
|
||||
|
||||
/* make local file name */
|
||||
rt_snprintf((char*)tftp_buffer, sizeof(tftp_buffer),
|
||||
"%s/%s", dir, filename);
|
||||
|
||||
/* open local file for write */
|
||||
fd = open((char*)tftp_buffer, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
rt_kprintf("can't open local filename\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* connect to tftp server */
|
||||
inet_aton(host, (struct in_addr*)&(tftp_addr.sin_addr));
|
||||
tftp_addr.sin_family = AF_INET;
|
||||
tftp_addr.sin_port = htons(TFTP_PORT);
|
||||
|
||||
sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
close(fd);
|
||||
rt_kprintf("can't create a socket\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
/* set socket option */
|
||||
sock_opt = 5000; /* 5 seconds */
|
||||
lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_opt, sizeof(sock_opt));
|
||||
|
||||
/* make tftp request */
|
||||
tftp_buffer[0] = 0; /* opcode */
|
||||
tftp_buffer[1] = TFTP_WRQ; /* WRQ */
|
||||
length = rt_sprintf((char *)&tftp_buffer[2], "%s", filename) + 2;
|
||||
tftp_buffer[length] = 0; length ++;
|
||||
length += rt_sprintf((char*)&tftp_buffer[length], "%s", "octet");
|
||||
tftp_buffer[length] = 0; length ++;
|
||||
|
||||
fromlen = sizeof(struct sockaddr_in);
|
||||
|
||||
/* send request */
|
||||
lwip_sendto(sock_fd, tftp_buffer, length, 0,
|
||||
(struct sockaddr *)&tftp_addr, fromlen);
|
||||
|
||||
/* wait ACK 0 */
|
||||
length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0,
|
||||
(struct sockaddr *)&from_addr, &fromlen);
|
||||
if (!(tftp_buffer[0] == 0 &&
|
||||
tftp_buffer[1] == TFTP_ACK &&
|
||||
tftp_buffer[2] == 0 &&
|
||||
tftp_buffer[3] == 0))
|
||||
{
|
||||
rt_kprintf("tftp server error\n");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
block_number = 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
length = read(fd, (char*)&tftp_buffer[4], 512);
|
||||
if (length > 0)
|
||||
{
|
||||
/* make opcode and block number */
|
||||
tftp_buffer[0] = 0; tftp_buffer[1] = TFTP_DATA;
|
||||
tftp_buffer[2] = (block_number >> 8) & 0xff;
|
||||
tftp_buffer[3] = block_number & 0xff;
|
||||
|
||||
lwip_sendto(sock_fd, tftp_buffer, length + 4, 0,
|
||||
(struct sockaddr *)&from_addr, fromlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("done\n");
|
||||
break; /* no data yet */
|
||||
}
|
||||
|
||||
/* receive ack */
|
||||
length = lwip_recvfrom(sock_fd, tftp_buffer, sizeof(tftp_buffer), 0,
|
||||
(struct sockaddr *)&from_addr, &fromlen);
|
||||
if (length > 0)
|
||||
{
|
||||
if ((tftp_buffer[0] == 0 &&
|
||||
tftp_buffer[1] == TFTP_ACK &&
|
||||
tftp_buffer[2] == (block_number >> 8) & 0xff) &&
|
||||
tftp_buffer[3] == (block_number & 0xff))
|
||||
{
|
||||
block_number ++;
|
||||
rt_kprintf("#");
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("server respondes with an error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (length == 0)
|
||||
{
|
||||
rt_kprintf("server timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
lwip_close(sock_fd);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(tftp_put, put file to tftp server);
|
@ -1,56 +0,0 @@
|
||||
#include <lwip/api.h>
|
||||
|
||||
#define UDP_ECHO_PORT 7
|
||||
|
||||
void udpecho_entry(void *parameter)
|
||||
{
|
||||
struct netconn *conn;
|
||||
struct netbuf *buf;
|
||||
struct ip_addr *addr;
|
||||
unsigned short port;
|
||||
|
||||
conn = netconn_new(NETCONN_UDP);
|
||||
netconn_bind(conn, IP_ADDR_ANY, 7);
|
||||
|
||||
while(1)
|
||||
{
|
||||
/* received data to buffer */
|
||||
netconn_recv(conn, &buf);
|
||||
|
||||
addr = netbuf_fromaddr(buf);
|
||||
port = netbuf_fromport(buf);
|
||||
|
||||
/* send the data to buffer */
|
||||
netconn_connect(conn, addr, port);
|
||||
|
||||
/* reset address, and send to client */
|
||||
buf->addr = *IP_ADDR_ANY;
|
||||
netconn_send(conn, buf);
|
||||
|
||||
/* release buffer */
|
||||
netbuf_delete(buf);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
static rt_thread_t echo_tid = RT_NULL;
|
||||
void udpecho(rt_uint32_t startup)
|
||||
{
|
||||
if (startup && echo_tid == RT_NULL)
|
||||
{
|
||||
echo_tid = rt_thread_create("uecho",
|
||||
udpecho_entry, RT_NULL,
|
||||
512, 30, 5);
|
||||
if (echo_tid != RT_NULL)
|
||||
rt_thread_startup(echo_tid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (echo_tid != RT_NULL)
|
||||
rt_thread_delete(echo_tid); /* delete thread */
|
||||
echo_tid = RT_NULL;
|
||||
}
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT(udpecho, startup or stop UDP echo server);
|
||||
#endif
|
@ -1,6 +0,0 @@
|
||||
savannah.txt - How to obtain the current development source code.
|
||||
contrib.txt - How to contribute to lwIP as a developer.
|
||||
rawapi.txt - The documentation for the core API of lwIP.
|
||||
Also provides an overview about the other APIs and multithreading.
|
||||
snmp_agent.txt - The documentation for the lwIP SNMP agent.
|
||||
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
|
@ -1,63 +0,0 @@
|
||||
1 Introduction
|
||||
|
||||
This document describes some guidelines for people participating
|
||||
in lwIP development.
|
||||
|
||||
2 How to contribute to lwIP
|
||||
|
||||
Here is a short list of suggestions to anybody working with lwIP and
|
||||
trying to contribute bug reports, fixes, enhancements, platform ports etc.
|
||||
First of all as you may already know lwIP is a volunteer project so feedback
|
||||
to fixes or questions might often come late. Hopefully the bug and patch tracking
|
||||
features of Savannah help us not lose users' input.
|
||||
|
||||
2.1 Source code style:
|
||||
|
||||
1. do not use tabs.
|
||||
2. indentation is two spaces per level (i.e. per tab).
|
||||
3. end debug messages with a trailing newline (\n).
|
||||
4. one space between keyword and opening bracket.
|
||||
5. no space between function and opening bracket.
|
||||
6. one space and no newline before opening curly braces of a block.
|
||||
7. closing curly brace on a single line.
|
||||
8. spaces surrounding assignment and comparisons.
|
||||
9. don't initialize static and/or global variables to zero, the compiler takes care of that.
|
||||
10. use current source code style as further reference.
|
||||
|
||||
2.2 Source code documentation style:
|
||||
|
||||
1. JavaDoc compliant and Doxygen compatible.
|
||||
2. Function documentation above functions in .c files, not .h files.
|
||||
(This forces you to synchronize documentation and implementation.)
|
||||
3. Use current documentation style as further reference.
|
||||
|
||||
2.3 Bug reports and patches:
|
||||
|
||||
1. Make sure you are reporting bugs or send patches against the latest
|
||||
sources. (From the latest release and/or the current CVS sources.)
|
||||
2. If you think you found a bug make sure it's not already filed in the
|
||||
bugtracker at Savannah.
|
||||
3. If you have a fix put the patch on Savannah. If it is a patch that affects
|
||||
both core and arch specific stuff please separate them so that the core can
|
||||
be applied separately while leaving the other patch 'open'. The prefered way
|
||||
is to NOT touch archs you can't test and let maintainers take care of them.
|
||||
This is a good way to see if they are used at all - the same goes for unix
|
||||
netifs except tapif.
|
||||
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
|
||||
or a patch will be enough.
|
||||
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
|
||||
5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
|
||||
can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
|
||||
as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
|
||||
for reporting a compiler warning fix.
|
||||
6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other
|
||||
trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you
|
||||
change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than
|
||||
if it's not to the point and long :) so the chances for it to be applied are greater.
|
||||
|
||||
2.4 Platform porters:
|
||||
|
||||
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
|
||||
you think it could benefit others[1] you might want discuss this on the mailing list. You
|
||||
can also ask for CVS access to submit and maintain your port in the contrib CVS module.
|
||||
|
@ -1,505 +0,0 @@
|
||||
Raw TCP/IP interface for lwIP
|
||||
|
||||
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
|
||||
|
||||
lwIP provides three Application Program's Interfaces (APIs) for programs
|
||||
to use for communication with the TCP/IP code:
|
||||
* low-level "core" / "callback" or "raw" API.
|
||||
* higher-level "sequential" API.
|
||||
* BSD-style socket API.
|
||||
|
||||
The sequential API provides a way for ordinary, sequential, programs
|
||||
to use the lwIP stack. It is quite similar to the BSD socket API. The
|
||||
model of execution is based on the blocking open-read-write-close
|
||||
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
|
||||
code and the application program must reside in different execution
|
||||
contexts (threads).
|
||||
|
||||
The socket API is a compatibility API for existing applications,
|
||||
currently it is built on top of the sequential API. It is meant to
|
||||
provide all functions needed to run socket API applications running
|
||||
on other platforms (e.g. unix / windows etc.). However, due to limitations
|
||||
in the specification of this API, there might be incompatibilities
|
||||
that require small modifications of existing programs.
|
||||
|
||||
** Threading
|
||||
|
||||
lwIP started targeting single-threaded environments. When adding multi-
|
||||
threading support, instead of making the core thread-safe, another
|
||||
approach was chosen: there is one main thread running the lwIP core
|
||||
(also known as the "tcpip_thread"). The raw API may only be used from
|
||||
this thread! Application threads using the sequential- or socket API
|
||||
communicate with this main thread through message passing.
|
||||
|
||||
As such, the list of functions that may be called from
|
||||
other threads or an ISR is very limited! Only functions
|
||||
from these API header files are thread-safe:
|
||||
- api.h
|
||||
- netbuf.h
|
||||
- netdb.h
|
||||
- netifapi.h
|
||||
- sockets.h
|
||||
- sys.h
|
||||
|
||||
Additionaly, memory (de-)allocation functions may be
|
||||
called from multiple threads (not ISR!) with NO_SYS=0
|
||||
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
|
||||
semaphores.
|
||||
|
||||
Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
|
||||
and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
|
||||
pbuf_free() may also be called from another thread or
|
||||
an ISR (since only then, mem_free - for PBUF_RAM - may
|
||||
be called from an ISR: otherwise, the HEAP is only
|
||||
protected by semaphores).
|
||||
|
||||
|
||||
** The remainder of this document discusses the "raw" API. **
|
||||
|
||||
The raw TCP/IP interface allows the application program to integrate
|
||||
better with the TCP/IP code. Program execution is event based by
|
||||
having callback functions being called from within the TCP/IP
|
||||
code. The TCP/IP code and the application program both run in the same
|
||||
thread. The sequential API has a much higher overhead and is not very
|
||||
well suited for small systems since it forces a multithreaded paradigm
|
||||
on the application.
|
||||
|
||||
The raw TCP/IP interface is not only faster in terms of code execution
|
||||
time but is also less memory intensive. The drawback is that program
|
||||
development is somewhat harder and application programs written for
|
||||
the raw TCP/IP interface are more difficult to understand. Still, this
|
||||
is the preferred way of writing applications that should be small in
|
||||
code size and memory usage.
|
||||
|
||||
Both APIs can be used simultaneously by different application
|
||||
programs. In fact, the sequential API is implemented as an application
|
||||
program using the raw TCP/IP interface.
|
||||
|
||||
--- Callbacks
|
||||
|
||||
Program execution is driven by callbacks. Each callback is an ordinary
|
||||
C function that is called from within the TCP/IP code. Every callback
|
||||
function is passed the current TCP or UDP connection state as an
|
||||
argument. Also, in order to be able to keep program specific state,
|
||||
the callback functions are called with a program specified argument
|
||||
that is independent of the TCP/IP state.
|
||||
|
||||
The function for setting the application connection state is:
|
||||
|
||||
- void tcp_arg(struct tcp_pcb *pcb, void *arg)
|
||||
|
||||
Specifies the program specific state that should be passed to all
|
||||
other callback functions. The "pcb" argument is the current TCP
|
||||
connection control block, and the "arg" argument is the argument
|
||||
that will be passed to the callbacks.
|
||||
|
||||
|
||||
--- TCP connection setup
|
||||
|
||||
The functions used for setting up connections is similar to that of
|
||||
the sequential API and of the BSD socket API. A new TCP connection
|
||||
identifier (i.e., a protocol control block - PCB) is created with the
|
||||
tcp_new() function. This PCB can then be either set to listen for new
|
||||
incoming connections or be explicitly connected to another host.
|
||||
|
||||
- struct tcp_pcb *tcp_new(void)
|
||||
|
||||
Creates a new connection identifier (PCB). If memory is not
|
||||
available for creating the new pcb, NULL is returned.
|
||||
|
||||
- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Binds the pcb to a local IP address and port number. The IP address
|
||||
can be specified as IP_ADDR_ANY in order to bind the connection to
|
||||
all local IP addresses.
|
||||
|
||||
If another connection is bound to the same port, the function will
|
||||
return ERR_USE, otherwise ERR_OK is returned.
|
||||
|
||||
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
|
||||
|
||||
Commands a pcb to start listening for incoming connections. When an
|
||||
incoming connection is accepted, the function specified with the
|
||||
tcp_accept() function will be called. The pcb will have to be bound
|
||||
to a local port with the tcp_bind() function.
|
||||
|
||||
The tcp_listen() function returns a new connection identifier, and
|
||||
the one passed as an argument to the function will be
|
||||
deallocated. The reason for this behavior is that less memory is
|
||||
needed for a connection that is listening, so tcp_listen() will
|
||||
reclaim the memory needed for the original connection and allocate a
|
||||
new smaller memory block for the listening connection.
|
||||
|
||||
tcp_listen() may return NULL if no memory was available for the
|
||||
listening connection. If so, the memory associated with the pcb
|
||||
passed as an argument to tcp_listen() will not be deallocated.
|
||||
|
||||
- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||
|
||||
Same as tcp_listen, but limits the number of outstanding connections
|
||||
in the listen queue to the value specified by the backlog argument.
|
||||
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
|
||||
|
||||
- void tcp_accepted(struct tcp_pcb *pcb)
|
||||
|
||||
Inform lwIP that an incoming connection has been accepted. This would
|
||||
usually be called from the accept callback. This allows lwIP to perform
|
||||
housekeeping tasks, such as allowing further incoming connections to be
|
||||
queued in the listen backlog.
|
||||
|
||||
- void tcp_accept(struct tcp_pcb *pcb,
|
||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
|
||||
err_t err))
|
||||
|
||||
Specified the callback function that should be called when a new
|
||||
connection arrives on a listening connection.
|
||||
|
||||
- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
u16_t port, err_t (* connected)(void *arg,
|
||||
struct tcp_pcb *tpcb,
|
||||
err_t err));
|
||||
|
||||
Sets up the pcb to connect to the remote host and sends the
|
||||
initial SYN segment which opens the connection.
|
||||
|
||||
The tcp_connect() function returns immediately; it does not wait for
|
||||
the connection to be properly setup. Instead, it will call the
|
||||
function specified as the fourth argument (the "connected" argument)
|
||||
when the connection is established. If the connection could not be
|
||||
properly established, either because the other host refused the
|
||||
connection or because the other host didn't answer, the "err"
|
||||
callback function of this pcb (registered with tcp_err, see below)
|
||||
will be called.
|
||||
|
||||
The tcp_connect() function can return ERR_MEM if no memory is
|
||||
available for enqueueing the SYN segment. If the SYN indeed was
|
||||
enqueued successfully, the tcp_connect() function returns ERR_OK.
|
||||
|
||||
|
||||
--- Sending TCP data
|
||||
|
||||
TCP data is sent by enqueueing the data with a call to
|
||||
tcp_write(). When the data is successfully transmitted to the remote
|
||||
host, the application will be notified with a call to a specified
|
||||
callback function.
|
||||
|
||||
- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,
|
||||
u8_t copy)
|
||||
|
||||
Enqueues the data pointed to by the argument dataptr. The length of
|
||||
the data is passed as the len parameter. The copy argument is either
|
||||
0 or 1 and indicates whether the new memory should be allocated for
|
||||
the data to be copied into. If the argument is 0, no new memory
|
||||
should be allocated and the data should only be referenced by
|
||||
pointer.
|
||||
|
||||
The tcp_write() function will fail and return ERR_MEM if the length
|
||||
of the data exceeds the current send buffer size or if the length of
|
||||
the queue of outgoing segment is larger than the upper limit defined
|
||||
in lwipopts.h. The number of bytes available in the output queue can
|
||||
be retrieved with the tcp_sndbuf() function.
|
||||
|
||||
The proper way to use this function is to call the function with at
|
||||
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
|
||||
the application should wait until some of the currently enqueued
|
||||
data has been successfully received by the other host and try again.
|
||||
|
||||
- void tcp_sent(struct tcp_pcb *pcb,
|
||||
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
|
||||
u16_t len))
|
||||
|
||||
Specifies the callback function that should be called when data has
|
||||
successfully been received (i.e., acknowledged) by the remote
|
||||
host. The len argument passed to the callback function gives the
|
||||
amount bytes that was acknowledged by the last acknowledgment.
|
||||
|
||||
|
||||
--- Receiving TCP data
|
||||
|
||||
TCP data reception is callback based - an application specified
|
||||
callback function is called when new data arrives. When the
|
||||
application has taken the data, it has to call the tcp_recved()
|
||||
function to indicate that TCP can advertise increase the receive
|
||||
window.
|
||||
|
||||
- void tcp_recv(struct tcp_pcb *pcb,
|
||||
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
|
||||
struct pbuf *p, err_t err))
|
||||
|
||||
Sets the callback function that will be called when new data
|
||||
arrives. The callback function will be passed a NULL pbuf to
|
||||
indicate that the remote host has closed the connection. If
|
||||
there are no errors and the callback function is to return
|
||||
ERR_OK, then it must free the pbuf. Otherwise, it must not
|
||||
free the pbuf so that lwIP core code can store it.
|
||||
|
||||
- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
||||
|
||||
Must be called when the application has received the data. The len
|
||||
argument indicates the length of the received data.
|
||||
|
||||
|
||||
--- Application polling
|
||||
|
||||
When a connection is idle (i.e., no data is either transmitted or
|
||||
received), lwIP will repeatedly poll the application by calling a
|
||||
specified callback function. This can be used either as a watchdog
|
||||
timer for killing connections that have stayed idle for too long, or
|
||||
as a method of waiting for memory to become available. For instance,
|
||||
if a call to tcp_write() has failed because memory wasn't available,
|
||||
the application may use the polling functionality to call tcp_write()
|
||||
again when the connection has been idle for a while.
|
||||
|
||||
- void tcp_poll(struct tcp_pcb *pcb,
|
||||
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
|
||||
u8_t interval)
|
||||
|
||||
Specifies the polling interval and the callback function that should
|
||||
be called to poll the application. The interval is specified in
|
||||
number of TCP coarse grained timer shots, which typically occurs
|
||||
twice a second. An interval of 10 means that the application would
|
||||
be polled every 5 seconds.
|
||||
|
||||
|
||||
--- Closing and aborting connections
|
||||
|
||||
- err_t tcp_close(struct tcp_pcb *pcb)
|
||||
|
||||
Closes the connection. The function may return ERR_MEM if no memory
|
||||
was available for closing the connection. If so, the application
|
||||
should wait and try again either by using the acknowledgment
|
||||
callback or the polling functionality. If the close succeeds, the
|
||||
function returns ERR_OK.
|
||||
|
||||
The pcb is deallocated by the TCP code after a call to tcp_close().
|
||||
|
||||
- void tcp_abort(struct tcp_pcb *pcb)
|
||||
|
||||
Aborts the connection by sending a RST (reset) segment to the remote
|
||||
host. The pcb is deallocated. This function never fails.
|
||||
|
||||
ATTENTION: When calling this from one of the TCP callbacks, make
|
||||
sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
|
||||
or you will risk accessing deallocated memory or memory leaks!
|
||||
|
||||
|
||||
If a connection is aborted because of an error, the application is
|
||||
alerted of this event by the err callback. Errors that might abort a
|
||||
connection are when there is a shortage of memory. The callback
|
||||
function to be called is set using the tcp_err() function.
|
||||
|
||||
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
|
||||
err_t err))
|
||||
|
||||
The error callback function does not get the pcb passed to it as a
|
||||
parameter since the pcb may already have been deallocated.
|
||||
|
||||
|
||||
--- Lower layer TCP interface
|
||||
|
||||
TCP provides a simple interface to the lower layers of the
|
||||
system. During system initialization, the function tcp_init() has
|
||||
to be called before any other TCP function is called. When the system
|
||||
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
|
||||
must be called with regular intervals. The tcp_fasttmr() should be
|
||||
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
|
||||
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
|
||||
|
||||
|
||||
--- UDP interface
|
||||
|
||||
The UDP interface is similar to that of TCP, but due to the lower
|
||||
level of complexity of UDP, the interface is significantly simpler.
|
||||
|
||||
- struct udp_pcb *udp_new(void)
|
||||
|
||||
Creates a new UDP pcb which can be used for UDP communication. The
|
||||
pcb is not active until it has either been bound to a local address
|
||||
or connected to a remote address.
|
||||
|
||||
- void udp_remove(struct udp_pcb *pcb)
|
||||
|
||||
Removes and deallocates the pcb.
|
||||
|
||||
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Binds the pcb to a local address. The IP-address argument "ipaddr"
|
||||
can be IP_ADDR_ANY to indicate that it should listen to any local IP
|
||||
address. The function currently always return ERR_OK.
|
||||
|
||||
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
|
||||
u16_t port)
|
||||
|
||||
Sets the remote end of the pcb. This function does not generate any
|
||||
network traffic, but only set the remote address of the pcb.
|
||||
|
||||
- err_t udp_disconnect(struct udp_pcb *pcb)
|
||||
|
||||
Remove the remote end of the pcb. This function does not generate
|
||||
any network traffic, but only removes the remote address of the pcb.
|
||||
|
||||
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
|
||||
Sends the pbuf p. The pbuf is not deallocated.
|
||||
|
||||
- void udp_recv(struct udp_pcb *pcb,
|
||||
void (* recv)(void *arg, struct udp_pcb *upcb,
|
||||
struct pbuf *p,
|
||||
struct ip_addr *addr,
|
||||
u16_t port),
|
||||
void *recv_arg)
|
||||
|
||||
Specifies a callback function that should be called when a UDP
|
||||
datagram is received.
|
||||
|
||||
|
||||
--- System initalization
|
||||
|
||||
A truly complete and generic sequence for initializing the lwip stack
|
||||
cannot be given because it depends on the build configuration (lwipopts.h)
|
||||
and additional initializations for your runtime environment (e.g. timers).
|
||||
|
||||
We can give you some idea on how to proceed when using the raw API.
|
||||
We assume a configuration using a single Ethernet netif and the
|
||||
UDP and TCP transport layers, IPv4 and the DHCP client.
|
||||
|
||||
Call these functions in the order of appearance:
|
||||
|
||||
- stats_init()
|
||||
|
||||
Clears the structure where runtime statistics are gathered.
|
||||
|
||||
- sys_init()
|
||||
|
||||
Not of much use since we set the NO_SYS 1 option in lwipopts.h,
|
||||
to be called for easy configuration changes.
|
||||
|
||||
- mem_init()
|
||||
|
||||
Initializes the dynamic memory heap defined by MEM_SIZE.
|
||||
|
||||
- memp_init()
|
||||
|
||||
Initializes the memory pools defined by MEMP_NUM_x.
|
||||
|
||||
- pbuf_init()
|
||||
|
||||
Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.
|
||||
|
||||
- etharp_init()
|
||||
|
||||
Initializes the ARP table and queue.
|
||||
Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval
|
||||
after this initialization.
|
||||
|
||||
- ip_init()
|
||||
|
||||
Doesn't do much, it should be called to handle future changes.
|
||||
|
||||
- udp_init()
|
||||
|
||||
Clears the UDP PCB list.
|
||||
|
||||
- tcp_init()
|
||||
|
||||
Clears the TCP PCB list and clears some internal TCP timers.
|
||||
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
|
||||
predefined regular intervals after this initialization.
|
||||
|
||||
- netif_add(struct netif *netif, struct ip_addr *ipaddr,
|
||||
struct ip_addr *netmask, struct ip_addr *gw,
|
||||
void *state, err_t (* init)(struct netif *netif),
|
||||
err_t (* input)(struct pbuf *p, struct netif *netif))
|
||||
|
||||
Adds your network interface to the netif_list. Allocate a struct
|
||||
netif and pass a pointer to this structure as the first argument.
|
||||
Give pointers to cleared ip_addr structures when using DHCP,
|
||||
or fill them with sane numbers otherwise. The state pointer may be NULL.
|
||||
|
||||
The init function pointer must point to a initialization function for
|
||||
your ethernet netif interface. The following code illustrates it's use.
|
||||
|
||||
err_t netif_if_init(struct netif *netif)
|
||||
{
|
||||
u8_t i;
|
||||
|
||||
for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];
|
||||
init_my_eth_device();
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
For ethernet drivers, the input function pointer must point to the lwip
|
||||
function ethernet_input() declared in "netif/etharp.h". Other drivers
|
||||
must use ip_input() declared in "lwip/ip.h".
|
||||
|
||||
- netif_set_default(struct netif *netif)
|
||||
|
||||
Registers the default network interface.
|
||||
|
||||
- netif_set_up(struct netif *netif)
|
||||
|
||||
When the netif is fully configured this function must be called.
|
||||
|
||||
- dhcp_start(struct netif *netif)
|
||||
|
||||
Creates a new DHCP client for this interface on the first call.
|
||||
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
|
||||
the predefined regular intervals after starting the client.
|
||||
|
||||
You can peek in the netif->dhcp struct for the actual DHCP status.
|
||||
|
||||
|
||||
--- Optimalization hints
|
||||
|
||||
The first thing you want to optimize is the lwip_standard_checksum()
|
||||
routine from src/core/inet.c. You can override this standard
|
||||
function with the #define LWIP_CHKSUM <your_checksum_routine>.
|
||||
|
||||
There are C examples given in inet.c or you might want to
|
||||
craft an assembly function for this. RFC1071 is a good
|
||||
introduction to this subject.
|
||||
|
||||
Other significant improvements can be made by supplying
|
||||
assembly or inline replacements for htons() and htonl()
|
||||
if you're using a little-endian architecture.
|
||||
#define LWIP_PLATFORM_BYTESWAP 1
|
||||
#define LWIP_PLATFORM_HTONS(x) <your_htons>
|
||||
#define LWIP_PLATFORM_HTONL(x) <your_htonl>
|
||||
|
||||
Check your network interface driver if it reads at
|
||||
a higher speed than the maximum wire-speed. If the
|
||||
hardware isn't serviced frequently and fast enough
|
||||
buffer overflows are likely to occur.
|
||||
|
||||
E.g. when using the cs8900 driver, call cs8900if_service(ethif)
|
||||
as frequently as possible. When using an RTOS let the cs8900 interrupt
|
||||
wake a high priority task that services your driver using a binary
|
||||
semaphore or event flag. Some drivers might allow additional tuning
|
||||
to match your application and network.
|
||||
|
||||
For a production release it is recommended to set LWIP_STATS to 0.
|
||||
Note that speed performance isn't influenced much by simply setting
|
||||
high values to the memory options.
|
||||
|
||||
For more optimization hints take a look at the lwIP wiki.
|
||||
|
||||
--- Zero-copy MACs
|
||||
|
||||
To achieve zero-copy on transmit, the data passed to the raw API must
|
||||
remain unchanged until sent. Because the send- (or write-)functions return
|
||||
when the packets have been enqueued for sending, data must be kept stable
|
||||
after that, too.
|
||||
|
||||
This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions
|
||||
must *not* be reused by the application unless their ref-count is 1.
|
||||
|
||||
For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too,
|
||||
but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while
|
||||
PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).
|
||||
|
||||
Also, data passed to tcp_write without the copy-flag must not be changed!
|
||||
|
||||
Therefore, be careful which type of PBUF you use and if you copy TCP data
|
||||
or not!
|
@ -1,135 +0,0 @@
|
||||
Daily Use Guide for using Savannah for lwIP
|
||||
|
||||
Table of Contents:
|
||||
|
||||
1 - Obtaining lwIP from the CVS repository
|
||||
2 - Committers/developers CVS access using SSH (to be written)
|
||||
3 - Merging from DEVEL branch to main trunk (stable branch)
|
||||
4 - How to release lwIP
|
||||
|
||||
|
||||
|
||||
1 Obtaining lwIP from the CVS repository
|
||||
----------------------------------------
|
||||
|
||||
To perform an anonymous CVS checkout of the main trunk (this is where
|
||||
bug fixes and incremental enhancements occur), do this:
|
||||
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip
|
||||
|
||||
Or, obtain a stable branch (updated with bug fixes only) as follows:
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
||||
-r STABLE-0_7 -d lwip-0.7 lwip
|
||||
|
||||
Or, obtain a specific (fixed) release as follows:
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
||||
-r STABLE-0_7_0 -d lwip-0.7.0 lwip
|
||||
|
||||
3 Committers/developers CVS access using SSH
|
||||
--------------------------------------------
|
||||
|
||||
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
|
||||
As such, CVS commits to the server occur through a SSH tunnel for project members.
|
||||
To create a SSH2 key pair in UNIX-like environments, do this:
|
||||
|
||||
ssh-keygen -t dsa
|
||||
|
||||
Under Windows, a recommended SSH client is "PuTTY", freely available with good
|
||||
documentation and a graphic user interface. Use its key generator.
|
||||
|
||||
Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
|
||||
a while so that Savannah can update its configuration (This can take minutes).
|
||||
|
||||
Try to login using SSH:
|
||||
|
||||
ssh -v your_login@cvs.sv.gnu.org
|
||||
|
||||
If it tells you:
|
||||
|
||||
Authenticating with public key "your_key_name"...
|
||||
Server refused to allocate pty
|
||||
|
||||
then you could login; Savannah refuses to give you a shell - which is OK, as we
|
||||
are allowed to use SSH for CVS only. Now, you should be able to do this:
|
||||
|
||||
export CVS_RSH=ssh
|
||||
cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip
|
||||
|
||||
after which you can edit your local files with bug fixes or new features and
|
||||
commit them. Make sure you know what you are doing when using CVS to make
|
||||
changes on the repository. If in doubt, ask on the lwip-members mailing list.
|
||||
|
||||
(If SSH asks about authenticity of the host, you can check the key
|
||||
fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
|
||||
|
||||
|
||||
3 Merging from DEVEL branch to main trunk (stable)
|
||||
--------------------------------------------------
|
||||
|
||||
Merging is a delicate process in CVS and requires the
|
||||
following disciplined steps in order to prevent conflicts
|
||||
in the future. Conflicts can be hard to solve!
|
||||
|
||||
Merging from branch A to branch B requires that the A branch
|
||||
has a tag indicating the previous merger. This tag is called
|
||||
'merged_from_A_to_B'. After merging, the tag is moved in the
|
||||
A branch to remember this merger for future merge actions.
|
||||
|
||||
IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
|
||||
REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
|
||||
MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
|
||||
|
||||
Merge all changes in DEVEL since our last merge to main:
|
||||
|
||||
In the working copy of the main trunk:
|
||||
cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
|
||||
|
||||
(This will apply the changes between 'merged_from_DEVEL_to_main'
|
||||
and 'DEVEL' to your work set of files)
|
||||
|
||||
We can now commit the merge result.
|
||||
cvs commit -R -m "Merged from DEVEL to main."
|
||||
|
||||
If this worked out OK, we now move the tag in the DEVEL branch
|
||||
to this merge point, so we can use this point for future merges:
|
||||
|
||||
cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
|
||||
|
||||
4 How to release lwIP
|
||||
---------------------
|
||||
|
||||
First, checkout a clean copy of the branch to be released. Tag this set with
|
||||
tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
|
||||
|
||||
Login CVS using pserver authentication, then export a clean copy of the
|
||||
tagged tree. Export is similar to a checkout, except that the CVS metadata
|
||||
is not created locally.
|
||||
|
||||
export CVS_RSH=ssh
|
||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
||||
-r STABLE-0_6_3 -d lwip-0.6.3 lwip
|
||||
|
||||
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
|
||||
|
||||
tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
|
||||
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
|
||||
zip -r lwip-0.6.3.zip lwip-0.6.3
|
||||
|
||||
Now, sign the archives with a detached GPG binary signature as follows:
|
||||
|
||||
gpg -b lwip-0.6.3.tar.gz
|
||||
gpg -b lwip-0.6.3.tar.bz2
|
||||
gpg -b lwip-0.6.3.zip
|
||||
|
||||
Upload these files using anonymous FTP:
|
||||
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
|
||||
|
||||
ncftp>mput *0.6.3.*
|
||||
|
||||
Additionally, you may post a news item on Savannah, like this:
|
||||
|
||||
A new 0.6.3 release is now available here:
|
||||
http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
|
||||
|
||||
You will have to submit this via the user News interface, then approve
|
||||
this via the Administrator News interface.
|
@ -1,181 +0,0 @@
|
||||
SNMPv1 agent for lwIP
|
||||
|
||||
Author: Christiaan Simons
|
||||
|
||||
This is a brief introduction how to use and configure the SNMP agent.
|
||||
Note the agent uses the raw-API UDP interface so you may also want to
|
||||
read rawapi.txt to gain a better understanding of the SNMP message handling.
|
||||
|
||||
0 Agent Capabilities
|
||||
====================
|
||||
|
||||
SNMPv1 per RFC1157
|
||||
This is an old(er) standard but is still widely supported.
|
||||
For SNMPv2c and v3 have a greater complexity and need many
|
||||
more lines of code. IMHO this breaks the idea of "lightweight IP".
|
||||
|
||||
Note the S in SNMP stands for "Simple". Note that "Simple" is
|
||||
relative. SNMP is simple compared to the complex ISO network
|
||||
management protocols CMIP (Common Management Information Protocol)
|
||||
and CMOT (CMip Over Tcp).
|
||||
|
||||
MIB II per RFC1213
|
||||
The standard lwIP stack management information base.
|
||||
This is a required MIB, so this is always enabled.
|
||||
When builing lwIP without TCP, the mib-2.tcp group is omitted.
|
||||
The groups EGP, CMOT and transmission are disabled by default.
|
||||
|
||||
Most mib-2 objects are not writable except:
|
||||
sysName, sysLocation, sysContact, snmpEnableAuthenTraps.
|
||||
Writing to or changing the ARP and IP address and route
|
||||
tables is not possible.
|
||||
|
||||
Note lwIP has a very limited notion of IP routing. It currently
|
||||
doen't have a route table and doesn't have a notion of the U,G,H flags.
|
||||
Instead lwIP uses the interface list with only one default interface
|
||||
acting as a single gateway interface (G) for the default route.
|
||||
|
||||
The agent returns a "virtual table" with the default route 0.0.0.0
|
||||
for the default interface and network routes (no H) for each
|
||||
network interface in the netif_list.
|
||||
All routes are considered to be up (U).
|
||||
|
||||
Loading additional MIBs
|
||||
MIBs can only be added in compile-time, not in run-time.
|
||||
There is no MIB compiler thus additional MIBs must be hand coded.
|
||||
|
||||
Large SNMP message support
|
||||
The packet decoding and encoding routines are designed
|
||||
to use pbuf-chains. Larger payloads than the minimum
|
||||
SNMP requirement of 484 octets are supported if the
|
||||
PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your
|
||||
local requirement.
|
||||
|
||||
1 Building the Agent
|
||||
====================
|
||||
|
||||
First of all you'll need to add the following define
|
||||
to your local lwipopts.h:
|
||||
|
||||
#define LWIP_SNMP 1
|
||||
|
||||
and add the source files in lwip/src/core/snmp
|
||||
and some snmp headers in lwip/src/include/lwip to your makefile.
|
||||
|
||||
Note you'll might need to adapt you network driver to update
|
||||
the mib2 variables for your interface.
|
||||
|
||||
2 Running the Agent
|
||||
===================
|
||||
|
||||
The following function calls must be made in your program to
|
||||
actually get the SNMP agent running.
|
||||
|
||||
Before starting the agent you should supply pointers
|
||||
to non-volatile memory for sysContact, sysLocation,
|
||||
and snmpEnableAuthenTraps. You can do this by calling
|
||||
|
||||
snmp_set_syscontact()
|
||||
snmp_set_syslocation()
|
||||
snmp_set_snmpenableauthentraps()
|
||||
|
||||
Additionally you may want to set
|
||||
|
||||
snmp_set_sysdescr()
|
||||
snmp_set_sysobjid() (if you have a private MIB)
|
||||
snmp_set_sysname()
|
||||
|
||||
Also before starting the agent you need to setup
|
||||
one or more trap destinations using these calls:
|
||||
|
||||
snmp_trap_dst_enable();
|
||||
snmp_trap_dst_ip_set();
|
||||
|
||||
In the lwIP initialisation sequence call snmp_init() just after
|
||||
the call to udp_init().
|
||||
|
||||
Exactly every 10 msec the SNMP uptime timestamp must be updated with
|
||||
snmp_inc_sysuptime(). You should call this from a timer interrupt
|
||||
or a timer signal handler depending on your runtime environment.
|
||||
|
||||
An alternative way to update the SNMP uptime timestamp is to do a call like
|
||||
snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to
|
||||
a lower frequency). Another one is to not call snmp_inc_sysuptime() or
|
||||
snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
|
||||
This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
|
||||
snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
|
||||
when it's queried (any function which need "sysuptime" have to call
|
||||
snmp_get_sysuptime).
|
||||
|
||||
|
||||
3 Private MIBs
|
||||
==============
|
||||
|
||||
If want to extend the agent with your own private MIB you'll need to
|
||||
add the following define to your local lwipopts.h:
|
||||
|
||||
#define SNMP_PRIVATE_MIB 1
|
||||
|
||||
You must provide the private_mib.h and associated files yourself.
|
||||
Note we don't have a "MIB compiler" that generates C source from a MIB,
|
||||
so you're required to do some serious coding if you enable this!
|
||||
|
||||
Note the lwIP enterprise ID (26381) is assigned to the lwIP project,
|
||||
ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP
|
||||
MAINTAINERS!
|
||||
|
||||
If you need to create your own private MIB you'll need
|
||||
to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html
|
||||
|
||||
You can set it by passing a struct snmp_obj_id to the agent
|
||||
using snmp_set_sysobjid(&my_object_id), just before snmp_init().
|
||||
|
||||
Note the object identifiers for thes MIB-2 and your private MIB
|
||||
tree must be kept in sorted ascending (lexicographical) order.
|
||||
This to ensure correct getnext operation.
|
||||
|
||||
An example for a private MIB is part of the "minimal Unix" project:
|
||||
contrib/ports/unix/proj/minimal/lwip_prvmib.c
|
||||
|
||||
The next chapter gives a more detailed description of the
|
||||
MIB-2 tree and the optional private MIB.
|
||||
|
||||
4 The Gory Details
|
||||
==================
|
||||
|
||||
4.0 Object identifiers and the MIB tree.
|
||||
|
||||
We have three distinct parts for all object identifiers:
|
||||
|
||||
The prefix
|
||||
.iso.org.dod.internet
|
||||
|
||||
the middle part
|
||||
.mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress
|
||||
|
||||
and the index part
|
||||
.1.192.168.0.1
|
||||
|
||||
Objects located above the .internet hierarchy aren't supported.
|
||||
Currently only the .mgmt sub-tree is available and
|
||||
when the SNMP_PRIVATE_MIB is enabled the .private tree
|
||||
becomes available too.
|
||||
|
||||
Object identifiers from incoming requests are checked
|
||||
for a matching prefix, middle part and index part
|
||||
or are expanded(*) for GetNext requests with short
|
||||
or inexisting names in the request.
|
||||
(* we call this "expansion" but this also
|
||||
resembles the "auto-completion" operation)
|
||||
|
||||
The middle part is usually located in ROM (const)
|
||||
to preserve precious RAM on small microcontrollers.
|
||||
However RAM location is possible for a dynamically
|
||||
changing private tree.
|
||||
|
||||
The index part is handled by functions which in
|
||||
turn use dynamically allocated index trees from RAM.
|
||||
These trees are updated by e.g. the etharp code
|
||||
when new entries are made or removed form the ARP cache.
|
||||
|
||||
/** @todo more gory details */
|
@ -1,216 +0,0 @@
|
||||
sys_arch interface for lwIP 0.6++
|
||||
|
||||
Author: Adam Dunkels
|
||||
|
||||
The operating system emulation layer provides a common interface
|
||||
between the lwIP code and the underlying operating system kernel. The
|
||||
general idea is that porting lwIP to new architectures requires only
|
||||
small changes to a few header files and a new sys_arch
|
||||
implementation. It is also possible to do a sys_arch implementation
|
||||
that does not rely on any underlying operating system.
|
||||
|
||||
The sys_arch provides semaphores and mailboxes to lwIP. For the full
|
||||
lwIP functionality, multiple threads support can be implemented in the
|
||||
sys_arch, but this is not required for the basic lwIP
|
||||
functionality. Previous versions of lwIP required the sys_arch to
|
||||
implement timer scheduling as well but as of lwIP 0.5 this is
|
||||
implemented in a higher layer.
|
||||
|
||||
In addition to the source file providing the functionality of sys_arch,
|
||||
the OS emulation layer must provide several header files defining
|
||||
macros used throughout lwip. The files required and the macros they
|
||||
must define are listed below the sys_arch description.
|
||||
|
||||
Semaphores can be either counting or binary - lwIP works with both
|
||||
kinds. Mailboxes are used for message passing and can be implemented
|
||||
either as a queue which allows multiple messages to be posted to a
|
||||
mailbox, or as a rendez-vous point where only one message can be
|
||||
posted at a time. lwIP works with both kinds, but the former type will
|
||||
be more efficient. A message in a mailbox is just a pointer, nothing
|
||||
more.
|
||||
|
||||
Semaphores are represented by the type "sys_sem_t" which is typedef'd
|
||||
in the sys_arch.h file. Mailboxes are equivalently represented by the
|
||||
type "sys_mbox_t". lwIP does not place any restrictions on how
|
||||
sys_sem_t or sys_mbox_t are represented internally.
|
||||
|
||||
The following functions must be implemented by the sys_arch:
|
||||
|
||||
- void sys_init(void)
|
||||
|
||||
Is called to initialize the sys_arch layer.
|
||||
|
||||
- sys_sem_t sys_sem_new(u8_t count)
|
||||
|
||||
Creates and returns a new semaphore. The "count" argument specifies
|
||||
the initial state of the semaphore.
|
||||
|
||||
- void sys_sem_free(sys_sem_t sem)
|
||||
|
||||
Deallocates a semaphore.
|
||||
|
||||
- void sys_sem_signal(sys_sem_t sem)
|
||||
|
||||
Signals a semaphore.
|
||||
|
||||
- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
|
||||
|
||||
Blocks the thread while waiting for the semaphore to be
|
||||
signaled. If the "timeout" argument is non-zero, the thread should
|
||||
only be blocked for the specified time (measured in
|
||||
milliseconds). If the "timeout" argument is zero, the thread should be
|
||||
blocked until the semaphore is signalled.
|
||||
|
||||
If the timeout argument is non-zero, the return value is the number of
|
||||
milliseconds spent waiting for the semaphore to be signaled. If the
|
||||
semaphore wasn't signaled within the specified time, the return value is
|
||||
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
|
||||
(i.e., it was already signaled), the function may return zero.
|
||||
|
||||
Notice that lwIP implements a function with a similar name,
|
||||
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
|
||||
|
||||
- sys_mbox_t sys_mbox_new(int size)
|
||||
|
||||
Creates an empty mailbox for maximum "size" elements. Elements stored
|
||||
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
|
||||
in your lwipopts.h, or ignore this parameter in your implementation
|
||||
and use a default size.
|
||||
|
||||
- void sys_mbox_free(sys_mbox_t mbox)
|
||||
|
||||
Deallocates a mailbox. If there are messages still present in the
|
||||
mailbox when the mailbox is deallocated, it is an indication of a
|
||||
programming error in lwIP and the developer should be notified.
|
||||
|
||||
- void sys_mbox_post(sys_mbox_t mbox, void *msg)
|
||||
|
||||
Posts the "msg" to the mailbox. This function have to block until
|
||||
the "msg" is really posted.
|
||||
|
||||
- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
|
||||
|
||||
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
|
||||
is full, else, ERR_OK if the "msg" is posted.
|
||||
|
||||
- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
|
||||
|
||||
Blocks the thread until a message arrives in the mailbox, but does
|
||||
not block the thread longer than "timeout" milliseconds (similar to
|
||||
the sys_arch_sem_wait() function). If "timeout" is 0, the thread should
|
||||
be blocked until a message arrives. The "msg" argument is a result
|
||||
parameter that is set by the function (i.e., by doing "*msg =
|
||||
ptr"). The "msg" parameter maybe NULL to indicate that the message
|
||||
should be dropped.
|
||||
|
||||
The return values are the same as for the sys_arch_sem_wait() function:
|
||||
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
|
||||
timeout.
|
||||
|
||||
Note that a function with a similar name, sys_mbox_fetch(), is
|
||||
implemented by lwIP.
|
||||
|
||||
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
|
||||
|
||||
This is similar to sys_arch_mbox_fetch, however if a message is not
|
||||
present in the mailbox, it immediately returns with the code
|
||||
SYS_MBOX_EMPTY. On success 0 is returned.
|
||||
|
||||
To allow for efficient implementations, this can be defined as a
|
||||
function-like macro in sys_arch.h instead of a normal function. For
|
||||
example, a naive implementation could be:
|
||||
#define sys_arch_mbox_tryfetch(mbox,msg) \
|
||||
sys_arch_mbox_fetch(mbox,msg,1)
|
||||
although this would introduce unnecessary delays.
|
||||
|
||||
If threads are supported by the underlying operating system and if
|
||||
such functionality is needed in lwIP, the following function will have
|
||||
to be implemented as well:
|
||||
|
||||
- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
|
||||
|
||||
Starts a new thread named "name" with priority "prio" that will begin its
|
||||
execution in the function "thread()". The "arg" argument will be passed as an
|
||||
argument to the thread() function. The stack size to used for this thread is
|
||||
the "stacksize" parameter. The id of the new thread is returned. Both the id
|
||||
and the priority are system dependent.
|
||||
|
||||
- sys_prot_t sys_arch_protect(void)
|
||||
|
||||
This optional function does a "fast" critical region protection and returns
|
||||
the previous protection level. This function is only called during very short
|
||||
critical regions. An embedded system which supports ISR-based drivers might
|
||||
want to implement this function by disabling interrupts. Task-based systems
|
||||
might want to implement this by using a mutex or disabling tasking. This
|
||||
function should support recursive calls from the same task or interrupt. In
|
||||
other words, sys_arch_protect() could be called while already protected. In
|
||||
that case the return value indicates that it is already protected.
|
||||
|
||||
sys_arch_protect() is only required if your port is supporting an operating
|
||||
system.
|
||||
|
||||
- void sys_arch_unprotect(sys_prot_t pval)
|
||||
|
||||
This optional function does a "fast" set of critical region protection to the
|
||||
value specified by pval. See the documentation for sys_arch_protect() for
|
||||
more information. This function is only required if your port is supporting
|
||||
an operating system.
|
||||
|
||||
Note:
|
||||
|
||||
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
|
||||
mem_malloc() you can run into a circular function call problem. In mem.c
|
||||
mem_init() tries to allcate a semaphore using mem_malloc, which of course
|
||||
can't be performed when sys_arch uses mem_malloc.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Additional files required for the "OS support" emulation layer:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
cc.h - Architecture environment, some compiler specific, some
|
||||
environment specific (probably should move env stuff
|
||||
to sys_arch.h.)
|
||||
|
||||
Typedefs for the types used by lwip -
|
||||
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
|
||||
|
||||
Compiler hints for packing lwip's structures -
|
||||
PACK_STRUCT_FIELD(x)
|
||||
PACK_STRUCT_STRUCT
|
||||
PACK_STRUCT_BEGIN
|
||||
PACK_STRUCT_END
|
||||
|
||||
Platform specific diagnostic output -
|
||||
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
|
||||
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
|
||||
Portability defines for printf formatters:
|
||||
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
|
||||
|
||||
"lightweight" synchronization mechanisms -
|
||||
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
|
||||
SYS_ARCH_PROTECT(x) - enter protection mode.
|
||||
SYS_ARCH_UNPROTECT(x) - leave protection mode.
|
||||
|
||||
If the compiler does not provide memset() this file must include a
|
||||
definition of it, or include a file which defines it.
|
||||
|
||||
This file must either include a system-local <errno.h> which defines
|
||||
the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
|
||||
to make lwip/arch.h define the codes which are used throughout.
|
||||
|
||||
|
||||
perf.h - Architecture specific performance measurement.
|
||||
Measurement calls made throughout lwip, these can be defined to nothing.
|
||||
PERF_START - start measuring something.
|
||||
PERF_STOP(x) - stop measuring something, and record the result.
|
||||
|
||||
sys_arch.h - Tied to sys_arch.c
|
||||
|
||||
Arch dependent types for the following objects:
|
||||
sys_sem_t, sys_mbox_t, sys_thread_t,
|
||||
And, optionally:
|
||||
sys_prot_t
|
||||
|
||||
Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
|
||||
SYS_MBOX_NULL NULL
|
||||
SYS_SEM_NULL NULL
|
@ -1,26 +0,0 @@
|
||||
syntax: glob
|
||||
|
||||
*.pyc
|
||||
*.orig
|
||||
*.rej
|
||||
*~
|
||||
TAGS
|
||||
Module.symvers
|
||||
*.ncb
|
||||
*.suo
|
||||
*.bak
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
syntax: regexp
|
||||
\.\#.+
|
||||
[\\/]CVS$
|
||||
^CVS$
|
||||
^build$
|
||||
^install$
|
||||
^logs.build_tree$
|
||||
[\\/]bin$
|
||||
^bin$
|
||||
[\\/]obj$
|
||||
^obj$
|
||||
\.cvsignore
|
@ -1,13 +0,0 @@
|
||||
api/ - The code for the high-level wrapper API. Not needed if
|
||||
you use the lowel-level call-back/raw API.
|
||||
|
||||
core/ - The core of the TPC/IP stack; protocol implementations,
|
||||
memory and buffer management, and the low-level raw API.
|
||||
|
||||
include/ - lwIP include files.
|
||||
|
||||
netif/ - Generic network interface device drivers are kept here,
|
||||
as well as the ARP module.
|
||||
|
||||
For more information on the various subdirectories, check the FILES
|
||||
file in each directory.
|
@ -1,740 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* Sequential API External module
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/* This is the part of the API that is linked with
|
||||
the application */
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/memp.h"
|
||||
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Create a new netconn (of a specific type) that has a callback function.
|
||||
* The corresponding pcb is also created.
|
||||
*
|
||||
* @param t the type of 'connection' to create (@see enum netconn_type)
|
||||
* @param proto the IP protocol for RAW IP pcbs
|
||||
* @param callback a function to call on status changes (RX available, TX'ed)
|
||||
* @return a newly allocated struct netconn or
|
||||
* NULL on memory error
|
||||
*/
|
||||
struct netconn*
|
||||
netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
|
||||
{
|
||||
struct netconn *conn;
|
||||
struct api_msg msg;
|
||||
|
||||
conn = netconn_alloc(t, callback);
|
||||
if (conn != NULL) {
|
||||
msg.function = do_newconn;
|
||||
msg.msg.msg.n.proto = proto;
|
||||
msg.msg.conn = conn;
|
||||
if (TCPIP_APIMSG(&msg) != ERR_OK) {
|
||||
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
|
||||
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
|
||||
LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
|
||||
#if LWIP_TCP
|
||||
LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
|
||||
#endif /* LWIP_TCP */
|
||||
sys_sem_free(&conn->op_completed);
|
||||
sys_mbox_free(&conn->recvmbox);
|
||||
memp_free(MEMP_NETCONN, conn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a netconn 'connection' and free its resources.
|
||||
* UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
|
||||
* after this returns.
|
||||
*
|
||||
* @param conn the netconn to delete
|
||||
* @return ERR_OK if the connection was deleted
|
||||
*/
|
||||
err_t
|
||||
netconn_delete(struct netconn *conn)
|
||||
{
|
||||
struct api_msg msg;
|
||||
|
||||
/* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
|
||||
if (conn == NULL) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
msg.function = do_delconn;
|
||||
msg.msg.conn = conn;
|
||||
tcpip_apimsg(&msg);
|
||||
|
||||
netconn_free(conn);
|
||||
|
||||
/* don't care for return value of do_delconn since it only calls void functions */
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local or remote IP address and port of a netconn.
|
||||
* For RAW netconns, this returns the protocol instead of a port!
|
||||
*
|
||||
* @param conn the netconn to query
|
||||
* @param addr a pointer to which to save the IP address
|
||||
* @param port a pointer to which to save the port (or protocol for RAW)
|
||||
* @param local 1 to get the local IP address, 0 to get the remote one
|
||||
* @return ERR_CONN for invalid connections
|
||||
* ERR_OK if the information was retrieved
|
||||
*/
|
||||
err_t
|
||||
netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_getaddr;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.ad.ipaddr = addr;
|
||||
msg.msg.msg.ad.port = port;
|
||||
msg.msg.msg.ad.local = local;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a netconn to a specific local IP address and port.
|
||||
* Binding one netconn twice might not always be checked correctly!
|
||||
*
|
||||
* @param conn the netconn to bind
|
||||
* @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
|
||||
* to bind to all addresses)
|
||||
* @param port the local port to bind the netconn to (not used for RAW)
|
||||
* @return ERR_OK if bound, any other err_t on failure
|
||||
*/
|
||||
err_t
|
||||
netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_bind;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.bc.ipaddr = addr;
|
||||
msg.msg.msg.bc.port = port;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect a netconn to a specific remote IP address and port.
|
||||
*
|
||||
* @param conn the netconn to connect
|
||||
* @param addr the remote IP address to connect to
|
||||
* @param port the remote port to connect to (no used for RAW)
|
||||
* @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
|
||||
*/
|
||||
err_t
|
||||
netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_connect;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.bc.ipaddr = addr;
|
||||
msg.msg.msg.bc.port = port;
|
||||
/* This is the only function which need to not block tcpip_thread */
|
||||
err = tcpip_apimsg(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect a netconn from its current peer (only valid for UDP netconns).
|
||||
*
|
||||
* @param conn the netconn to disconnect
|
||||
* @return TODO: return value is not set here...
|
||||
*/
|
||||
err_t
|
||||
netconn_disconnect(struct netconn *conn)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_disconnect;
|
||||
msg.msg.conn = conn;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a TCP netconn into listen mode
|
||||
*
|
||||
* @param conn the tcp netconn to set to listen mode
|
||||
* @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
|
||||
* @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
|
||||
* don't return any error (yet?))
|
||||
*/
|
||||
err_t
|
||||
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
|
||||
{
|
||||
#if LWIP_TCP
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
|
||||
LWIP_UNUSED_ARG(backlog);
|
||||
|
||||
LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_listen;
|
||||
msg.msg.conn = conn;
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
msg.msg.msg.lb.backlog = backlog;
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
#else /* LWIP_TCP */
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
LWIP_UNUSED_ARG(backlog);
|
||||
return ERR_ARG;
|
||||
#endif /* LWIP_TCP */
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a new connection on a TCP listening netconn.
|
||||
*
|
||||
* @param conn the TCP listen netconn
|
||||
* @param new_conn pointer where the new connection is stored
|
||||
* @return ERR_OK if a new connection has been received or an error
|
||||
* code otherwise
|
||||
*/
|
||||
err_t
|
||||
netconn_accept(struct netconn *conn, struct netconn **new_conn)
|
||||
{
|
||||
#if LWIP_TCP
|
||||
struct netconn *newconn;
|
||||
err_t err;
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
struct api_msg msg;
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
|
||||
*new_conn = NULL;
|
||||
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
|
||||
|
||||
err = conn->last_err;
|
||||
if (ERR_IS_FATAL(err)) {
|
||||
/* don't recv on fatal errors: this might block the application task
|
||||
waiting on acceptmbox forever! */
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
#else
|
||||
sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
||||
|
||||
if (newconn == NULL) {
|
||||
/* connection has been aborted */
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
|
||||
return ERR_ABRT;
|
||||
}
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
/* Let the stack know that we have accepted the connection. */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
/* don't care for the return value of do_recv */
|
||||
TCPIP_APIMSG(&msg);
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
|
||||
*new_conn = newconn;
|
||||
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||
return ERR_OK;
|
||||
#else /* LWIP_TCP */
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
LWIP_UNUSED_ARG(new_conn);
|
||||
return ERR_ARG;
|
||||
#endif /* LWIP_TCP */
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data: actual implementation that doesn't care whether pbuf or netbuf
|
||||
* is received
|
||||
*
|
||||
* @param conn the netconn from which to receive data
|
||||
* @param new_buf pointer where a new pbuf/netbuf is stored when received data
|
||||
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||
* memory error or another error)
|
||||
*/
|
||||
static err_t
|
||||
netconn_recv_data(struct netconn *conn, void **new_buf)
|
||||
{
|
||||
void *buf = NULL;
|
||||
u16_t len;
|
||||
err_t err;
|
||||
#if LWIP_TCP
|
||||
struct api_msg msg;
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
||||
*new_buf = NULL;
|
||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
|
||||
|
||||
err = conn->last_err;
|
||||
if (ERR_IS_FATAL(err)) {
|
||||
/* don't recv on fatal errors: this might block the application task
|
||||
waiting on recvmbox forever! */
|
||||
/* @todo: this does not allow us to fetch data that has been put into recvmbox
|
||||
before the fatal error occurred - is that a problem? */
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
#else
|
||||
sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
|
||||
#if LWIP_TCP
|
||||
if (conn->type == NETCONN_TCP) {
|
||||
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
|
||||
/* Let the stack know that we have taken the data. */
|
||||
/* TODO: Speedup: Don't block and wait for the answer here
|
||||
(to prevent multiple thread-switches). */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
if (buf != NULL) {
|
||||
msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
|
||||
} else {
|
||||
msg.msg.msg.r.len = 1;
|
||||
}
|
||||
/* don't care for the return value of do_recv */
|
||||
TCPIP_APIMSG(&msg);
|
||||
}
|
||||
|
||||
/* If we are closed, we indicate that we no longer wish to use the socket */
|
||||
if (buf == NULL) {
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
||||
/* Avoid to lose any previous error code */
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
|
||||
return ERR_CLSD;
|
||||
}
|
||||
len = ((struct pbuf *)buf)->tot_len;
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
|
||||
else
|
||||
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
{
|
||||
LWIP_ASSERT("buf != NULL", buf != NULL);
|
||||
len = netbuf_len((struct netbuf *)buf);
|
||||
}
|
||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||
|
||||
#if LWIP_SO_RCVBUF
|
||||
SYS_ARCH_DEC(conn->recv_avail, len);
|
||||
#endif /* LWIP_SO_RCVBUF */
|
||||
/* Register event with callback */
|
||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
|
||||
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
|
||||
|
||||
*new_buf = buf;
|
||||
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data (in form of a pbuf) from a TCP netconn
|
||||
*
|
||||
* @param conn the netconn from which to receive data
|
||||
* @param new_buf pointer where a new pbuf is stored when received data
|
||||
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||
* memory error or another error)
|
||||
* ERR_ARG if conn is not a TCP netconn
|
||||
*/
|
||||
err_t
|
||||
netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
|
||||
{
|
||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
|
||||
netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
|
||||
|
||||
return netconn_recv_data(conn, (void **)new_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive data (in form of a netbuf containing a packet buffer) from a netconn
|
||||
*
|
||||
* @param conn the netconn from which to receive data
|
||||
* @param new_buf pointer where a new netbuf is stored when received data
|
||||
* @return ERR_OK if data has been received, an error code otherwise (timeout,
|
||||
* memory error or another error)
|
||||
*/
|
||||
err_t
|
||||
netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
||||
{
|
||||
#if LWIP_TCP
|
||||
struct netbuf *buf = NULL;
|
||||
err_t err;
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
||||
*new_buf = NULL;
|
||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
|
||||
|
||||
#if LWIP_TCP
|
||||
if (conn->type == NETCONN_TCP) {
|
||||
struct pbuf *p = NULL;
|
||||
/* This is not a listening netconn, since recvmbox is set */
|
||||
|
||||
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
||||
if (buf == NULL) {
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
err = netconn_recv_data(conn, (void **)&p);
|
||||
if (err != ERR_OK) {
|
||||
memp_free(MEMP_NETBUF, buf);
|
||||
return err;
|
||||
}
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
|
||||
buf->p = p;
|
||||
buf->ptr = p;
|
||||
buf->port = 0;
|
||||
ip_addr_set_any(&buf->addr);
|
||||
*new_buf = buf;
|
||||
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||
return ERR_OK;
|
||||
} else
|
||||
#endif /* LWIP_TCP */
|
||||
{
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
return netconn_recv_data(conn, (void **)new_buf);
|
||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TCP: update the receive window: by calling this, the application
|
||||
* tells the stack that it has processed data and is able to accept
|
||||
* new data.
|
||||
* ATTENTION: use with care, this is mainly used for sockets!
|
||||
* Can only be used when calling netconn_set_noautorecved(conn, 1) before.
|
||||
*
|
||||
* @param conn the netconn for which to update the receive window
|
||||
* @param length amount of data processed (ATTENTION: this must be accurate!)
|
||||
*/
|
||||
void
|
||||
netconn_recved(struct netconn *conn, u32_t length)
|
||||
{
|
||||
#if LWIP_TCP
|
||||
if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
|
||||
(netconn_get_noautorecved(conn))) {
|
||||
struct api_msg msg;
|
||||
/* Let the stack know that we have taken the data. */
|
||||
/* TODO: Speedup: Don't block and wait for the answer here
|
||||
(to prevent multiple thread-switches). */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.r.len = length;
|
||||
/* don't care for the return value of do_recv */
|
||||
TCPIP_APIMSG(&msg);
|
||||
}
|
||||
#else /* LWIP_TCP */
|
||||
LWIP_UNUSED_ARG(conn);
|
||||
LWIP_UNUSED_ARG(length);
|
||||
#endif /* LWIP_TCP */
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data (in form of a netbuf) to a specific remote IP address and port.
|
||||
* Only to be used for UDP and RAW netconns (not TCP).
|
||||
*
|
||||
* @param conn the netconn over which to send data
|
||||
* @param buf a netbuf containing the data to send
|
||||
* @param addr the remote IP address to which to send the data
|
||||
* @param port the remote port to which to send the data
|
||||
* @return ERR_OK if data was sent, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
if (buf != NULL) {
|
||||
ip_addr_set(&buf->addr, addr);
|
||||
buf->port = port;
|
||||
return netconn_send(conn, buf);
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data over a UDP or RAW netconn (that is already connected).
|
||||
*
|
||||
* @param conn the UDP or RAW netconn over which to send data
|
||||
* @param buf a netbuf containing the data to send
|
||||
* @return ERR_OK if data was sent, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_send(struct netconn *conn, struct netbuf *buf)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
|
||||
msg.function = do_send;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.b = buf;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data over a TCP netconn.
|
||||
*
|
||||
* @param conn the TCP netconn over which to send data
|
||||
* @param dataptr pointer to the application buffer that contains the data to send
|
||||
* @param size size of the application data to send
|
||||
* @param apiflags combination of following flags :
|
||||
* - NETCONN_COPY: data will be copied into memory belonging to the stack
|
||||
* - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
|
||||
* - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
|
||||
* @return ERR_OK if data was sent, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
|
||||
if (size == 0) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* @todo: for non-blocking write, check if 'size' would ever fit into
|
||||
snd_queue or snd_buf */
|
||||
msg.function = do_write;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.w.dataptr = dataptr;
|
||||
msg.msg.msg.w.apiflags = apiflags;
|
||||
msg.msg.msg.w.len = size;
|
||||
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
|
||||
but if it is, this is done inside api_msg.c:do_write(), so we can use the
|
||||
non-blocking version here. */
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close ot shutdown a TCP netconn (doesn't delete it).
|
||||
*
|
||||
* @param conn the TCP netconn to close or shutdown
|
||||
* @param how fully close or only shutdown one side?
|
||||
* @return ERR_OK if the netconn was closed, any other err_t on error
|
||||
*/
|
||||
static err_t
|
||||
netconn_close_shutdown(struct netconn *conn, u8_t how)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_close;
|
||||
msg.msg.conn = conn;
|
||||
/* shutting down both ends is the same as closing */
|
||||
msg.msg.msg.sd.shut = how;
|
||||
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
|
||||
don't use TCPIP_APIMSG here */
|
||||
err = tcpip_apimsg(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a TCP netconn (doesn't delete it).
|
||||
*
|
||||
* @param conn the TCP netconn to close
|
||||
* @return ERR_OK if the netconn was closed, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_close(struct netconn *conn)
|
||||
{
|
||||
/* shutting down both ends is the same as closing */
|
||||
return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down one or both sides of a TCP netconn (doesn't delete it).
|
||||
*
|
||||
* @param conn the TCP netconn to shut down
|
||||
* @return ERR_OK if the netconn was closed, any other err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
|
||||
{
|
||||
return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
|
||||
}
|
||||
|
||||
#if LWIP_IGMP
|
||||
/**
|
||||
* Join multicast groups for UDP netconns.
|
||||
*
|
||||
* @param conn the UDP netconn for which to change multicast addresses
|
||||
* @param multiaddr IP address of the multicast group to join or leave
|
||||
* @param netif_addr the IP address of the network interface on which to send
|
||||
* the igmp message
|
||||
* @param join_or_leave flag whether to send a join- or leave-message
|
||||
* @return ERR_OK if the action was taken, any err_t on error
|
||||
*/
|
||||
err_t
|
||||
netconn_join_leave_group(struct netconn *conn,
|
||||
ip_addr_t *multiaddr,
|
||||
ip_addr_t *netif_addr,
|
||||
enum netconn_igmp join_or_leave)
|
||||
{
|
||||
struct api_msg msg;
|
||||
err_t err;
|
||||
|
||||
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
|
||||
|
||||
msg.function = do_join_leave_group;
|
||||
msg.msg.conn = conn;
|
||||
msg.msg.msg.jl.multiaddr = multiaddr;
|
||||
msg.msg.msg.jl.netif_addr = netif_addr;
|
||||
msg.msg.msg.jl.join_or_leave = join_or_leave;
|
||||
err = TCPIP_APIMSG(&msg);
|
||||
|
||||
NETCONN_SET_SAFE_ERR(conn, err);
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
#if LWIP_DNS
|
||||
/**
|
||||
* Execute a DNS query, only one IP address is returned
|
||||
*
|
||||
* @param name a string representation of the DNS host name to query
|
||||
* @param addr a preallocated ip_addr_t where to store the resolved IP address
|
||||
* @return ERR_OK: resolving succeeded
|
||||
* ERR_MEM: memory error, try again later
|
||||
* ERR_ARG: dns client not initialized or invalid hostname
|
||||
* ERR_VAL: dns server response was invalid
|
||||
*/
|
||||
err_t
|
||||
netconn_gethostbyname(const char *name, ip_addr_t *addr)
|
||||
{
|
||||
struct dns_api_msg msg;
|
||||
err_t err;
|
||||
sys_sem_t sem;
|
||||
|
||||
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
|
||||
|
||||
err = sys_sem_new(&sem, 0);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
msg.name = name;
|
||||
msg.addr = addr;
|
||||
msg.err = &err;
|
||||
msg.sem = &sem;
|
||||
|
||||
tcpip_callback(do_gethostbyname, &msg);
|
||||
sys_sem_wait(&sem);
|
||||
sys_sem_free(&sem);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* LWIP_DNS*/
|
||||
|
||||
#endif /* LWIP_NETCONN */
|
File diff suppressed because it is too large
Load Diff
@ -1,75 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* Error Management module
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
|
||||
static const char *err_strerr[] = {
|
||||
"Ok.", /* ERR_OK 0 */
|
||||
"Out of memory error.", /* ERR_MEM -1 */
|
||||
"Buffer error.", /* ERR_BUF -2 */
|
||||
"Timeout.", /* ERR_TIMEOUT -3 */
|
||||
"Routing problem.", /* ERR_RTE -4 */
|
||||
"Operation in progress.", /* ERR_INPROGRESS -5 */
|
||||
"Illegal value.", /* ERR_VAL -6 */
|
||||
"Operation would block.", /* ERR_WOULDBLOCK -7 */
|
||||
"Address in use.", /* ERR_USE -8 */
|
||||
"Already connected.", /* ERR_ISCONN -9 */
|
||||
"Connection aborted.", /* ERR_ABRT -10 */
|
||||
"Connection reset.", /* ERR_RST -11 */
|
||||
"Connection closed.", /* ERR_CLSD -12 */
|
||||
"Not connected.", /* ERR_CONN -13 */
|
||||
"Illegal argument.", /* ERR_ARG -14 */
|
||||
"Low-level netif error.", /* ERR_IF -15 */
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert an lwip internal error to a string representation.
|
||||
*
|
||||
* @param err an lwip internal err_t
|
||||
* @return a string representation for err
|
||||
*/
|
||||
const char *
|
||||
lwip_strerr(err_t err)
|
||||
{
|
||||
return err_strerr[-err];
|
||||
|
||||
}
|
||||
|
||||
#endif /* LWIP_DEBUG */
|
@ -1,245 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* Network buffer management
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/netbuf.h"
|
||||
#include "lwip/memp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Create (allocate) and initialize a new netbuf.
|
||||
* The netbuf doesn't yet contain a packet buffer!
|
||||
*
|
||||
* @return a pointer to a new netbuf
|
||||
* NULL on lack of memory
|
||||
*/
|
||||
struct
|
||||
netbuf *netbuf_new(void)
|
||||
{
|
||||
struct netbuf *buf;
|
||||
|
||||
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
||||
if (buf != NULL) {
|
||||
buf->p = NULL;
|
||||
buf->ptr = NULL;
|
||||
ip_addr_set_any(&buf->addr);
|
||||
buf->port = 0;
|
||||
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
buf->flags = 0;
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
buf->toport_chksum = 0;
|
||||
#if LWIP_NETBUF_RECVINFO
|
||||
ip_addr_set_any(&buf->toaddr);
|
||||
#endif /* LWIP_NETBUF_RECVINFO */
|
||||
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
|
||||
return buf;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocate a netbuf allocated by netbuf_new().
|
||||
*
|
||||
* @param buf pointer to a netbuf allocated by netbuf_new()
|
||||
*/
|
||||
void
|
||||
netbuf_delete(struct netbuf *buf)
|
||||
{
|
||||
if (buf != NULL) {
|
||||
if (buf->p != NULL) {
|
||||
pbuf_free(buf->p);
|
||||
buf->p = buf->ptr = NULL;
|
||||
}
|
||||
memp_free(MEMP_NETBUF, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate memory for a packet buffer for a given netbuf.
|
||||
*
|
||||
* @param buf the netbuf for which to allocate a packet buffer
|
||||
* @param size the size of the packet buffer to allocate
|
||||
* @return pointer to the allocated memory
|
||||
* NULL if no memory could be allocated
|
||||
*/
|
||||
void *
|
||||
netbuf_alloc(struct netbuf *buf, u16_t size)
|
||||
{
|
||||
LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);
|
||||
|
||||
/* Deallocate any previously allocated memory. */
|
||||
if (buf->p != NULL) {
|
||||
pbuf_free(buf->p);
|
||||
}
|
||||
buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
|
||||
if (buf->p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold size",
|
||||
(buf->p->len >= size));
|
||||
buf->ptr = buf->p;
|
||||
return buf->p->payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the packet buffer included in a netbuf
|
||||
*
|
||||
* @param buf pointer to the netbuf which contains the packet buffer to free
|
||||
*/
|
||||
void
|
||||
netbuf_free(struct netbuf *buf)
|
||||
{
|
||||
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
|
||||
if (buf->p != NULL) {
|
||||
pbuf_free(buf->p);
|
||||
}
|
||||
buf->p = buf->ptr = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Let a netbuf reference existing (non-volatile) data.
|
||||
*
|
||||
* @param buf netbuf which should reference the data
|
||||
* @param dataptr pointer to the data to reference
|
||||
* @param size size of the data
|
||||
* @return ERR_OK if data is referenced
|
||||
* ERR_MEM if data couldn't be referenced due to lack of memory
|
||||
*/
|
||||
err_t
|
||||
netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
||||
{
|
||||
LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);
|
||||
if (buf->p != NULL) {
|
||||
pbuf_free(buf->p);
|
||||
}
|
||||
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
|
||||
if (buf->p == NULL) {
|
||||
buf->ptr = NULL;
|
||||
return ERR_MEM;
|
||||
}
|
||||
buf->p->payload = (void*)dataptr;
|
||||
buf->p->len = buf->p->tot_len = size;
|
||||
buf->ptr = buf->p;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain one netbuf to another (@see pbuf_chain)
|
||||
*
|
||||
* @param head the first netbuf
|
||||
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
|
||||
*/
|
||||
void
|
||||
netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
||||
{
|
||||
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
|
||||
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
|
||||
pbuf_cat(head->p, tail->p);
|
||||
head->ptr = head->p;
|
||||
memp_free(MEMP_NETBUF, tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data pointer and length of the data inside a netbuf.
|
||||
*
|
||||
* @param buf netbuf to get the data from
|
||||
* @param dataptr pointer to a void pointer where to store the data pointer
|
||||
* @param len pointer to an u16_t where the length of the data is stored
|
||||
* @return ERR_OK if the information was retreived,
|
||||
* ERR_BUF on error.
|
||||
*/
|
||||
err_t
|
||||
netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
|
||||
{
|
||||
LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
|
||||
LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);
|
||||
|
||||
if (buf->ptr == NULL) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
*dataptr = buf->ptr->payload;
|
||||
*len = buf->ptr->len;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the current data pointer of a packet buffer contained in a netbuf
|
||||
* to the next part.
|
||||
* The packet buffer itself is not modified.
|
||||
*
|
||||
* @param buf the netbuf to modify
|
||||
* @return -1 if there is no next part
|
||||
* 1 if moved to the next part but now there is no next part
|
||||
* 0 if moved to the next part and there are still more parts
|
||||
*/
|
||||
s8_t
|
||||
netbuf_next(struct netbuf *buf)
|
||||
{
|
||||
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
|
||||
if (buf->ptr->next == NULL) {
|
||||
return -1;
|
||||
}
|
||||
buf->ptr = buf->ptr->next;
|
||||
if (buf->ptr->next == NULL) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the current data pointer of a packet buffer contained in a netbuf
|
||||
* to the beginning of the packet.
|
||||
* The packet buffer itself is not modified.
|
||||
*
|
||||
* @param buf the netbuf to modify
|
||||
*/
|
||||
void
|
||||
netbuf_first(struct netbuf *buf)
|
||||
{
|
||||
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
|
||||
buf->ptr = buf->p;
|
||||
}
|
||||
|
||||
#endif /* LWIP_NETCONN */
|
@ -1,352 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* API functions for name resolving
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/netdb.h"
|
||||
|
||||
#if LWIP_DNS && LWIP_SOCKET
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** helper struct for gethostbyname_r to access the char* buffer */
|
||||
struct gethostbyname_r_helper {
|
||||
ip_addr_t *addrs;
|
||||
ip_addr_t addr;
|
||||
char *aliases;
|
||||
};
|
||||
|
||||
/** h_errno is exported in netdb.h for access by applications. */
|
||||
#if LWIP_DNS_API_DECLARE_H_ERRNO
|
||||
int h_errno;
|
||||
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
|
||||
|
||||
/** define "hostent" variables storage: 0 if we use a static (but unprotected)
|
||||
* set of variables for lwip_gethostbyname, 1 if we use a local storage */
|
||||
#ifndef LWIP_DNS_API_HOSTENT_STORAGE
|
||||
#define LWIP_DNS_API_HOSTENT_STORAGE 0
|
||||
#endif
|
||||
|
||||
/** define "hostent" variables storage */
|
||||
#if LWIP_DNS_API_HOSTENT_STORAGE
|
||||
#define HOSTENT_STORAGE
|
||||
#else
|
||||
#define HOSTENT_STORAGE static
|
||||
#endif /* LWIP_DNS_API_STATIC_HOSTENT */
|
||||
|
||||
/**
|
||||
* Returns an entry containing addresses of address family AF_INET
|
||||
* for the host with name name.
|
||||
* Due to dns_gethostbyname limitations, only one address is returned.
|
||||
*
|
||||
* @param name the hostname to resolve
|
||||
* @return an entry containing addresses of address family AF_INET
|
||||
* for the host with name name
|
||||
*/
|
||||
struct hostent*
|
||||
lwip_gethostbyname(const char *name)
|
||||
{
|
||||
err_t err;
|
||||
ip_addr_t addr;
|
||||
|
||||
/* buffer variables for lwip_gethostbyname() */
|
||||
HOSTENT_STORAGE struct hostent s_hostent;
|
||||
HOSTENT_STORAGE char *s_aliases;
|
||||
HOSTENT_STORAGE ip_addr_t s_hostent_addr;
|
||||
HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
|
||||
|
||||
/* query host IP address */
|
||||
err = netconn_gethostbyname(name, &addr);
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
|
||||
h_errno = HOST_NOT_FOUND;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* fill hostent */
|
||||
s_hostent_addr = addr;
|
||||
s_phostent_addr[0] = &s_hostent_addr;
|
||||
s_phostent_addr[1] = NULL;
|
||||
s_hostent.h_name = (char*)name;
|
||||
s_hostent.h_aliases = &s_aliases;
|
||||
s_hostent.h_addrtype = AF_INET;
|
||||
s_hostent.h_length = sizeof(ip_addr_t);
|
||||
s_hostent.h_addr_list = (char**)&s_phostent_addr;
|
||||
|
||||
#if DNS_DEBUG
|
||||
/* dump hostent */
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
|
||||
if (s_hostent.h_aliases != NULL) {
|
||||
u8_t idx;
|
||||
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
|
||||
}
|
||||
}
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
|
||||
if (s_hostent.h_addr_list != NULL) {
|
||||
u8_t idx;
|
||||
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
|
||||
}
|
||||
}
|
||||
#endif /* DNS_DEBUG */
|
||||
|
||||
#if LWIP_DNS_API_HOSTENT_STORAGE
|
||||
/* this function should return the "per-thread" hostent after copy from s_hostent */
|
||||
return sys_thread_hostent(&s_hostent);
|
||||
#else
|
||||
return &s_hostent;
|
||||
#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread-safe variant of lwip_gethostbyname: instead of using a static
|
||||
* buffer, this function takes buffer and errno pointers as arguments
|
||||
* and uses these for the result.
|
||||
*
|
||||
* @param name the hostname to resolve
|
||||
* @param ret pre-allocated struct where to store the result
|
||||
* @param buf pre-allocated buffer where to store additional data
|
||||
* @param buflen the size of buf
|
||||
* @param result pointer to a hostent pointer that is set to ret on success
|
||||
* and set to zero on error
|
||||
* @param h_errnop pointer to an int where to store errors (instead of modifying
|
||||
* the global h_errno)
|
||||
* @return 0 on success, non-zero on error, additional error information
|
||||
* is stored in *h_errnop instead of h_errno to be thread-safe
|
||||
*/
|
||||
int
|
||||
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
size_t buflen, struct hostent **result, int *h_errnop)
|
||||
{
|
||||
err_t err;
|
||||
struct gethostbyname_r_helper *h;
|
||||
char *hostname;
|
||||
size_t namelen;
|
||||
int lh_errno;
|
||||
|
||||
if (h_errnop == NULL) {
|
||||
/* ensure h_errnop is never NULL */
|
||||
h_errnop = &lh_errno;
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
/* not all arguments given */
|
||||
*h_errnop = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* first thing to do: set *result to nothing */
|
||||
*result = NULL;
|
||||
if ((name == NULL) || (ret == NULL) || (buf == 0)) {
|
||||
/* not all arguments given */
|
||||
*h_errnop = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
namelen = strlen(name);
|
||||
if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
|
||||
/* buf can't hold the data needed + a copy of name */
|
||||
*h_errnop = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
|
||||
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
|
||||
|
||||
/* query host IP address */
|
||||
err = netconn_gethostbyname(name, &(h->addr));
|
||||
if (err != ERR_OK) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
|
||||
*h_errnop = ENSRNOTFOUND;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* copy the hostname into buf */
|
||||
MEMCPY(hostname, name, namelen);
|
||||
hostname[namelen] = 0;
|
||||
|
||||
/* fill hostent */
|
||||
h->addrs = &(h->addr);
|
||||
h->aliases = NULL;
|
||||
ret->h_name = (char*)hostname;
|
||||
ret->h_aliases = &(h->aliases);
|
||||
ret->h_addrtype = AF_INET;
|
||||
ret->h_length = sizeof(ip_addr_t);
|
||||
ret->h_addr_list = (char**)&(h->addrs);
|
||||
|
||||
/* set result != NULL */
|
||||
*result = ret;
|
||||
|
||||
/* return success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees one or more addrinfo structures returned by getaddrinfo(), along with
|
||||
* any additional storage associated with those structures. If the ai_next field
|
||||
* of the structure is not null, the entire list of structures is freed.
|
||||
*
|
||||
* @param ai struct addrinfo to free
|
||||
*/
|
||||
void
|
||||
lwip_freeaddrinfo(struct addrinfo *ai)
|
||||
{
|
||||
struct addrinfo *next;
|
||||
|
||||
while (ai != NULL) {
|
||||
next = ai->ai_next;
|
||||
memp_free(MEMP_NETDB, ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the name of a service location (for example, a host name) and/or
|
||||
* a service name and returns a set of socket addresses and associated
|
||||
* information to be used in creating a socket with which to address the
|
||||
* specified service.
|
||||
* Memory for the result is allocated internally and must be freed by calling
|
||||
* lwip_freeaddrinfo()!
|
||||
*
|
||||
* Due to a limitation in dns_gethostbyname, only the first address of a
|
||||
* host is returned.
|
||||
* Also, service names are not supported (only port numbers)!
|
||||
*
|
||||
* @param nodename descriptive name or address string of the host
|
||||
* (may be NULL -> local address)
|
||||
* @param servname port number as string of NULL
|
||||
* @param hints structure containing input values that set socktype and protocol
|
||||
* @param res pointer to a pointer where to store the result (set to NULL on failure)
|
||||
* @return 0 on success, non-zero on failure
|
||||
*/
|
||||
int
|
||||
lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
err_t err;
|
||||
ip_addr_t addr;
|
||||
struct addrinfo *ai;
|
||||
struct sockaddr_in *sa = NULL;
|
||||
int port_nr = 0;
|
||||
size_t total_size;
|
||||
size_t namelen = 0;
|
||||
|
||||
if (res == NULL) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
*res = NULL;
|
||||
if ((nodename == NULL) && (servname == NULL)) {
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
if (servname != NULL) {
|
||||
/* service name specified: convert to port number
|
||||
* @todo?: currently, only ASCII integers (port numbers) are supported! */
|
||||
port_nr = atoi(servname);
|
||||
if ((port_nr <= 0) || (port_nr > 0xffff)) {
|
||||
return EAI_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodename != NULL) {
|
||||
/* service location specified, try to resolve */
|
||||
err = netconn_gethostbyname(nodename, &addr);
|
||||
if (err != ERR_OK) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
} else {
|
||||
/* service location specified, use loopback address */
|
||||
ip_addr_set_loopback(&addr);
|
||||
}
|
||||
|
||||
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
|
||||
if (nodename != NULL) {
|
||||
namelen = strlen(nodename);
|
||||
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
|
||||
total_size += namelen + 1;
|
||||
}
|
||||
/* If this fails, please report to lwip-devel! :-) */
|
||||
LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
|
||||
total_size <= NETDB_ELEM_SIZE);
|
||||
ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
|
||||
if (ai == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
memset(ai, 0, total_size);
|
||||
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
|
||||
/* set up sockaddr */
|
||||
inet_addr_from_ipaddr(&sa->sin_addr, &addr);
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_len = sizeof(struct sockaddr_in);
|
||||
sa->sin_port = htons((u16_t)port_nr);
|
||||
|
||||
/* set up addrinfo */
|
||||
ai->ai_family = AF_INET;
|
||||
if (hints != NULL) {
|
||||
/* copy socktype & protocol from hints if specified */
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
ai->ai_protocol = hints->ai_protocol;
|
||||
}
|
||||
if (nodename != NULL) {
|
||||
/* copy nodename to canonname if specified */
|
||||
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
||||
MEMCPY(ai->ai_canonname, nodename, namelen);
|
||||
ai->ai_canonname[namelen] = 0;
|
||||
}
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ai->ai_addr = (struct sockaddr*)sa;
|
||||
|
||||
*res = ai;
|
||||
|
||||
return 0;
|
||||
memerr:
|
||||
if (ai != NULL) {
|
||||
memp_free(MEMP_NETDB, ai);
|
||||
}
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
#endif /* LWIP_DNS && LWIP_SOCKET */
|
@ -1,160 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* Network Interface Sequential API module
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/netifapi.h"
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
/**
|
||||
* Call netif_add() inside the tcpip_thread context.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
|
||||
{
|
||||
if (!netif_add( msg->netif,
|
||||
msg->msg.add.ipaddr,
|
||||
msg->msg.add.netmask,
|
||||
msg->msg.add.gw,
|
||||
msg->msg.add.state,
|
||||
msg->msg.add.init,
|
||||
msg->msg.add.input)) {
|
||||
msg->err = ERR_IF;
|
||||
} else {
|
||||
msg->err = ERR_OK;
|
||||
}
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_set_addr() inside the tcpip_thread context.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
|
||||
{
|
||||
netif_set_addr( msg->netif,
|
||||
msg->msg.add.ipaddr,
|
||||
msg->msg.add.netmask,
|
||||
msg->msg.add.gw);
|
||||
msg->err = ERR_OK;
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
|
||||
* tcpip_thread context.
|
||||
*/
|
||||
void
|
||||
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
|
||||
{
|
||||
if (msg->msg.common.errtfunc != NULL) {
|
||||
msg->err = msg->msg.common.errtfunc(msg->netif);
|
||||
} else {
|
||||
msg->err = ERR_OK;
|
||||
msg->msg.common.voidfunc(msg->netif);
|
||||
}
|
||||
TCPIP_NETIFAPI_ACK(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_add() in a thread-safe way by running that function inside the
|
||||
* tcpip_thread context.
|
||||
*
|
||||
* @note for params @see netif_add()
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_add(struct netif *netif,
|
||||
ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask,
|
||||
ip_addr_t *gw,
|
||||
void *state,
|
||||
netif_init_fn init,
|
||||
netif_input_fn input)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_add;
|
||||
msg.msg.netif = netif;
|
||||
msg.msg.msg.add.ipaddr = ipaddr;
|
||||
msg.msg.msg.add.netmask = netmask;
|
||||
msg.msg.msg.add.gw = gw;
|
||||
msg.msg.msg.add.state = state;
|
||||
msg.msg.msg.add.init = init;
|
||||
msg.msg.msg.add.input = input;
|
||||
TCPIP_NETIFAPI(&msg);
|
||||
return msg.msg.err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call netif_set_addr() in a thread-safe way by running that function inside the
|
||||
* tcpip_thread context.
|
||||
*
|
||||
* @note for params @see netif_set_addr()
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_set_addr(struct netif *netif,
|
||||
ip_addr_t *ipaddr,
|
||||
ip_addr_t *netmask,
|
||||
ip_addr_t *gw)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_set_addr;
|
||||
msg.msg.netif = netif;
|
||||
msg.msg.msg.add.ipaddr = ipaddr;
|
||||
msg.msg.msg.add.netmask = netmask;
|
||||
msg.msg.msg.add.gw = gw;
|
||||
TCPIP_NETIFAPI(&msg);
|
||||
return msg.msg.err;
|
||||
}
|
||||
|
||||
/**
|
||||
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
|
||||
* way by running that function inside the tcpip_thread context.
|
||||
*
|
||||
* @note use only for functions where there is only "netif" parameter.
|
||||
*/
|
||||
err_t
|
||||
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
|
||||
netifapi_errt_fn errtfunc)
|
||||
{
|
||||
struct netifapi_msg msg;
|
||||
msg.function = do_netifapi_netif_common;
|
||||
msg.msg.netif = netif;
|
||||
msg.msg.msg.common.voidfunc = voidfunc;
|
||||
msg.msg.msg.common.errtfunc = errtfunc;
|
||||
TCPIP_NETIFAPI(&msg);
|
||||
return msg.msg.err;
|
||||
}
|
||||
|
||||
#endif /* LWIP_NETIF_API */
|
File diff suppressed because it is too large
Load Diff
@ -1,460 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* Sequential API Main thread module
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/init.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ppp_oe.h"
|
||||
|
||||
/* global variables */
|
||||
static tcpip_init_done_fn tcpip_init_done;
|
||||
static void *tcpip_init_done_arg;
|
||||
static sys_mbox_t mbox;
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
/** The global semaphore to lock the stack. */
|
||||
sys_mutex_t lock_tcpip_core;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
|
||||
/**
|
||||
* The main lwIP thread. This thread has exclusive access to lwIP core functions
|
||||
* (unless access to them is not locked). Other threads communicate with this
|
||||
* thread using message boxes.
|
||||
*
|
||||
* It also starts all the timers to make sure they are running in the right
|
||||
* thread context.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
tcpip_thread(void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
if (tcpip_init_done != NULL) {
|
||||
tcpip_init_done(tcpip_init_done_arg);
|
||||
}
|
||||
|
||||
LOCK_TCPIP_CORE();
|
||||
while (1) { /* MAIN Loop */
|
||||
UNLOCK_TCPIP_CORE();
|
||||
LWIP_TCPIP_THREAD_ALIVE();
|
||||
/* wait for a message, timeouts are processed while waiting */
|
||||
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
|
||||
LOCK_TCPIP_CORE();
|
||||
switch (msg->type) {
|
||||
#if LWIP_NETCONN
|
||||
case TCPIP_MSG_API:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
|
||||
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
|
||||
break;
|
||||
#endif /* LWIP_NETCONN */
|
||||
|
||||
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
case TCPIP_MSG_INPKT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
|
||||
#if LWIP_ETHERNET
|
||||
if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
|
||||
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
|
||||
} else
|
||||
#endif /* LWIP_ETHERNET */
|
||||
{
|
||||
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
|
||||
}
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
break;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
|
||||
#if LWIP_NETIF_API
|
||||
case TCPIP_MSG_NETIFAPI:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
|
||||
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
|
||||
break;
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
case TCPIP_MSG_CALLBACK:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
|
||||
msg->msg.cb.function(msg->msg.cb.ctx);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT
|
||||
case TCPIP_MSG_TIMEOUT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
||||
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
case TCPIP_MSG_UNTIMEOUT:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
|
||||
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
break;
|
||||
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||
|
||||
default:
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
|
||||
LWIP_ASSERT("tcpip_thread: invalid message", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass a received packet to tcpip_thread for input processing
|
||||
*
|
||||
* @param p the received packet, p->payload pointing to the Ethernet header or
|
||||
* to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
|
||||
* NETIF_FLAG_ETHERNET flags)
|
||||
* @param inp the network interface on which the packet was received
|
||||
*/
|
||||
err_t
|
||||
tcpip_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
#if LWIP_TCPIP_CORE_LOCKING_INPUT
|
||||
err_t ret;
|
||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
|
||||
LOCK_TCPIP_CORE();
|
||||
#if LWIP_ETHERNET
|
||||
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
|
||||
ret = ethernet_input(p, inp);
|
||||
} else
|
||||
#endif /* LWIP_ETHERNET */
|
||||
{
|
||||
ret = ip_input(p, inp);
|
||||
}
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return ret;
|
||||
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_INPKT;
|
||||
msg->msg.inp.p = p;
|
||||
msg->msg.inp.netif = inp;
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a specific function in the thread context of
|
||||
* tcpip_thread for easy access synchronization.
|
||||
* A function called in that way may access lwIP core code
|
||||
* without fearing concurrent access.
|
||||
*
|
||||
* @param f the function to call
|
||||
* @param ctx parameter passed to f
|
||||
* @param block 1 to block until the request is posted, 0 to non-blocking mode
|
||||
* @return ERR_OK if the function was called, another err_t if not
|
||||
*/
|
||||
err_t
|
||||
tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_CALLBACK;
|
||||
msg->msg.cb.function = function;
|
||||
msg->msg.cb.ctx = ctx;
|
||||
if (block) {
|
||||
sys_mbox_post(&mbox, msg);
|
||||
} else {
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
||||
return ERR_MEM;
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
#if LWIP_TCPIP_TIMEOUT
|
||||
/**
|
||||
* call sys_timeout in tcpip_thread
|
||||
*
|
||||
* @param msec time in milliseconds for timeout
|
||||
* @param h function to be called on timeout
|
||||
* @param arg argument to pass to timeout function h
|
||||
* @return ERR_MEM on memory error, ERR_OK otherwise
|
||||
*/
|
||||
err_t
|
||||
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_TIMEOUT;
|
||||
msg->msg.tmo.msecs = msecs;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* call sys_untimeout in tcpip_thread
|
||||
*
|
||||
* @param msec time in milliseconds for timeout
|
||||
* @param h function to be called on timeout
|
||||
* @param arg argument to pass to timeout function h
|
||||
* @return ERR_MEM on memory error, ERR_OK otherwise
|
||||
*/
|
||||
err_t
|
||||
tcpip_untimeout(sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct tcpip_msg *msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
|
||||
if (msg == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
msg->type = TCPIP_MSG_UNTIMEOUT;
|
||||
msg->msg.tmo.h = h;
|
||||
msg->msg.tmo.arg = arg;
|
||||
sys_mbox_post(&mbox, msg);
|
||||
return ERR_OK;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
#endif /* LWIP_TCPIP_TIMEOUT */
|
||||
|
||||
#if LWIP_NETCONN
|
||||
/**
|
||||
* Call the lower part of a netconn_* function
|
||||
* This function is then running in the thread context
|
||||
* of tcpip_thread and has exclusive access to lwIP core code.
|
||||
*
|
||||
* @param apimsg a struct containing the function to call and its parameters
|
||||
* @return ERR_OK if the function was called, another err_t if not
|
||||
*/
|
||||
err_t
|
||||
tcpip_apimsg(struct api_msg *apimsg)
|
||||
{
|
||||
struct tcpip_msg msg;
|
||||
#ifdef LWIP_DEBUG
|
||||
/* catch functions that don't set err */
|
||||
apimsg->msg.err = ERR_VAL;
|
||||
#endif
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
msg.type = TCPIP_MSG_API;
|
||||
msg.msg.apimsg = apimsg;
|
||||
sys_mbox_post(&mbox, &msg);
|
||||
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
|
||||
return apimsg->msg.err;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
/**
|
||||
* Call the lower part of a netconn_* function
|
||||
* This function has exclusive access to lwIP core code by locking it
|
||||
* before the function is called.
|
||||
*
|
||||
* @param apimsg a struct containing the function to call and its parameters
|
||||
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
|
||||
*/
|
||||
err_t
|
||||
tcpip_apimsg_lock(struct api_msg *apimsg)
|
||||
{
|
||||
#ifdef LWIP_DEBUG
|
||||
/* catch functions that don't set err */
|
||||
apimsg->msg.err = ERR_VAL;
|
||||
#endif
|
||||
|
||||
LOCK_TCPIP_CORE();
|
||||
apimsg->function(&(apimsg->msg));
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return apimsg->msg.err;
|
||||
|
||||
}
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
#endif /* LWIP_NETCONN */
|
||||
|
||||
#if LWIP_NETIF_API
|
||||
#if !LWIP_TCPIP_CORE_LOCKING
|
||||
/**
|
||||
* Much like tcpip_apimsg, but calls the lower part of a netifapi_*
|
||||
* function.
|
||||
*
|
||||
* @param netifapimsg a struct containing the function to call and its parameters
|
||||
* @return error code given back by the function that was called
|
||||
*/
|
||||
err_t
|
||||
tcpip_netifapi(struct netifapi_msg* netifapimsg)
|
||||
{
|
||||
struct tcpip_msg msg;
|
||||
|
||||
if (sys_mbox_valid(&mbox)) {
|
||||
err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);
|
||||
if (err != ERR_OK) {
|
||||
netifapimsg->msg.err = err;
|
||||
return err;
|
||||
}
|
||||
|
||||
msg.type = TCPIP_MSG_NETIFAPI;
|
||||
msg.msg.netifapimsg = netifapimsg;
|
||||
sys_mbox_post(&mbox, &msg);
|
||||
sys_sem_wait(&netifapimsg->msg.sem);
|
||||
sys_sem_free(&netifapimsg->msg.sem);
|
||||
return netifapimsg->msg.err;
|
||||
}
|
||||
return ERR_VAL;
|
||||
}
|
||||
#else /* !LWIP_TCPIP_CORE_LOCKING */
|
||||
/**
|
||||
* Call the lower part of a netifapi_* function
|
||||
* This function has exclusive access to lwIP core code by locking it
|
||||
* before the function is called.
|
||||
*
|
||||
* @param netifapimsg a struct containing the function to call and its parameters
|
||||
* @return ERR_OK (only for compatibility fo tcpip_netifapi())
|
||||
*/
|
||||
err_t
|
||||
tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
|
||||
{
|
||||
LOCK_TCPIP_CORE();
|
||||
netifapimsg->function(&(netifapimsg->msg));
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return netifapimsg->msg.err;
|
||||
}
|
||||
#endif /* !LWIP_TCPIP_CORE_LOCKING */
|
||||
#endif /* LWIP_NETIF_API */
|
||||
|
||||
/**
|
||||
* Initialize this module:
|
||||
* - initialize all sub modules
|
||||
* - start the tcpip_thread
|
||||
*
|
||||
* @param initfunc a function to call when tcpip_thread is running and finished initializing
|
||||
* @param arg argument to pass to initfunc
|
||||
*/
|
||||
void
|
||||
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
|
||||
{
|
||||
lwip_init();
|
||||
|
||||
tcpip_init_done = initfunc;
|
||||
tcpip_init_done_arg = arg;
|
||||
if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
|
||||
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
|
||||
}
|
||||
#if LWIP_TCPIP_CORE_LOCKING
|
||||
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
|
||||
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
|
||||
}
|
||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||
|
||||
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple callback function used with tcpip_callback to free a pbuf
|
||||
* (pbuf_free has a wrong signature for tcpip_callback)
|
||||
*
|
||||
* @param p The pbuf (chain) to be dereferenced.
|
||||
*/
|
||||
static void
|
||||
pbuf_free_int(void *p)
|
||||
{
|
||||
struct pbuf *q = (struct pbuf *)p;
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper function that allows you to free a pbuf from interrupt context.
|
||||
*
|
||||
* @param p The pbuf (chain) to be dereferenced.
|
||||
* @return ERR_OK if callback could be enqueued, an err_t if not
|
||||
*/
|
||||
err_t
|
||||
pbuf_free_callback(struct pbuf *p)
|
||||
{
|
||||
return tcpip_callback_with_block(pbuf_free_int, p, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper function that allows you to free heap memory from
|
||||
* interrupt context.
|
||||
*
|
||||
* @param m the heap memory to free
|
||||
* @return ERR_OK if callback could be enqueued, an err_t if not
|
||||
*/
|
||||
err_t
|
||||
mem_free_callback(void *m)
|
||||
{
|
||||
return tcpip_callback_with_block(mem_free, m, 0);
|
||||
}
|
||||
|
||||
#endif /* !NO_SYS */
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
#pragma pack(1)
|
||||
#endif
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: cc.h,v 1.1.1.1 2004/12/16 14:17:13 bear Exp $
|
||||
*/
|
||||
#ifndef __ARCH_CC_H__
|
||||
#define __ARCH_CC_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
typedef rt_uint8_t u8_t;
|
||||
typedef rt_int8_t s8_t;
|
||||
typedef rt_uint16_t u16_t;
|
||||
typedef rt_int16_t s16_t;
|
||||
typedef rt_uint32_t u32_t;
|
||||
typedef rt_int32_t s32_t;
|
||||
typedef rt_uint32_t mem_ptr_t;
|
||||
|
||||
#define U16_F "hu"
|
||||
#define S16_F "hd"
|
||||
#define X16_F "hx"
|
||||
#define U32_F "lu"
|
||||
#define S32_F "ld"
|
||||
#define X32_F "lx"
|
||||
|
||||
#ifdef RT_USING_NEWLIB
|
||||
#include <errno.h>
|
||||
/* some errno not defined in newlib */
|
||||
#define ENSRNOTFOUND 163 /* Domain name not found */
|
||||
/* WARNING: ESHUTDOWN also not defined in newlib. We chose
|
||||
180 here because the number "108" which is used
|
||||
in arch.h has been assigned to another error code. */
|
||||
#define ESHUTDOWN 180
|
||||
#elif RT_USING_MINILIBC
|
||||
#include <errno.h>
|
||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||
#else
|
||||
#define LWIP_PROVIDE_ERRNO
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_MINILIBC
|
||||
#include <time.h>
|
||||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
#endif
|
||||
|
||||
#if defined(__CC_ARM) /* ARMCC compiler */
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_END
|
||||
#elif defined(__IAR_SYSTEMS_ICC__) /* IAR Compiler */
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
#define PACK_STRUCT_USE_INCLUDES
|
||||
#elif defined(__GNUC__) /* GNU GCC Compiler */
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
#define PACK_STRUCT_STRUCT __attribute__((packed))
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_END
|
||||
#elif defined(_MSC_VER)
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_END
|
||||
#endif
|
||||
|
||||
void sys_arch_assert(const char* file, int line);
|
||||
#define LWIP_PLATFORM_DIAG(x) do {rt_kprintf x;} while(0)
|
||||
#define LWIP_PLATFORM_ASSERT(x) do {rt_kprintf(x); sys_arch_assert(__FILE__, __LINE__);}while(0)
|
||||
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#endif /* __ARCH_CC_H__ */
|
||||
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
#pragma pack()
|
||||
#endif
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
* $Id: perf.h,v 1.1.1.1 2004/12/16 14:17:13 bear Exp $
|
||||
*/
|
||||
#ifndef __ARCH_PERF_H__
|
||||
#define __ARCH_PERF_H__
|
||||
|
||||
//#include <sys/times.h>
|
||||
|
||||
#define PERF_START /* null definition */
|
||||
#define PERF_STOP(x) /* null definition */
|
||||
|
||||
/*
|
||||
void perf_print(unsigned long c1l, unsigned long c1h,
|
||||
unsigned long c2l, unsigned long c2h,
|
||||
char *key);
|
||||
|
||||
void perf_print_times(struct tms *start, struct tms *end, char *key);
|
||||
|
||||
void perf_init(char *fname);
|
||||
*/
|
||||
#endif /* __ARCH_PERF_H__ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user