提交 94e1935f 编写于 作者: W weety

Merge branch 'master' of https://github.com/RT-Thread/rt-thread into fixed

...@@ -8,8 +8,9 @@ ...@@ -8,8 +8,9 @@
* http://www.rt-thread.org/license/LICENSE * http://www.rt-thread.org/license/LICENSE
* *
* Change Logs: * Change Logs:
* Date Author Notes * Date Author Notes
* 2015-03-24 Bright the first version * 2015-03-24 Bright the first version
* 2016-05-23 Margguo@gmail.com Add 48 pins IC define
*/ */
#include <rthw.h> #include <rthw.h>
...@@ -19,7 +20,7 @@ ...@@ -19,7 +20,7 @@
#ifdef RT_USING_PIN #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(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} #define __STM32_PIN_DEFAULT {-1, 0, 0, 0}
...@@ -35,6 +36,58 @@ struct pin_index ...@@ -35,6 +36,58 @@ struct pin_index
static const struct pin_index pins[] = 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) #if (STM32F10X_PIN_NUMBERS == 64)
__STM32_PIN_DEFAULT, __STM32_PIN_DEFAULT,
__STM32_PIN_DEFAULT, __STM32_PIN_DEFAULT,
...@@ -216,7 +269,7 @@ static const struct pin_index pins[] = ...@@ -216,7 +269,7 @@ static const struct pin_index pins[] =
__STM32_PIN(7, APB2, C, 13), __STM32_PIN(7, APB2, C, 13),
__STM32_PIN(8, APB2, C, 14), __STM32_PIN(8, APB2, C, 14),
__STM32_PIN(9, APB2, C, 15), __STM32_PIN(9, APB2, C, 15),
__STM32_PIN(10, APB2, F, 0), __STM32_PIN(10, APB2, F, 0),
__STM32_PIN(11, APB2, F, 1), __STM32_PIN(11, APB2, F, 1),
__STM32_PIN(12, APB2, F, 2), __STM32_PIN(12, APB2, F, 2),
...@@ -472,7 +525,7 @@ const static struct rt_pin_ops _stm32_pin_ops = ...@@ -472,7 +525,7 @@ const static struct rt_pin_ops _stm32_pin_ops =
int stm32_hw_pin_init(void) int stm32_hw_pin_init(void)
{ {
int result; int result;
result = rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL); result = rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
return result; return result;
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode * 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode
* 2013-05-13 aozima update for kehong-lingtai. * 2013-05-13 aozima update for kehong-lingtai.
* 2015-01-31 armink make sure the serial transmit complete in putc() * 2015-01-31 armink make sure the serial transmit complete in putc()
* 2016-05-13 armink add DMA Rx mode
*/ */
#include "stm32f10x.h" #include "stm32f10x.h"
...@@ -44,10 +45,22 @@ ...@@ -44,10 +45,22 @@
/* STM32 uart driver */ /* STM32 uart driver */
struct stm32_uart struct stm32_uart
{ {
USART_TypeDef* uart_device; USART_TypeDef *uart_device;
IRQn_Type irq; 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) static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{ {
struct stm32_uart* uart; struct stm32_uart* uart;
...@@ -93,6 +106,7 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c ...@@ -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) static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
{ {
struct stm32_uart* uart; struct stm32_uart* uart;
rt_uint32_t ctrl_arg = (rt_uint32_t)(arg);
RT_ASSERT(serial != RT_NULL); RT_ASSERT(serial != RT_NULL);
uart = (struct stm32_uart *)serial->parent.user_data; 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 ...@@ -113,8 +127,13 @@ static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *ar
/* enable interrupt */ /* enable interrupt */
USART_ITConfig(uart->uart_device, USART_IT_RXNE, ENABLE); USART_ITConfig(uart->uart_device, USART_IT_RXNE, ENABLE);
break; break;
/* USART config */
case RT_DEVICE_CTRL_CONFIG :
if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX) {
DMA_Configuration(serial);
}
break;
} }
return RT_EOK; return RT_EOK;
} }
...@@ -148,6 +167,91 @@ static int stm32_getc(struct rt_serial_device *serial) ...@@ -148,6 +167,91 @@ static int stm32_getc(struct rt_serial_device *serial)
return ch; 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 = static const struct rt_uart_ops stm32_uart_ops =
{ {
stm32_configure, stm32_configure,
...@@ -162,70 +266,68 @@ struct stm32_uart uart1 = ...@@ -162,70 +266,68 @@ struct stm32_uart uart1 =
{ {
USART1, USART1,
USART1_IRQn, USART1_IRQn,
{
DMA1_Channel5,
DMA1_FLAG_GL5,
DMA1_Channel5_IRQn,
0,
},
}; };
struct rt_serial_device serial1; struct rt_serial_device serial1;
void USART1_IRQHandler(void) void USART1_IRQHandler(void)
{ {
struct stm32_uart* uart; /* enter interrupt */
rt_interrupt_enter();
uart = &uart1; uart_isr(&serial1);
/* leave interrupt */
rt_interrupt_leave();
}
void DMA1_Channel5_IRQHandler(void) {
/* enter interrupt */ /* enter interrupt */
rt_interrupt_enter(); 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) dma_rx_done_isr(&serial1);
{
/* clear interrupt */
USART_ClearITPendingBit(uart->uart_device, USART_IT_TC);
}
if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET)
{
stm32_getc(&serial1);
}
/* leave interrupt */ /* leave interrupt */
rt_interrupt_leave(); rt_interrupt_leave();
} }
#endif /* RT_USING_UART1 */ #endif /* RT_USING_UART1 */
#if defined(RT_USING_UART2) #if defined(RT_USING_UART2)
/* UART1 device driver structure */ /* UART2 device driver structure */
struct stm32_uart uart2 = struct stm32_uart uart2 =
{ {
USART2, USART2,
USART2_IRQn, USART2_IRQn,
{
DMA1_Channel6,
DMA1_FLAG_GL6,
DMA1_Channel6_IRQn,
0,
},
}; };
struct rt_serial_device serial2; struct rt_serial_device serial2;
void USART2_IRQHandler(void) void USART2_IRQHandler(void)
{ {
struct stm32_uart* uart; /* enter interrupt */
rt_interrupt_enter();
uart = &uart2; uart_isr(&serial2);
/* leave interrupt */
rt_interrupt_leave();
}
void DMA1_Channel6_IRQHandler(void) {
/* enter interrupt */ /* enter interrupt */
rt_interrupt_enter(); rt_interrupt_enter();
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
{ dma_rx_done_isr(&serial2);
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);
}
/* leave interrupt */ /* leave interrupt */
rt_interrupt_leave(); rt_interrupt_leave();
...@@ -238,32 +340,31 @@ struct stm32_uart uart3 = ...@@ -238,32 +340,31 @@ struct stm32_uart uart3 =
{ {
USART3, USART3,
USART3_IRQn, USART3_IRQn,
{
DMA1_Channel3,
DMA1_FLAG_GL3,
DMA1_Channel3_IRQn,
0,
},
}; };
struct rt_serial_device serial3; struct rt_serial_device serial3;
void USART3_IRQHandler(void) void USART3_IRQHandler(void)
{ {
struct stm32_uart* uart; /* enter interrupt */
rt_interrupt_enter();
uart = &uart3; uart_isr(&serial3);
/* leave interrupt */
rt_interrupt_leave();
}
void DMA1_Channel3_IRQHandler(void) {
/* enter interrupt */ /* enter interrupt */
rt_interrupt_enter(); rt_interrupt_enter();
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
{ dma_rx_done_isr(&serial3);
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);
}
/* leave interrupt */ /* leave interrupt */
rt_interrupt_leave(); rt_interrupt_leave();
...@@ -276,69 +377,66 @@ struct stm32_uart uart4 = ...@@ -276,69 +377,66 @@ struct stm32_uart uart4 =
{ {
UART4, UART4,
UART4_IRQn, UART4_IRQn,
{
DMA2_Channel3,
DMA2_FLAG_GL3,
DMA2_Channel3_IRQn,
0,
},
}; };
struct rt_serial_device serial4; struct rt_serial_device serial4;
void UART4_IRQHandler(void) void UART4_IRQHandler(void)
{ {
struct stm32_uart* uart; /* enter interrupt */
rt_interrupt_enter();
uart = &uart4; uart_isr(&serial4);
/* leave interrupt */
rt_interrupt_leave();
}
void DMA2_Channel3_IRQHandler(void) {
/* enter interrupt */ /* enter interrupt */
rt_interrupt_enter(); rt_interrupt_enter();
if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET)
{ dma_rx_done_isr(&serial4);
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);
}
/* leave interrupt */ /* leave interrupt */
rt_interrupt_leave(); rt_interrupt_leave();
} }
#endif /* RT_USING_UART3 */ #endif /* RT_USING_UART4 */
static void RCC_Configuration(void) static void RCC_Configuration(void)
{ {
#if defined(RT_USING_UART1) #if defined(RT_USING_UART1)
/* Enable UART GPIO clocks */ /* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */ /* Enable UART clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
#endif /* RT_USING_UART1 */ #endif /* RT_USING_UART1 */
#if defined(RT_USING_UART2) #if defined(RT_USING_UART2)
/* Enable UART GPIO clocks */ /* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */ /* Enable UART clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
#endif /* RT_USING_UART2 */ #endif /* RT_USING_UART2 */
#if defined(RT_USING_UART3) #if defined(RT_USING_UART3)
/* Enable UART GPIO clocks */ /* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */ /* Enable UART clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
#endif /* RT_USING_UART3 */ #endif /* RT_USING_UART3 */
#if defined(RT_USING_UART4) #if defined(RT_USING_UART4)
/* Enable UART GPIO clocks */ /* Enable UART GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
/* Enable UART clock */ /* Enable UART clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
#endif /* RT_USING_UART4 */ #endif /* RT_USING_UART4 */
} }
static void GPIO_Configuration(void) static void GPIO_Configuration(void)
...@@ -390,7 +488,6 @@ static void GPIO_Configuration(void) ...@@ -390,7 +488,6 @@ static void GPIO_Configuration(void)
GPIO_InitStructure.GPIO_Pin = UART4_GPIO_TX; GPIO_InitStructure.GPIO_Pin = UART4_GPIO_TX;
GPIO_Init(UART4_GPIO, &GPIO_InitStructure); GPIO_Init(UART4_GPIO, &GPIO_InitStructure);
#endif /* RT_USING_UART4 */ #endif /* RT_USING_UART4 */
} }
static void NVIC_Configuration(struct stm32_uart* uart) static void NVIC_Configuration(struct stm32_uart* uart)
...@@ -405,6 +502,46 @@ static void NVIC_Configuration(struct stm32_uart* uart) ...@@ -405,6 +502,46 @@ static void NVIC_Configuration(struct stm32_uart* uart)
NVIC_Init(&NVIC_InitStructure); 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) void rt_hw_usart_init(void)
{ {
struct stm32_uart* uart; struct stm32_uart* uart;
...@@ -420,11 +557,11 @@ void rt_hw_usart_init(void) ...@@ -420,11 +557,11 @@ void rt_hw_usart_init(void)
serial1.ops = &stm32_uart_ops; serial1.ops = &stm32_uart_ops;
serial1.config = config; serial1.config = config;
NVIC_Configuration(&uart1); NVIC_Configuration(uart);
/* register UART1 device */ /* register UART1 device */
rt_hw_serial_register(&serial1, "uart1", 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); uart);
#endif /* RT_USING_UART1 */ #endif /* RT_USING_UART1 */
...@@ -435,11 +572,11 @@ void rt_hw_usart_init(void) ...@@ -435,11 +572,11 @@ void rt_hw_usart_init(void)
serial2.ops = &stm32_uart_ops; serial2.ops = &stm32_uart_ops;
serial2.config = config; serial2.config = config;
NVIC_Configuration(&uart2); NVIC_Configuration(uart);
/* register UART1 device */ /* register UART2 device */
rt_hw_serial_register(&serial2, "uart2", 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); uart);
#endif /* RT_USING_UART2 */ #endif /* RT_USING_UART2 */
...@@ -451,11 +588,11 @@ void rt_hw_usart_init(void) ...@@ -451,11 +588,11 @@ void rt_hw_usart_init(void)
serial3.ops = &stm32_uart_ops; serial3.ops = &stm32_uart_ops;
serial3.config = config; serial3.config = config;
NVIC_Configuration(&uart3); NVIC_Configuration(uart);
/* register UART1 device */ /* register UART3 device */
rt_hw_serial_register(&serial3, "uart3", 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); uart);
#endif /* RT_USING_UART3 */ #endif /* RT_USING_UART3 */
...@@ -467,12 +604,11 @@ void rt_hw_usart_init(void) ...@@ -467,12 +604,11 @@ void rt_hw_usart_init(void)
serial4.ops = &stm32_uart_ops; serial4.ops = &stm32_uart_ops;
serial4.config = config; serial4.config = config;
NVIC_Configuration(&uart4); NVIC_Configuration(uart);
/* register UART4 device */ /* register UART4 device */
rt_hw_serial_register(&serial4, "uart4", 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); uart);
#endif /* RT_USING_UART4 */ #endif /* RT_USING_UART4 */
} }
...@@ -6,6 +6,6 @@ cwd = GetCurrentDir() ...@@ -6,6 +6,6 @@ cwd = GetCurrentDir()
src = Glob('*.c') src = Glob('*.c')
CPPPATH = [cwd] 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') Return('group')
/* /*
* File : dfs_lwip.c * File : dfs_net.c
* This file is part of RT-Thread RTOS * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -20,15 +20,16 @@ ...@@ -20,15 +20,16 @@
* Change Logs: * Change Logs:
* Date Author Notes * Date Author Notes
* 2015-02-17 Bernard First version * 2015-02-17 Bernard First version
* 2016-05-07 Bernard Rename dfs_lwip to dfs_net
*/ */
#include <rtthread.h> #include <rtthread.h>
#include <dfs.h> #include <dfs.h>
#include <dfs_fs.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; struct dfs_fd *_dfs_fd;
...@@ -40,12 +41,12 @@ int dfs_lwip_getsocket(int fd) ...@@ -40,12 +41,12 @@ int dfs_lwip_getsocket(int fd)
return (int)_dfs_fd->data; 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; 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; int sock;
...@@ -55,7 +56,7 @@ int dfs_lwip_read(struct dfs_fd* file, void *buf, rt_size_t count) ...@@ -55,7 +56,7 @@ int dfs_lwip_read(struct dfs_fd* file, void *buf, rt_size_t count)
return 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; int sock;
...@@ -65,7 +66,7 @@ int dfs_lwip_write(struct dfs_fd *file, const void *buf, rt_size_t count) ...@@ -65,7 +66,7 @@ int dfs_lwip_write(struct dfs_fd *file, const void *buf, rt_size_t count)
return count; return count;
} }
int dfs_lwip_close(struct dfs_fd* file) int dfs_net_close(struct dfs_fd* file)
{ {
int sock; int sock;
int result; int result;
...@@ -78,9 +79,9 @@ int dfs_lwip_close(struct dfs_fd* file) ...@@ -78,9 +79,9 @@ int dfs_lwip_close(struct dfs_fd* file)
return -result; 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, DFS_FS_FLAG_DEFAULT,
RT_NULL, /* mount */ RT_NULL, /* mount */
RT_NULL, /* unmont */ RT_NULL, /* unmont */
...@@ -88,10 +89,10 @@ static const struct dfs_filesystem_operation _lwip_fs_ops = ...@@ -88,10 +89,10 @@ static const struct dfs_filesystem_operation _lwip_fs_ops =
RT_NULL, /* statfs */ RT_NULL, /* statfs */
RT_NULL, /* open */ RT_NULL, /* open */
dfs_lwip_close, dfs_net_close,
dfs_lwip_ioctl, dfs_net_ioctl,
dfs_lwip_read, dfs_net_read,
dfs_lwip_write, dfs_net_write,
RT_NULL, RT_NULL,
RT_NULL, /* lseek */ RT_NULL, /* lseek */
RT_NULL, /* getdents */ RT_NULL, /* getdents */
...@@ -100,28 +101,28 @@ static const struct dfs_filesystem_operation _lwip_fs_ops = ...@@ -100,28 +101,28 @@ static const struct dfs_filesystem_operation _lwip_fs_ops =
RT_NULL, /* rename */ RT_NULL, /* rename */
}; };
static struct dfs_filesystem _lwip_fs = static struct dfs_filesystem _net_fs =
{ {
0, /* dev_id */ 0, /* dev_id */
RT_NULL, /* path */ RT_NULL, /* path */
&_lwip_fs_ops, &_net_fs_ops,
RT_NULL /* data */ 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 NOTE: Beause we don't need to mount lwIP file system, the filesystem_ops is not
registered to the system. 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; return 0;
} }
INIT_FS_EXPORT(dfs_lwip_system_init); INIT_FS_EXPORT(dfs_net_system_init);
*/ */
/* /*
* File : dfs_lwip.h * File : dfs_net.h
* This file is part of RT-Thread RTOS * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -20,10 +20,11 @@ ...@@ -20,10 +20,11 @@
* Change Logs: * Change Logs:
* Date Author Notes * Date Author Notes
* 2015-02-17 Bernard First version * 2015-02-17 Bernard First version
* 2016-05-05 Bernard rename dfs_lwip to dfs_net.
*/ */
#ifndef DFS_LWIP_H__ #ifndef DFS_NET_H__
#define DFS_LWIP_H__ #define DFS_NET_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
...@@ -31,10 +32,10 @@ extern "C" { ...@@ -31,10 +32,10 @@ extern "C" {
#include <lwip/sockets.h> #include <lwip/sockets.h>
struct dfs_filesystem* dfs_lwip_get_fs(void); struct dfs_filesystem* dfs_net_get_fs(void);
int dfs_lwip_getsocket(int fd); int dfs_net_getsocket(int fd);
int dfs_lwip_system_init(void); int dfs_net_system_init(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifdef RT_USING_LWIP #ifdef RT_USING_LWIP
#include "dfs_lwip.h" #include "dfs_net.h"
int int
select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, 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, ...@@ -48,7 +48,7 @@ select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
for (index = 0; index < maxfdp1; index ++) for (index = 0; index < maxfdp1; index ++)
{ {
/* convert fd to sock */ /* convert fd to sock */
sock = dfs_lwip_getsocket(index); sock = dfs_net_getsocket(index);
if (sock == -1) continue; if (sock == -1) continue;
if (sock > maxfd) maxfd = sock; if (sock > maxfd) maxfd = sock;
......
...@@ -28,12 +28,12 @@ ...@@ -28,12 +28,12 @@
#include <sys/socket.h> #include <sys/socket.h>
#include "dfs_lwip.h" #include "dfs_net.h"
int accept(int s, struct sockaddr *addr, socklen_t *addrlen) int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{ {
int new_client = -1; int new_client = -1;
int sock = dfs_lwip_getsocket(s); int sock = dfs_net_getsocket(s);
new_client = lwip_accept(sock, addr, addrlen); new_client = lwip_accept(sock, addr, addrlen);
if (new_client != -1) if (new_client != -1)
...@@ -58,7 +58,7 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen) ...@@ -58,7 +58,7 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
d->type = FT_SOCKET; d->type = FT_SOCKET;
d->path = RT_NULL; 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->flags = DFS_O_RDWR; /* set flags as read and write */
d->size = 0; d->size = 0;
...@@ -79,7 +79,7 @@ RTM_EXPORT(accept); ...@@ -79,7 +79,7 @@ RTM_EXPORT(accept);
int bind(int s, const struct sockaddr *name, socklen_t namelen) 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); return lwip_bind(sock, name, namelen);
} }
...@@ -98,7 +98,7 @@ int shutdown(int s, int how) ...@@ -98,7 +98,7 @@ int shutdown(int s, int how)
return -1; return -1;
} }
sock = dfs_lwip_getsocket(s); sock = dfs_net_getsocket(s);
if (lwip_shutdown(sock, how) == 0) if (lwip_shutdown(sock, how) == 0)
{ {
/* socket has been closed, delete it from file system fd */ /* socket has been closed, delete it from file system fd */
...@@ -114,7 +114,7 @@ RTM_EXPORT(shutdown); ...@@ -114,7 +114,7 @@ RTM_EXPORT(shutdown);
int getpeername(int s, struct sockaddr *name, socklen_t *namelen) 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); return lwip_getpeername(sock, name, namelen);
} }
...@@ -122,7 +122,7 @@ RTM_EXPORT(getpeername); ...@@ -122,7 +122,7 @@ RTM_EXPORT(getpeername);
int getsockname(int s, struct sockaddr *name, socklen_t *namelen) 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); return lwip_getsockname(sock, name, namelen);
} }
...@@ -130,7 +130,7 @@ RTM_EXPORT(getsockname); ...@@ -130,7 +130,7 @@ RTM_EXPORT(getsockname);
int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) 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); return lwip_getsockopt(sock, level, optname, optval, optlen);
} }
...@@ -138,7 +138,7 @@ RTM_EXPORT(getsockopt); ...@@ -138,7 +138,7 @@ RTM_EXPORT(getsockopt);
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) 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); return lwip_setsockopt(sock, level, optname, optval, optlen);
} }
...@@ -146,7 +146,7 @@ RTM_EXPORT(setsockopt); ...@@ -146,7 +146,7 @@ RTM_EXPORT(setsockopt);
int connect(int s, const struct sockaddr *name, socklen_t namelen) 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); return lwip_connect(sock, name, namelen);
} }
...@@ -154,7 +154,7 @@ RTM_EXPORT(connect); ...@@ -154,7 +154,7 @@ RTM_EXPORT(connect);
int listen(int s, int backlog) int listen(int s, int backlog)
{ {
int sock = dfs_lwip_getsocket(s); int sock = dfs_net_getsocket(s);
return lwip_listen(sock, backlog); return lwip_listen(sock, backlog);
} }
...@@ -162,7 +162,7 @@ RTM_EXPORT(listen); ...@@ -162,7 +162,7 @@ RTM_EXPORT(listen);
int recv(int s, void *mem, size_t len, int flags) 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); return lwip_recv(sock, mem, len, flags);
} }
...@@ -171,7 +171,7 @@ RTM_EXPORT(recv); ...@@ -171,7 +171,7 @@ RTM_EXPORT(recv);
int recvfrom(int s, void *mem, size_t len, int flags, int recvfrom(int s, void *mem, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen) 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); return lwip_recvfrom(sock, mem, len, flags, from, fromlen);
} }
...@@ -179,7 +179,7 @@ RTM_EXPORT(recvfrom); ...@@ -179,7 +179,7 @@ RTM_EXPORT(recvfrom);
int send(int s, const void *dataptr, size_t size, int flags) 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); return lwip_send(sock, dataptr, size, flags);
} }
...@@ -188,7 +188,7 @@ RTM_EXPORT(send); ...@@ -188,7 +188,7 @@ RTM_EXPORT(send);
int sendto(int s, const void *dataptr, size_t size, int flags, int sendto(int s, const void *dataptr, size_t size, int flags,
const struct sockaddr *to, socklen_t tolen) 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); return lwip_sendto(sock, dataptr, size, flags, to, tolen);
} }
...@@ -219,7 +219,7 @@ int socket(int domain, int type, int protocol) ...@@ -219,7 +219,7 @@ int socket(int domain, int type, int protocol)
d->type = FT_SOCKET; d->type = FT_SOCKET;
d->path = RT_NULL; 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->flags = DFS_O_RDWR; /* set flags as read and write */
d->size = 0; d->size = 0;
......
...@@ -220,6 +220,10 @@ rt_inline rt_uint32_t fls(rt_uint32_t val) ...@@ -220,6 +220,10 @@ rt_inline rt_uint32_t fls(rt_uint32_t val)
return bit; 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_lock(struct rt_mmcsd_host *host);
void mmcsd_host_unlock(struct rt_mmcsd_host *host); void mmcsd_host_unlock(struct rt_mmcsd_host *host);
void mmcsd_req_complete(struct rt_mmcsd_host *host); void mmcsd_req_complete(struct rt_mmcsd_host *host);
......
...@@ -33,12 +33,15 @@ ...@@ -33,12 +33,15 @@
#define BAUD_RATE_2400 2400 #define BAUD_RATE_2400 2400
#define BAUD_RATE_4800 4800 #define BAUD_RATE_4800 4800
#define BAUD_RATE_9600 9600 #define BAUD_RATE_9600 9600
#define BAUD_RATE_19200 19200
#define BAUD_RATE_38400 38400 #define BAUD_RATE_38400 38400
#define BAUD_RATE_57600 57600 #define BAUD_RATE_57600 57600
#define BAUD_RATE_115200 115200 #define BAUD_RATE_115200 115200
#define BAUD_RATE_230400 230400 #define BAUD_RATE_230400 230400
#define BAUD_RATE_460800 460800 #define BAUD_RATE_460800 460800
#define BAUD_RATE_921600 921600 #define BAUD_RATE_921600 921600
#define BAUD_RATE_2000000 2000000
#define BAUD_RATE_3000000 3000000
#define DATA_BITS_5 5 #define DATA_BITS_5 5
#define DATA_BITS_6 6 #define DATA_BITS_6 6
...@@ -106,7 +109,7 @@ struct serial_configure ...@@ -106,7 +109,7 @@ struct serial_configure
rt_uint32_t parity :2; rt_uint32_t parity :2;
rt_uint32_t bit_order :1; rt_uint32_t bit_order :1;
rt_uint32_t invert :1; rt_uint32_t invert :1;
rt_uint32_t bufsz :16; rt_uint32_t bufsz :16;
rt_uint32_t reserved :4; rt_uint32_t reserved :4;
}; };
...@@ -115,15 +118,15 @@ struct serial_configure ...@@ -115,15 +118,15 @@ struct serial_configure
*/ */
struct rt_serial_rx_fifo struct rt_serial_rx_fifo
{ {
/* software fifo */ /* software fifo */
rt_uint8_t *buffer; 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_serial_tx_fifo
{ {
struct rt_completion completion; struct rt_completion completion;
}; };
/* /*
...@@ -131,13 +134,13 @@ struct rt_serial_tx_fifo ...@@ -131,13 +134,13 @@ struct rt_serial_tx_fifo
*/ */
struct rt_serial_rx_dma struct rt_serial_rx_dma
{ {
rt_bool_t activated; rt_bool_t activated;
}; };
struct rt_serial_tx_dma struct rt_serial_tx_dma
{ {
rt_bool_t activated; rt_bool_t activated;
struct rt_data_queue data_queue; struct rt_data_queue data_queue;
}; };
struct rt_serial_device struct rt_serial_device
...@@ -147,8 +150,8 @@ struct rt_serial_device ...@@ -147,8 +150,8 @@ struct rt_serial_device
const struct rt_uart_ops *ops; const struct rt_uart_ops *ops;
struct serial_configure config; struct serial_configure config;
void *serial_rx; void *serial_rx;
void *serial_tx; void *serial_tx;
}; };
typedef struct rt_serial_device rt_serial_t; typedef struct rt_serial_device rt_serial_t;
...@@ -163,7 +166,7 @@ struct rt_uart_ops ...@@ -163,7 +166,7 @@ struct rt_uart_ops
int (*putc)(struct rt_serial_device *serial, char c); int (*putc)(struct rt_serial_device *serial, char c);
int (*getc)(struct rt_serial_device *serial); 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); 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, ...@@ -174,4 +177,3 @@ rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
void *data); void *data);
#endif #endif
...@@ -44,6 +44,8 @@ static struct rt_thread mmcsd_detect_thread; ...@@ -44,6 +44,8 @@ static struct rt_thread mmcsd_detect_thread;
static rt_uint8_t mmcsd_stack[RT_MMCSD_STACK_SIZE]; static rt_uint8_t mmcsd_stack[RT_MMCSD_STACK_SIZE];
static struct rt_mailbox mmcsd_detect_mb; static struct rt_mailbox mmcsd_detect_mb;
static rt_uint32_t mmcsd_detect_mb_pool[4]; 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) void mmcsd_host_lock(struct rt_mmcsd_host *host)
{ {
...@@ -594,6 +596,24 @@ static void mmcsd_power_off(struct rt_mmcsd_host *host) ...@@ -594,6 +596,24 @@ static void mmcsd_power_off(struct rt_mmcsd_host *host)
mmcsd_set_iocfg(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) void mmcsd_change(struct rt_mmcsd_host *host)
{ {
rt_mb_send(&mmcsd_detect_mb, (rt_uint32_t)host); rt_mb_send(&mmcsd_detect_mb, (rt_uint32_t)host);
...@@ -647,6 +667,7 @@ void mmcsd_detect(void *param) ...@@ -647,6 +667,7 @@ void mmcsd_detect(void *param)
if (init_mmc(host, ocr)) if (init_mmc(host, ocr))
mmcsd_power_off(host); mmcsd_power_off(host);
mmcsd_host_unlock(host); mmcsd_host_unlock(host);
rt_mb_send(&mmcsd_hotpluge_mb, (rt_uint32_t)host);
continue; continue;
} }
mmcsd_host_unlock(host); mmcsd_host_unlock(host);
...@@ -667,6 +688,7 @@ void mmcsd_detect(void *param) ...@@ -667,6 +688,7 @@ void mmcsd_detect(void *param)
host->card = RT_NULL; host->card = RT_NULL;
} }
mmcsd_host_unlock(host); mmcsd_host_unlock(host);
rt_mb_send(&mmcsd_hotpluge_mb, (rt_uint32_t)host);
} }
} }
} }
...@@ -711,11 +733,15 @@ void rt_mmcsd_core_init(void) ...@@ -711,11 +733,15 @@ void rt_mmcsd_core_init(void)
/* initialize detect SD cart thread */ /* initialize detect SD cart thread */
/* initialize mailbox and create detect SD card thread */ /* initialize mailbox and create detect SD card thread */
ret = rt_mb_init(&mmcsd_detect_mb, "mmcsdmb", 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_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK); 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); &mmcsd_stack[0], RT_MMCSD_STACK_SIZE, RT_MMCSD_THREAD_PREORITY, 20);
if (ret == RT_EOK) if (ret == RT_EOK)
{ {
......
...@@ -27,9 +27,10 @@ ...@@ -27,9 +27,10 @@
* the size of ring buffer. * the size of ring buffer.
* 2014-07-10 bernard rewrite serial framework * 2014-07-10 bernard rewrite serial framework
* 2014-12-31 bernard use open_flag for poll_tx stream mode. * 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. * in open function.
* 2015-11-10 bernard fix the poll rx issue when there is no data. * 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> #include <rthw.h>
...@@ -37,13 +38,13 @@ ...@@ -37,13 +38,13 @@
#include <rtdevice.h> #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) rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
{ {
int ch; int ch;
int size; int size;
RT_ASSERT(serial != RT_NULL); RT_ASSERT(serial != RT_NULL);
size = length; size = length;
...@@ -52,7 +53,7 @@ rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, ...@@ -52,7 +53,7 @@ rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data,
ch = serial->ops->getc(serial); ch = serial->ops->getc(serial);
if (ch == -1) break; if (ch == -1) break;
*data = ch; *data = ch;
data ++; length --; data ++; length --;
if (ch == '\n') break; if (ch == '\n') break;
...@@ -77,9 +78,9 @@ rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t ...@@ -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, '\r');
} }
serial->ops->putc(serial, *data); serial->ops->putc(serial, *data);
++ data; ++ data;
-- length; -- length;
} }
...@@ -96,8 +97,8 @@ rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data, ...@@ -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; struct rt_serial_rx_fifo* rx_fifo;
RT_ASSERT(serial != RT_NULL); RT_ASSERT(serial != RT_NULL);
size = length; size = length;
rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx; rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;
RT_ASSERT(rx_fifo != RT_NULL); 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 * ...@@ -136,7 +137,7 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
{ {
int size; int size;
struct rt_serial_tx_fifo *tx; struct rt_serial_tx_fifo *tx;
RT_ASSERT(serial != RT_NULL); RT_ASSERT(serial != RT_NULL);
size = length; size = length;
...@@ -157,32 +158,136 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t * ...@@ -157,32 +158,136 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *
return size - length; 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 * Serial DMA routines
*/ */
rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length) rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
{ {
rt_base_t level; rt_base_t level;
int result = RT_EOK;
struct rt_serial_rx_dma *rx_dma;
RT_ASSERT((serial != RT_NULL) && (data != RT_NULL)); 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(); 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);
}
else result = -RT_EBUSY;
rt_hw_interrupt_enable(level);
if (result == RT_EOK) return length; 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);
rt_set_errno(result); if (length < fifo_recved_len) {
return 0; 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;
}
} }
rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) 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 * ...@@ -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; struct rt_serial_tx_dma *tx_dma;
tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx); 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) if (result == RT_EOK)
{ {
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
...@@ -203,7 +308,7 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t * ...@@ -203,7 +308,7 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
/* make a DMA transfer */ /* 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 else
{ {
...@@ -250,7 +355,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) ...@@ -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; serial = (struct rt_serial_device *)dev;
/* check device flag with the open flag */ /* 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; return -RT_EIO;
if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX)) if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX))
return -RT_EIO; return -RT_EIO;
...@@ -261,26 +366,41 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) ...@@ -261,26 +366,41 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)
/* get open flags */ /* get open flags */
dev->open_flag = oflag & 0xff; dev->open_flag = oflag & 0xff;
/* initialize the Rx/Tx structure according to open flag */ /* initialize the Rx/Tx structure according to open flag */
if (serial->serial_rx == RT_NULL) if (serial->serial_rx == RT_NULL)
{ {
if (oflag & RT_DEVICE_FLAG_DMA_RX) 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 = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma));
rx_dma->activated = RT_FALSE; 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; dev->open_flag |= RT_DEVICE_FLAG_DMA_RX;
} }
else if (oflag & RT_DEVICE_FLAG_INT_RX) else if (oflag & RT_DEVICE_FLAG_INT_RX)
{ {
struct rt_serial_rx_fifo* rx_fifo; 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); serial->config.bufsz);
RT_ASSERT(rx_fifo != RT_NULL); RT_ASSERT(rx_fifo != RT_NULL);
rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1); 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) ...@@ -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)); tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma));
RT_ASSERT(tx_dma != RT_NULL); RT_ASSERT(tx_dma != RT_NULL);
tx_dma->activated = RT_FALSE; tx_dma->activated = RT_FALSE;
rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL); rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL);
serial->serial_tx = tx_dma; serial->serial_tx = tx_dma;
...@@ -346,7 +466,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev) ...@@ -346,7 +466,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
/* this device has more reference count */ /* this device has more reference count */
if (dev->ref_count > 1) return RT_EOK; if (dev->ref_count > 1) return RT_EOK;
if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
{ {
struct rt_serial_rx_fifo* rx_fifo; struct rt_serial_rx_fifo* rx_fifo;
...@@ -362,12 +482,23 @@ static rt_err_t rt_serial_close(struct rt_device *dev) ...@@ -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) 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; rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
RT_ASSERT(rx_dma != RT_NULL); RT_ASSERT(rx_dma != RT_NULL);
rt_free(rx_dma);
} else {
struct rt_serial_rx_fifo* rx_fifo;
rt_free(rx_dma); 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; serial->serial_rx = RT_NULL;
dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX; dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX;
} }
...@@ -376,7 +507,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev) ...@@ -376,7 +507,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev)
{ {
struct rt_serial_tx_fifo* tx_fifo; 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_ASSERT(tx_fifo != RT_NULL);
rt_free(tx_fifo); rt_free(tx_fifo);
...@@ -534,30 +665,30 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) ...@@ -534,30 +665,30 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
ch = serial->ops->getc(serial); ch = serial->ops->getc(serial);
if (ch == -1) break; if (ch == -1) break;
/* disable interrupt */ /* disable interrupt */
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
rx_fifo->buffer[rx_fifo->put_index] = ch; rx_fifo->buffer[rx_fifo->put_index] = ch;
rx_fifo->put_index += 1; rx_fifo->put_index += 1;
if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0; 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 the next position is read index, discard this 'read char' */
if (rx_fifo->put_index == rx_fifo->get_index) if (rx_fifo->put_index == rx_fifo->get_index)
{ {
rx_fifo->get_index += 1; rx_fifo->get_index += 1;
if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
} }
/* enable interrupt */ /* enable interrupt */
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
} }
/* invoke callback */ /* invoke callback */
if (serial->parent.rx_indicate != RT_NULL) if (serial->parent.rx_indicate != RT_NULL)
{ {
rt_size_t rx_length; rt_size_t rx_length;
/* get rx length */ /* get rx length */
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index): 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) ...@@ -584,19 +715,19 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
struct rt_serial_tx_dma* tx_dma; struct rt_serial_tx_dma* tx_dma;
tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx; tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0); 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) if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK)
{ {
/* transmit next data node */ /* transmit next data node */
tx_dma->activated = RT_TRUE; 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 else
{ {
tx_dma->activated = RT_FALSE; tx_dma->activated = RT_FALSE;
} }
/* invoke callback */ /* invoke callback */
if (serial->parent.tx_complete != RT_NULL) if (serial->parent.tx_complete != RT_NULL)
{ {
...@@ -607,13 +738,27 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) ...@@ -607,13 +738,27 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
case RT_SERIAL_EVENT_RX_DMADONE: case RT_SERIAL_EVENT_RX_DMADONE:
{ {
int length; int length;
struct rt_serial_rx_dma* rx_dma;
rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
/* get DMA rx length */ /* get DMA rx length */
length = (event & (~0xff)) >> 8; 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; break;
} }
} }
......
...@@ -21,6 +21,9 @@ if GetDepend('RT_USING_AT45DBXX'): ...@@ -21,6 +21,9 @@ if GetDepend('RT_USING_AT45DBXX'):
if GetDepend('RT_USING_SST25VFXX'): if GetDepend('RT_USING_SST25VFXX'):
src_device += ['spi_flash_sst25vfxx.c'] src_device += ['spi_flash_sst25vfxx.c']
if GetDepend('RT_USING_GD'):
src_device += ['spi_flash_gd.c']
src += src_device src += src_device
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH) group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH)
......
...@@ -675,7 +675,7 @@ static struct pbuf *enc28j60_rx(rt_device_t dev) ...@@ -675,7 +675,7 @@ static struct pbuf *enc28j60_rx(rt_device_t dev)
else else
{ {
/* allocation pbuf */ /* allocation pbuf */
p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM); p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
if (p != RT_NULL) if (p != RT_NULL)
{ {
struct pbuf* q; struct pbuf* q;
......
/*
* 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
/* /*
* File : rtdef.h * File : spi_flash_at45dbxx.c
* This file is part of RT-Thread RTOS * This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
* *
* The license and distribution terms for this file may be * This program is free software; you can redistribute it and/or modify
* found in the file LICENSE in this distribution or at * it under the terms of the GNU General Public License as published by
* http://www.rt-thread.org/license/LICENSE * 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: * Change Logs:
* Date Author Notes * Date Author Notes
......
/*
* 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 #ifndef SPI_FLASH_AT45DBXX_H_INCLUDED
#define SPI_FLASH_AT45DBXX_H_INCLUDED #define SPI_FLASH_AT45DBXX_H_INCLUDED
......
/*
* 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;
}
/*
* 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_ */
/* /*
* File : rtdef.h * File : spi_flash_sst25vfxx.c
* This file is part of RT-Thread RTOS * This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
* *
* The license and distribution terms for this file may be * This program is free software; you can redistribute it and/or modify
* found in the file LICENSE in this distribution or at * it under the terms of the GNU General Public License as published by
* http://www.rt-thread.org/license/LICENSE * 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: * Change Logs:
* Date Author Notes * Date Author Notes
......
/* /*
* File : rtdef.h * File : spi_flash_sst25vxx.h
* This file is part of RT-Thread RTOS * This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
* *
* The license and distribution terms for this file may be * This program is free software; you can redistribute it and/or modify
* found in the file LICENSE in this distribution or at * it under the terms of the GNU General Public License as published by
* http://www.rt-thread.org/license/LICENSE * 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: * Change Logs:
* Date Author Notes * Date Author Notes
......
...@@ -3,9 +3,19 @@ ...@@ -3,9 +3,19 @@
* This file is part of RT-Thread RTOS * This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
* *
* The license and distribution terms for this file may be * This program is free software; you can redistribute it and/or modify
* found in the file LICENSE in this distribution or at * it under the terms of the GNU General Public License as published by
* http://www.rt-thread.org/license/LICENSE * 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: * Change Logs:
* Date Author Notes * Date Author Notes
...@@ -13,10 +23,12 @@ ...@@ -13,10 +23,12 @@
* 2012-05-06 aozima can page write. * 2012-05-06 aozima can page write.
* 2012-08-23 aozima add flash lock. * 2012-08-23 aozima add flash lock.
* 2012-08-24 aozima fixed write status register BUG. * 2012-08-24 aozima fixed write status register BUG.
* 2015-05-13 bernard add GD25Q flash ID.
*/ */
#include <stdint.h> #include <stdint.h>
#include <rtdevice.h>
#include "spi_flash.h"
#include "spi_flash_w25qxx.h" #include "spi_flash_w25qxx.h"
#define FLASH_DEBUG #define FLASH_DEBUG
...@@ -31,7 +43,6 @@ ...@@ -31,7 +43,6 @@
/* JEDEC Manufacturer��s ID */ /* JEDEC Manufacturer��s ID */
#define MF_ID (0xEF) #define MF_ID (0xEF)
#define GD_ID (0xC8)
/* JEDEC Device ID: Memory type and Capacity */ /* JEDEC Device ID: Memory type and Capacity */
#define MTC_W25Q80_BV (0x4014) /* W25Q80BV */ #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 ...@@ -301,7 +312,7 @@ rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_nam
flash_unlock(&spi_flash_device); 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("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]); FLASH_TRACE("JEDEC Read-ID Data : %02X %02X %02X\r\n", id_recv[0], id_recv[1], id_recv[2]);
......
...@@ -3,9 +3,19 @@ ...@@ -3,9 +3,19 @@
* This file is part of RT-Thread RTOS * This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
* *
* The license and distribution terms for this file may be * This program is free software; you can redistribute it and/or modify
* found in the file LICENSE in this distribution or at * it under the terms of the GNU General Public License as published by
* http://www.rt-thread.org/license/LICENSE * 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: * Change Logs:
* Date Author Notes * Date Author Notes
...@@ -17,18 +27,8 @@ ...@@ -17,18 +27,8 @@
#define SPI_FLASH_W25QXX_H_INCLUDED #define SPI_FLASH_W25QXX_H_INCLUDED
#include <rtthread.h> #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, extern rt_err_t w25qxx_init(const char * flash_device_name,
const char * spi_device_name); const char * spi_device_name);
#endif // SPI_FLASH_W25QXX_H_INCLUDED #endif // SPI_FLASH_W25QXX_H_INCLUDED
Import('RTT_ROOT')
Import('rtconfig')
from building import * from building import *
import os import os
CAIRO_VERSION = '1.10.2' CAIRO_VERSION = '1.10.2'
CAIRO_PATH = 'cairo-' + CAIRO_VERSION CAIRO_PATH = 'cairo-' + CAIRO_VERSION
cwd = GetCurrentDir()
if GetDepend('RT_USING_CAIRO') and not os.path.exists(CAIRO_PATH): if GetDepend('RT_USING_CAIRO') and not os.path.exists(CAIRO_PATH):
print '================ERROR============================' print '================ERROR============================'
...@@ -99,7 +97,7 @@ cairo.c ...@@ -99,7 +97,7 @@ cairo.c
for item in range(len(src)): for item in range(len(src)):
src[item] = CAIRO_PATH + '/src/' + src[item] 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) group = DefineGroup('cairo', src, depend = ['RT_USING_CAIRO', 'RT_USING_NEWLIB', 'RTGUI_IMAGE_PNG', 'RT_USING_PTHREADS'], CPPPATH = CPPPATH)
Return('group') Return('group')
Import('RTT_ROOT')
Import('rtconfig')
from building import * from building import *
cwd = GetCurrentDir()
src = Split(''' src = Split('''
minilzo.c minilzo.c
lzo.c lzo.c
''') ''')
CPPPATH = [RTT_ROOT + '/components/external/lzo'] CPPPATH = [cwd]
group = DefineGroup('lzo', src, depend = ['RT_USING_LZO'], CPPPATH = CPPPATH) group = DefineGroup('lzo', src, depend = ['RT_USING_LZO'], CPPPATH = CPPPATH)
......
Import('RTT_ROOT')
Import('rtconfig')
from building import * from building import *
cwd = GetCurrentDir()
src = Split(''' src = Split('''
pb_common.c pb_common.c
pb_decode.c pb_decode.c
pb_encode.c pb_encode.c
''') ''')
CPPPATH = [RTT_ROOT + '/components/external/nanopb'] CPPPATH = [cwd]
group = DefineGroup('Nanopb', src, depend = ['RT_USING_NANOPB'], CPPPATH = CPPPATH) group = DefineGroup('Nanopb', src, depend = ['RT_USING_NANOPB'], CPPPATH = CPPPATH)
......
...@@ -17,4 +17,7 @@ else: ...@@ -17,4 +17,7 @@ else:
if rtconfig.PLATFORM == 'gcc' and rtconfig.ARCH != 'sim': if rtconfig.PLATFORM == 'gcc' and rtconfig.ARCH != 'sim':
objs = objs + SConscript('minilibc/SConscript') objs = objs + SConscript('minilibc/SConscript')
objs = objs + SConscript('pthreads/SConscript')
objs = objs + SConscript('libdl/SConscript')
Return('objs') Return('objs')
Import('RTT_ROOT')
Import('rtconfig')
from building import * from building import *
src = Glob('*.c') 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) group = DefineGroup('libdl', src, depend = ['RT_USING_MODULE', 'RT_USING_LIBDL'], CPPPATH = CPPPATH)
Return('group') Return('group')
...@@ -447,3 +447,18 @@ void __libc_init_array(void) ...@@ -447,3 +447,18 @@ void __libc_init_array(void)
{ {
/* we not use __libc init_aray to initialize C++ objects */ /* 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);
}
Import('RTT_ROOT')
from building import * from building import *
cwd = GetCurrentDir()
src = Glob('*.c') src = Glob('*.c')
CPPPATH = [RTT_ROOT + '/components/pthreads'] CPPPATH = [cwd]
group = DefineGroup('pthreads', src, depend = ['RT_USING_PTHREADS', 'RT_USING_LIBC'], CPPPATH = CPPPATH) group = DefineGroup('pthreads', src, depend = ['RT_USING_PTHREADS', 'RT_USING_LIBC'], CPPPATH = CPPPATH)
Return('group') Return('group')
...@@ -142,6 +142,20 @@ typedef struct pthread_barrier pthread_barrier_t; ...@@ -142,6 +142,20 @@ typedef struct pthread_barrier pthread_barrier_t;
/* pthread thread interface */ /* pthread thread interface */
int pthread_attr_destroy(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_init(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_system_init(void);
int pthread_create (pthread_t *tid, const pthread_attr_t *attr, int pthread_create (pthread_t *tid, const pthread_attr_t *attr,
......
...@@ -4,14 +4,15 @@ Import('RTT_ROOT') ...@@ -4,14 +4,15 @@ Import('RTT_ROOT')
from building import * from building import *
objs = [] 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 # 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'): if not GetDepend('RT_USING_LWIP132') and not GetDepend('RT_USING_LWIP140') and not GetDepend('RT_USING_LWIP_HEAD'):
AddDepend('RT_USING_LWIP141') AddDepend('RT_USING_LWIP141')
for d in list: 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')): if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript')) objs = objs + SConscript(os.path.join(d, 'SConscript'))
......
...@@ -76,7 +76,7 @@ typedef rt_uint32_t mem_ptr_t; ...@@ -76,7 +76,7 @@ typedef rt_uint32_t mem_ptr_t;
#define LWIP_TIMEVAL_PRIVATE 1 #define LWIP_TIMEVAL_PRIVATE 1
#endif #endif
#if defined(RT_USING_DFS_LWIP) #if defined(RT_USING_DFS_NET)
#define LWIP_COMPAT_SOCKETS 0 #define LWIP_COMPAT_SOCKETS 0
#endif #endif
......
...@@ -1248,6 +1248,12 @@ tcp_rexmit_rto(struct tcp_pcb *pcb) ...@@ -1248,6 +1248,12 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
/* concatenate unsent queue after unacked queue */ /* concatenate unsent queue after unacked queue */
seg->next = pcb->unsent; 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) */ /* unsent queue is the concatenated queue (of unacked, unsent) */
pcb->unsent = pcb->unacked; pcb->unsent = pcb->unacked;
/* unacked queue is now empty */ /* unacked queue is now empty */
......
...@@ -139,6 +139,7 @@ PACK_STRUCT_END ...@@ -139,6 +139,7 @@ PACK_STRUCT_END
#define ETHTYPE_VLAN 0x8100U #define ETHTYPE_VLAN 0x8100U
#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */ #define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */
#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session 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 /** 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. */ * or known to be 32-bit aligned within the protocol header. */
......
...@@ -38,10 +38,6 @@ ...@@ -38,10 +38,6 @@
#define LWIP_PLATFORM_BYTESWAP 0 #define LWIP_PLATFORM_BYTESWAP 0
#define BYTE_ORDER LITTLE_ENDIAN #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 */ /* #define RT_LWIP_DEBUG */
#ifdef RT_LWIP_DEBUG #ifdef RT_LWIP_DEBUG
...@@ -355,5 +351,62 @@ ...@@ -355,5 +351,62 @@
#include <stdlib.h> #include <stdlib.h>
#define LWIP_RAND rand #define LWIP_RAND rand
#endif #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__ */ #endif /* __LWIPOPTS_H__ */
此差异已折叠。
/*
* 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>
*
*/
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
See also the FILES file in each subdirectory.
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>
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')
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
Import('RTT_ROOT')
from building import *
src = Glob('*.c')
group = DefineGroup('netutils', src, depend = ['RT_USING_NETUTILS'])
Return('group')
#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
此差异已折叠。
/**
* @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
/*
* 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
/**
* @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( &timestamp, (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);
}
#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
#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);
#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
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.
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
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.
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册