937 lines
27 KiB
C
937 lines
27 KiB
C
|
/*============================================================================
|
||
|
Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
|
||
|
Quectel Wireless Solution Proprietary and Confidential.
|
||
|
=============================================================================*/
|
||
|
/*===========================================================================
|
||
|
|
||
|
EDIT HISTORY FOR MODULE
|
||
|
|
||
|
This section contains comments describing changes made to the module.
|
||
|
Notice that changes are listed in reverse chronological order.
|
||
|
|
||
|
|
||
|
WHEN WHO WHAT, WHERE, WHY
|
||
|
---------- ------------ ----------------------------------------------------
|
||
|
|
||
|
=============================================================================*/
|
||
|
|
||
|
/*===========================================================================
|
||
|
* include files
|
||
|
===========================================================================*/
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "ql_api_osi.h"
|
||
|
#include "ql_log.h"
|
||
|
#include "ql_gpio.h"
|
||
|
#include "ql_api_spi.h"
|
||
|
#include "ethernet_demo_macro.h"
|
||
|
#include "ql_api_ethernet.h"
|
||
|
#include "ql_api_datacall.h"
|
||
|
#include "ql_api_nw.h"
|
||
|
#include "ql_power.h"
|
||
|
|
||
|
#include "sockets.h"
|
||
|
#include "lwip/ip_addr.h"
|
||
|
#include "lwip/ip6_addr.h"
|
||
|
|
||
|
#include "lwip/inet.h"
|
||
|
#include "lwip/tcp.h"
|
||
|
|
||
|
#ifdef ETHERNET_PHY_CH395
|
||
|
#include "CH395.H"
|
||
|
#endif
|
||
|
|
||
|
/*========================================================================
|
||
|
* Macro Definition
|
||
|
*========================================================================*/
|
||
|
#define QL_ETHERNET_LOG_LEVEL QL_LOG_LEVEL_INFO
|
||
|
#define QL_ETHERNET_DEMO_LOG(msg, ...) QL_LOG(QL_ETHERNET_LOG_LEVEL, "phy_demo", msg, ##__VA_ARGS__)
|
||
|
|
||
|
#ifdef ETHERNET_PHY_CH395
|
||
|
// SPI
|
||
|
#define QL_CUR_SPI_PORT QL_SPI_PORT1
|
||
|
#define QL_CUR_SPI_CS_PIN QL_CUR_SPI1_CS_PIN
|
||
|
#define QL_CUR_SPI_CS_FUNC QL_CUR_SPI1_CS_FUNC
|
||
|
#define QL_CUR_SPI_CLK_PIN QL_CUR_SPI1_CLK_PIN
|
||
|
#define QL_CUR_SPI_CLK_FUNC QL_CUR_SPI1_CLK_FUNC
|
||
|
#define QL_CUR_SPI_DO_PIN QL_CUR_SPI1_DO_PIN
|
||
|
#define QL_CUR_SPI_DO_FUNC QL_CUR_SPI1_DO_FUNC
|
||
|
#define QL_CUR_SPI_DI_PIN QL_CUR_SPI1_DI_PIN
|
||
|
#define QL_CUR_SPI_DI_FUNC QL_CUR_SPI1_DI_FUNC
|
||
|
// GPIO
|
||
|
#define QL_CUR_INT_PIN 59
|
||
|
#define QL_CUR_INT_PIN_GPIO_FUNC 0
|
||
|
#define QL_CUR_INT_GPIO_NUM GPIO_2
|
||
|
|
||
|
#define QL_ETHERNET_HOT_PLUG_PIN 121
|
||
|
#define QL_ETHERNET_HOT_PLUG_PIN_GPIO_FUNC 0
|
||
|
#define QL_ETHERNET_HOT_PLUG_GPIO_NUM GPIO_23
|
||
|
|
||
|
#define QL_ETHERNET_HOT_PLUG_DEBOUNCE_TIME 100
|
||
|
// TCP
|
||
|
#define QL_ETHERNET_PHY_TCP_IP4_SIZE 4
|
||
|
#define QL_ETHERNET_PHY_TCP_CLIENTS_CNT 6
|
||
|
|
||
|
#define QL_ETHERNET_SIM_NUM 2
|
||
|
#endif
|
||
|
|
||
|
/*========================================================================
|
||
|
* Enumeration Definition
|
||
|
*========================================================================*/
|
||
|
|
||
|
/*========================================================================
|
||
|
* Type Definition
|
||
|
*=========================================================================*/
|
||
|
#ifdef ETHERNET_PHY_CH395
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
int id;
|
||
|
int fd;
|
||
|
int close_flag;
|
||
|
uint8_t srcip[QL_ETHERNET_PHY_TCP_IP4_SIZE];
|
||
|
uint16_t srcport;
|
||
|
uint8_t destip[QL_ETHERNET_PHY_TCP_IP4_SIZE];
|
||
|
uint16_t destport;
|
||
|
ql_task_t task;
|
||
|
struct sockaddr_in addr_in;
|
||
|
} ethernet_phy_tcp_ctx_s;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
ql_spi_port_e port;
|
||
|
ql_LvlMode lvl;
|
||
|
} ethernet_phy_spi_cs_s;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
bool state;
|
||
|
ql_sem_t act_sem;
|
||
|
ql_sem_t deact_sem;
|
||
|
}datacall_context_s;
|
||
|
#endif
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
ql_task_t task;
|
||
|
#ifdef ETHERNET_PHY_CH395
|
||
|
ql_mutex_t mutex;
|
||
|
// TCP
|
||
|
ethernet_phy_tcp_ctx_s client_ctx[QL_ETHERNET_PHY_TCP_CLIENTS_CNT];
|
||
|
int client_num;
|
||
|
// Debounce
|
||
|
ql_timer_t timer;
|
||
|
ql_GpioNum gpio_num;
|
||
|
#endif
|
||
|
} ethernet_phy_manager_s;
|
||
|
/*========================================================================
|
||
|
* Global Variable
|
||
|
*========================================================================*/
|
||
|
ethernet_phy_manager_s ethernet_phy_manager = {0};
|
||
|
#ifdef ETHERNET_PHY_CH395
|
||
|
static char send_buf[128]={0};
|
||
|
static int send_len = 0;
|
||
|
static char recv_buf[128]={0};
|
||
|
static int recv_len = 0;
|
||
|
|
||
|
ql_sem_t ql_data_reg_sem[QL_ETHERNET_SIM_NUM] = {0};
|
||
|
#endif
|
||
|
|
||
|
/*========================================================================
|
||
|
* function Definition
|
||
|
*========================================================================*/
|
||
|
#ifdef ETHERNET_PHY_CH395
|
||
|
void ethernet_phy_create_mutex(ql_mutex_t *lockaddr)
|
||
|
{
|
||
|
if (!lockaddr)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
if (NULL == *lockaddr)
|
||
|
{
|
||
|
ql_rtos_mutex_create(lockaddr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_delete_mutex(ql_mutex_t lock)
|
||
|
{
|
||
|
if (NULL == lock)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
ql_rtos_mutex_delete(lock);
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_try_lock(ql_mutex_t lock)
|
||
|
{
|
||
|
if (NULL == lock)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
ql_rtos_mutex_lock(lock, 0xffffffffUL);
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_unlock(ql_mutex_t lock)
|
||
|
{
|
||
|
if (NULL == lock)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
ql_rtos_mutex_unlock(lock);
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_send_event(uint32_t id, uint32_t param1, uint32_t param2, uint32_t param3)
|
||
|
{
|
||
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
||
|
ql_event_t event;
|
||
|
event.id = id;
|
||
|
event.param1 = param1;
|
||
|
event.param2 = param2;
|
||
|
event.param3 = param3;
|
||
|
ethernet_phy_try_lock(manager->mutex);
|
||
|
ql_rtos_event_send(manager->task, &event);
|
||
|
ethernet_phy_unlock(manager->mutex);
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_ch395_app_reset_cb(void *ctx)
|
||
|
{
|
||
|
// Do hardware reset here.
|
||
|
QL_ETHERNET_DEMO_LOG("ch395 reset cb");
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_ch395_app_notify_cb(void *ctx)
|
||
|
{
|
||
|
ch395_app_net_status_e status = *((ch395_app_net_status_e *)ctx);
|
||
|
QL_ETHERNET_DEMO_LOG("get phy status: %d", status);
|
||
|
if (status == CH395_APP_NET_CONNECTED)
|
||
|
{
|
||
|
ethernet_phy_send_event(QUEC_ETHERNET_APP_CONNECTED, 0, 0, 0);
|
||
|
}
|
||
|
else if (status == CH395_APP_NET_DISCONNECTED)
|
||
|
{
|
||
|
ethernet_phy_send_event(QUEC_ETHERNET_APP_DISCONNECTED, 0, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_hot_plug_timer_cb(void *ctx)
|
||
|
{
|
||
|
ql_GpioNum gpio_num = *((ql_GpioNum*)ctx);
|
||
|
ql_LvlMode lvl = LVL_LOW;
|
||
|
|
||
|
ql_gpio_get_level(QL_ETHERNET_HOT_PLUG_GPIO_NUM, &lvl);
|
||
|
if(lvl == LVL_LOW)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("eth plug in");
|
||
|
ch395_app_reset();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("eth plug out");
|
||
|
}
|
||
|
if(QL_GPIO_SUCCESS !=ql_int_enable(gpio_num))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_hot_plug_cb(void *ctx)
|
||
|
{
|
||
|
ql_GpioNum gpio_num = *((ql_GpioNum*)ctx);
|
||
|
if(QL_GPIO_SUCCESS !=ql_int_disable(gpio_num))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
||
|
if(manager->timer == NULL || ql_rtos_timer_is_running(manager->timer))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
QL_ETHERNET_DEMO_LOG("hot plug debounce");
|
||
|
ql_rtos_timer_start(manager->timer, QL_ETHERNET_HOT_PLUG_DEBOUNCE_TIME, 0);
|
||
|
}
|
||
|
|
||
|
int ethernet_phy_int_gpio(void *cb, void *ctx)
|
||
|
{
|
||
|
int err = -1;
|
||
|
// ch395 interrupt
|
||
|
if (QL_GPIO_SUCCESS != ql_pin_set_func(QL_CUR_INT_PIN, QL_CUR_INT_PIN_GPIO_FUNC))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
if (QL_GPIO_SUCCESS != ql_int_register(QL_CUR_INT_GPIO_NUM, EDGE_TRIGGER, DEBOUNCE_DIS, EDGE_FALLING, PULL_UP, cb, ctx))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
if (QL_GPIO_SUCCESS != ql_int_enable(QL_CUR_INT_GPIO_NUM))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
// ch395 hot plug
|
||
|
/*
|
||
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
||
|
manager->gpio_num = QL_ETHERNET_HOT_PLUG_GPIO_NUM;
|
||
|
if (QL_GPIO_SUCCESS != ql_pin_set_func(QL_ETHERNET_HOT_PLUG_PIN, QL_ETHERNET_HOT_PLUG_PIN_GPIO_FUNC))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
if (QL_GPIO_SUCCESS != ql_int_register(QL_ETHERNET_HOT_PLUG_GPIO_NUM, EDGE_TRIGGER, DEBOUNCE_EN, EDGE_BOTH, PULL_UP, ethernet_phy_hot_plug_cb, &(manager->gpio_num)))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
if (QL_GPIO_SUCCESS != ql_int_enable(QL_ETHERNET_HOT_PLUG_GPIO_NUM))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
*/
|
||
|
err = 0;
|
||
|
exit:
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_set_cs(void *ctx)
|
||
|
{
|
||
|
if (!ctx)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
ql_LvlMode lvl = (ql_LvlMode)(*((uint8_t *)ctx));
|
||
|
if (lvl == LVL_HIGH)
|
||
|
{
|
||
|
ql_spi_cs_high(QL_CUR_SPI_PORT);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ql_spi_cs_low(QL_CUR_SPI_PORT);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ethernet_phy_get_src_dst_ip(int fd,char src[32],char dst[32])
|
||
|
{
|
||
|
if(fd < 0 || !src || !dst)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
char src_ip[32] = {0};
|
||
|
char dst_ip[32] = {0};
|
||
|
struct sockaddr sa;
|
||
|
struct sockaddr_in *sa_v4;
|
||
|
int sa_len = sizeof(sa);
|
||
|
/* Get local ip. */
|
||
|
if(getsockname(fd,(struct sockaddr*)&sa,&sa_len))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if(AF_INET == sa.sa_family)
|
||
|
{
|
||
|
sa_v4 = (struct sockaddr_in *)&sa;
|
||
|
snprintf(src_ip,32,"%s/%d",inet_ntoa(sa_v4->sin_addr),ntohs(sa_v4->sin_port));
|
||
|
}
|
||
|
/* Get remote ip. */
|
||
|
if(getpeername(fd,(struct sockaddr*)&sa,&sa_len))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if(AF_INET == sa.sa_family)
|
||
|
{
|
||
|
sa_v4 = (struct sockaddr_in *)&sa;
|
||
|
snprintf(dst_ip,32,"%s/%d",inet_ntoa(sa_v4->sin_addr),ntohs(sa_v4->sin_port));
|
||
|
}
|
||
|
|
||
|
memcpy(src,src_ip,sizeof(src_ip));
|
||
|
memcpy(dst,dst_ip,sizeof(dst_ip));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static void ethernet_phy_client_thread(void *argv)
|
||
|
{
|
||
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
||
|
ethernet_phy_tcp_ctx_s *ctx = (ethernet_phy_tcp_ctx_s *)argv;
|
||
|
ctx->close_flag = 0;
|
||
|
int i = 0;
|
||
|
int ret = 0;
|
||
|
int socket_fd = -1;
|
||
|
int flags = 0;
|
||
|
int connected = 0;
|
||
|
fd_set read_fds;
|
||
|
fd_set write_fds;
|
||
|
fd_set exp_fds;
|
||
|
int fd_changed = 0;
|
||
|
int closing = false;
|
||
|
struct sockaddr_in local4, server_ipv4;
|
||
|
|
||
|
ip4_addr_t int_srcip;
|
||
|
ip4_addr_t int_destip;
|
||
|
|
||
|
IP4_ADDR(&int_srcip, ctx->srcip[0],ctx->srcip[1],ctx->srcip[2],ctx->srcip[3]);
|
||
|
IP4_ADDR(&int_destip, ctx->destip[0],ctx->destip[1],ctx->destip[2],ctx->destip[3]);
|
||
|
|
||
|
FD_ZERO(&read_fds);
|
||
|
FD_ZERO(&write_fds);
|
||
|
FD_ZERO(&exp_fds);
|
||
|
|
||
|
memset(&local4, 0x00, sizeof(struct sockaddr_in));
|
||
|
local4.sin_family = AF_INET;
|
||
|
local4.sin_port = htons(ctx->srcport);;
|
||
|
memcpy(&(local4.sin_addr),&int_srcip,sizeof(int_srcip));
|
||
|
|
||
|
|
||
|
QL_ETHERNET_DEMO_LOG("socket start!");
|
||
|
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||
|
if(socket_fd < 0)
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
/*
|
||
|
The local IP must be bound when NAT on.And when NAT off,bind IP or not is OK.
|
||
|
And for ethernet phy,the route policy is used when setting route prefer.
|
||
|
*/
|
||
|
ret = bind(socket_fd,(struct sockaddr *)&local4,sizeof(struct sockaddr));
|
||
|
if(ret < 0)
|
||
|
{
|
||
|
close(socket_fd);
|
||
|
socket_fd = -1;
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
flags |= O_NONBLOCK;
|
||
|
fcntl(socket_fd, F_SETFL,flags);
|
||
|
memset(&server_ipv4, 0x00, sizeof(struct sockaddr_in));
|
||
|
server_ipv4.sin_family = AF_INET;
|
||
|
server_ipv4.sin_port = htons(ctx->destport);
|
||
|
memcpy(&(server_ipv4.sin_addr),&int_destip,sizeof(int_destip));
|
||
|
ret = connect(socket_fd, (struct sockaddr *)&server_ipv4, sizeof(server_ipv4));
|
||
|
if(ret == 0)
|
||
|
{
|
||
|
connected = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(lwip_get_error(socket_fd) != EINPROGRESS)
|
||
|
{
|
||
|
close(socket_fd);
|
||
|
socket_fd = -1;
|
||
|
goto exit;
|
||
|
}
|
||
|
}
|
||
|
if(connected == 1)
|
||
|
{
|
||
|
ethernet_phy_try_lock(manager->mutex);
|
||
|
ctx->fd = socket_fd;
|
||
|
ethernet_phy_unlock(manager->mutex);
|
||
|
|
||
|
FD_SET(socket_fd, &read_fds);
|
||
|
QL_ETHERNET_DEMO_LOG("=====connect to \"tcp\" success=====");
|
||
|
memset(send_buf, 0x00, 128);
|
||
|
|
||
|
char src[32] = {"0.0.0.0/0"};
|
||
|
char dst[32] = {"255.255.255.255/255"};
|
||
|
if(true == ethernet_phy_get_src_dst_ip(socket_fd,src,dst))
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("get ip");
|
||
|
}
|
||
|
send_len = snprintf(send_buf, 128,"socket src:%s,dst:%s,cnt%d",src,dst,i);
|
||
|
|
||
|
if(write(socket_fd, send_buf, send_len) != send_len){
|
||
|
FD_SET(socket_fd, &write_fds);
|
||
|
}else{
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FD_SET(socket_fd, &write_fds);
|
||
|
}
|
||
|
FD_SET(socket_fd, &exp_fds);
|
||
|
while(1)
|
||
|
{
|
||
|
if(ctx->close_flag)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("client close flag");
|
||
|
goto exit;
|
||
|
}
|
||
|
if(connected == 1)
|
||
|
{
|
||
|
FD_SET(socket_fd, &read_fds);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FD_SET(socket_fd, &write_fds);
|
||
|
}
|
||
|
|
||
|
FD_SET(socket_fd, &exp_fds);
|
||
|
struct timeval timeout = {3,0};
|
||
|
fd_changed = select(socket_fd+1, &read_fds, &write_fds, &exp_fds, &timeout);
|
||
|
if(fd_changed > 0)
|
||
|
{
|
||
|
if(FD_ISSET(socket_fd, &write_fds))
|
||
|
{
|
||
|
FD_CLR(socket_fd, &write_fds);
|
||
|
if(connected== 0)
|
||
|
{
|
||
|
int value = 0;
|
||
|
int len = 0;
|
||
|
|
||
|
len = sizeof(value);
|
||
|
getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, &value, &len);
|
||
|
if(value == 0 || value == EISCONN )
|
||
|
{
|
||
|
ethernet_phy_try_lock(manager->mutex);
|
||
|
ctx->fd = socket_fd;
|
||
|
ethernet_phy_unlock(manager->mutex);
|
||
|
QL_ETHERNET_DEMO_LOG("=====connect to \"tcp\" success=====");
|
||
|
connected = 1;
|
||
|
FD_SET(socket_fd, &read_fds);
|
||
|
memset(send_buf, 0x00, 128);
|
||
|
|
||
|
char src[32] = {"0.0.0.0/0"};
|
||
|
char dst[32] = {"255.255.255.255/255"};
|
||
|
if(true == ethernet_phy_get_src_dst_ip(socket_fd,src,dst))
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("get ip");
|
||
|
}
|
||
|
send_len = snprintf(send_buf, 128,"socket src:%s,dst:%s,cnt%d",src,dst,i);
|
||
|
|
||
|
write(socket_fd, send_buf, send_len);
|
||
|
i++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("=====connect to \"tcp\" failed=====");
|
||
|
close(socket_fd);
|
||
|
socket_fd = -1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memset(send_buf, 0x00, 128);
|
||
|
|
||
|
char src[32] = {"0.0.0.0/0"};
|
||
|
char dst[32] = {"255.255.255.255/255"};
|
||
|
if(true == ethernet_phy_get_src_dst_ip(socket_fd,src,dst))
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("get ip");
|
||
|
}
|
||
|
send_len = snprintf(send_buf, 128,"socket src:%s,dst:%s,cnt%d",src,dst,i);
|
||
|
|
||
|
write(socket_fd, send_buf, send_len);
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
else if(FD_ISSET(socket_fd, &read_fds))
|
||
|
{
|
||
|
FD_CLR(socket_fd, &read_fds);
|
||
|
memset(recv_buf,0x00, 128);
|
||
|
recv_len = read(socket_fd, recv_buf, 128);
|
||
|
if(recv_len > 0)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG(">>>>Recv: %s", recv_buf);
|
||
|
memset(send_buf, 0x00, 128);
|
||
|
|
||
|
char src[32] = {"0.0.0.0/0"};
|
||
|
char dst[32] = {"255.255.255.255/255"};
|
||
|
if(true == ethernet_phy_get_src_dst_ip(socket_fd,src,dst))
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("get ip");
|
||
|
}
|
||
|
send_len = snprintf(send_buf, 128,"socket src:%s,dst:%s,cnt%d",src,dst,i);
|
||
|
|
||
|
write(socket_fd, send_buf, send_len);
|
||
|
i++;
|
||
|
FD_SET(socket_fd, &read_fds);
|
||
|
}
|
||
|
else if(recv_len == 0)
|
||
|
{
|
||
|
if(closing == false)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("===passive close!!!!");
|
||
|
shutdown(socket_fd, SHUT_WR);
|
||
|
closing = true;
|
||
|
FD_SET(socket_fd, &read_fds);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
close(socket_fd);
|
||
|
socket_fd = -1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(lwip_get_error(socket_fd) == EAGAIN)
|
||
|
{
|
||
|
FD_SET(socket_fd, &read_fds);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
close(socket_fd);
|
||
|
socket_fd = -1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if(FD_ISSET(socket_fd, &exp_fds))
|
||
|
{
|
||
|
FD_CLR(socket_fd, &exp_fds);
|
||
|
close(socket_fd);
|
||
|
socket_fd = -1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
exit:
|
||
|
QL_ETHERNET_DEMO_LOG("client end");
|
||
|
close(socket_fd);
|
||
|
ethernet_phy_try_lock(manager->mutex);
|
||
|
memset(ctx, 0, sizeof(ethernet_phy_tcp_ctx_s));
|
||
|
ctx->id = -1;
|
||
|
ctx->fd = -1;
|
||
|
manager->client_num--;
|
||
|
ethernet_phy_unlock(manager->mutex);
|
||
|
ql_rtos_task_delete(NULL);
|
||
|
}
|
||
|
|
||
|
int ethernet_phy_tcp_client_create(void *argv)
|
||
|
{
|
||
|
if (!argv)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("client param err");
|
||
|
return -1;
|
||
|
}
|
||
|
ethernet_phy_tcp_ctx_s *ctx = (ethernet_phy_tcp_ctx_s *)argv;
|
||
|
QlOSStatus err = QL_OSI_SUCCESS;
|
||
|
err = ql_rtos_task_create(&(ctx->task), 4 * 1024, APP_PRIORITY_NORMAL, "phy_client", ethernet_phy_client_thread, argv, 10);
|
||
|
if (err != QL_OSI_SUCCESS)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("task created failed");
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_tcp_open(void *argv)
|
||
|
{
|
||
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
||
|
uint16_t srcport = 0;
|
||
|
|
||
|
uint8_t destip[] = {220, 180, 239, 212};
|
||
|
uint16_t destport = 8305;
|
||
|
|
||
|
ql_data_call_info_s *info =(ql_data_call_info_s *)argv;
|
||
|
//Find NULL task
|
||
|
ethernet_phy_tcp_ctx_s *ctx = NULL;
|
||
|
int i = 0;
|
||
|
for (i = 0; i < QL_ETHERNET_PHY_TCP_CLIENTS_CNT; i++)
|
||
|
{
|
||
|
ctx = &(manager->client_ctx[i]);
|
||
|
if(NULL == ctx->task)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(i < QL_ETHERNET_PHY_TCP_CLIENTS_CNT)
|
||
|
{
|
||
|
ctx->srcip[3] = (info->v4.addr.ip.addr & 0xff000000UL) >> 24;
|
||
|
ctx->srcip[2] = (info->v4.addr.ip.addr & 0x00ff0000UL) >> 16;
|
||
|
ctx->srcip[1] = (info->v4.addr.ip.addr & 0x0000ff00UL) >> 8;
|
||
|
ctx->srcip[0] = (info->v4.addr.ip.addr & 0x000000ffUL);
|
||
|
ctx->srcport = srcport;
|
||
|
memcpy(ctx->destip, destip, QL_ETHERNET_PHY_TCP_IP4_SIZE);
|
||
|
ctx->destport = destport;
|
||
|
if (0 == ethernet_phy_tcp_client_create((void *)ctx))
|
||
|
{
|
||
|
manager->client_num++;
|
||
|
QL_ETHERNET_DEMO_LOG("client %d", manager->client_num);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("client create failed %d/%d",manager->client_num,QL_ETHERNET_PHY_TCP_CLIENTS_CNT);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("client max %d/%d,end", manager->client_num,QL_ETHERNET_PHY_TCP_CLIENTS_CNT);
|
||
|
}
|
||
|
ethernet_phy_unlock(manager->mutex);
|
||
|
}
|
||
|
|
||
|
void ethernet_phy_tcp_close(void)
|
||
|
{
|
||
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
||
|
ethernet_phy_try_lock(manager->mutex);
|
||
|
ethernet_phy_tcp_ctx_s *ctx = NULL;
|
||
|
int i = 0;
|
||
|
for (i = 0; i < QL_ETHERNET_PHY_TCP_CLIENTS_CNT; i++)
|
||
|
{
|
||
|
ctx = &(manager->client_ctx[i]);
|
||
|
if(ctx->task)
|
||
|
{
|
||
|
ctx->close_flag = 1;
|
||
|
}
|
||
|
}
|
||
|
ethernet_phy_unlock(manager->mutex);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ql_nw_ind_callback(uint8_t sim_id, unsigned int ind_type, void *ind_msg_buf)
|
||
|
{
|
||
|
if(QUEC_NW_DATA_REG_STATUS_IND == ind_type)
|
||
|
{
|
||
|
ql_nw_common_reg_status_info_s *data_reg_status=(ql_nw_common_reg_status_info_s *)ind_msg_buf;
|
||
|
QL_ETHERNET_DEMO_LOG("Sim%d data reg status changed, current status is %d", sim_id, data_reg_status->state);
|
||
|
if((QL_NW_REG_STATE_HOME_NETWORK == data_reg_status->state) || (QL_NW_REG_STATE_ROAMING == data_reg_status->state))
|
||
|
{
|
||
|
ql_rtos_semaphore_release(ql_data_reg_sem[sim_id]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ethernet_phy_start_data_call(uint8_t sim_id,int profile_idx)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
ql_nw_reg_status_info_s nw_info = {0};
|
||
|
ql_data_call_info_s info ={0};
|
||
|
|
||
|
ql_rtos_semaphore_create(&ql_data_reg_sem[sim_id], 0);
|
||
|
|
||
|
ret = ql_nw_register_cb(ql_nw_ind_callback);
|
||
|
if(0 != ret)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("ql_nw_register_cb err, ret=0x%x", ret);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
ret = ql_nw_get_reg_status(sim_id, &nw_info);
|
||
|
QL_ETHERNET_DEMO_LOG("ret: 0x%x, current data reg status=%d", ret, nw_info.data_reg.state);
|
||
|
if((QL_NW_REG_STATE_HOME_NETWORK != nw_info.data_reg.state) && (QL_NW_REG_STATE_ROAMING != nw_info.data_reg.state))
|
||
|
{
|
||
|
ql_rtos_semaphore_wait(ql_data_reg_sem[sim_id], QL_WAIT_FOREVER); //wait network registered
|
||
|
}
|
||
|
|
||
|
/* Start datacall. */
|
||
|
ret = ql_set_data_call_asyn_mode(sim_id, profile_idx, 0);
|
||
|
QL_ETHERNET_DEMO_LOG("mode 0x%x", ret);
|
||
|
ret=ql_start_data_call(sim_id, profile_idx, QL_PDP_TYPE_IP, NULL, NULL, NULL, 0);
|
||
|
if(0 != ret)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("ql_start_data_call err, ret=0x%x", ret);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/*Get datacall info. */
|
||
|
ret = ql_get_data_call_info(sim_id, profile_idx, &info);
|
||
|
QL_ETHERNET_DEMO_LOG("ql_get_data_call_info ret: 0x%x", ret);
|
||
|
QL_ETHERNET_DEMO_LOG("info.profile_idx: %d, info.ip_version: %d", info.profile_idx, info.ip_version);
|
||
|
QL_ETHERNET_DEMO_LOG("info->v4.state: %d, info.v6.state: %d", info.v4.state, info.v6.state);
|
||
|
if(info.v4.state)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("info.v4.addr.ip: %s", ip4addr_ntoa(&(info.v4.addr.ip)));
|
||
|
QL_ETHERNET_DEMO_LOG("info.v4.addr.pri_dns: %s", ip4addr_ntoa(&(info.v4.addr.pri_dns)));
|
||
|
QL_ETHERNET_DEMO_LOG("info.v4.addr.sec_dns: %s", ip4addr_ntoa(&(info.v4.addr.sec_dns)));
|
||
|
}
|
||
|
exit:
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
static void ethernet_phy_thread(void *argv)
|
||
|
{
|
||
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
||
|
#ifdef ETHERNET_PHY_CH395
|
||
|
int ret = 0;
|
||
|
uint8_t sim_id = 0;
|
||
|
int profile_idx = 5;
|
||
|
int datacall_profile_idx = 1;
|
||
|
ql_data_call_info_s info ={0};
|
||
|
|
||
|
/*
|
||
|
The following is used for NAT.
|
||
|
|
||
|
uint32_t saved_list = 0;
|
||
|
uint32_t target_list = (1 << (profile_idx - 1)) << (sim_id == 0? 0 : 16);
|
||
|
ret = ql_datacall_get_nat(&saved_list);
|
||
|
QL_ETHERNET_DEMO_LOG("get datacall saved nat ret: 0x%x, %d", ret, saved_list);
|
||
|
if(0 != ret)
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
if(saved_list != target_list)
|
||
|
{
|
||
|
ret = ql_datacall_set_nat(target_list);
|
||
|
QL_ETHERNET_DEMO_LOG("ql_datacall_set_nat err, ret=0x%x", ret);
|
||
|
if(0 != ret)
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
ql_power_reset(RESET_NORMAL);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
ql_nat_subnet_config_s config = {"192.168.1.0","255.255.255.0"};
|
||
|
ret = ql_datacall_set_subnet(sim_id, profile_idx, &config);
|
||
|
QL_ETHERNET_DEMO_LOG("ql_datacall_set_subnet ret=0x%x", ret);
|
||
|
if(0 != ret)
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
ethernet_phy_create_mutex(&(manager->mutex));
|
||
|
|
||
|
/*
|
||
|
ch395q init
|
||
|
*/
|
||
|
ql_ethernet_phy_s spi_ctx =
|
||
|
{
|
||
|
.mode = QL_ETHERNET_PHY_HW_SPI_MODE,
|
||
|
.hw_spi.mosi_pin_num = QL_CUR_SPI_DO_PIN,
|
||
|
.hw_spi.mosi_func_sel = QL_CUR_SPI_DO_FUNC,
|
||
|
.hw_spi.miso_pin_num = QL_CUR_SPI_DI_PIN,
|
||
|
.hw_spi.miso_func_sel = QL_CUR_SPI_DO_FUNC,
|
||
|
.hw_spi.clk_pin_num = QL_CUR_SPI_CLK_PIN,
|
||
|
.hw_spi.clk_func_sel = QL_CUR_SPI_CLK_FUNC,
|
||
|
.hw_spi.cs_pin_num = QL_CUR_SPI_CS_PIN,
|
||
|
.hw_spi.cs_func_sel = QL_CUR_SPI_CS_FUNC,
|
||
|
/*********************************************/
|
||
|
.hw_spi.config.input_mode = QL_SPI_INPUT_TRUE,
|
||
|
.hw_spi.config.port = QL_CUR_SPI_PORT,
|
||
|
.hw_spi.config.spiclk = QL_SPI_CLK_20MHZ,
|
||
|
#if QL_SPI_16BIT_DMA
|
||
|
.hw_spi.config.framesize = 16,
|
||
|
#else
|
||
|
.hw_spi.config.framesize = 8,
|
||
|
#endif
|
||
|
.hw_spi.config.cs_polarity0 = QL_SPI_CS_ACTIVE_LOW,
|
||
|
.hw_spi.config.cs_polarity1 = QL_SPI_CS_ACTIVE_LOW,
|
||
|
.hw_spi.config.cpol = QL_SPI_CPOL_LOW,
|
||
|
.hw_spi.config.cpha = QL_SPI_CPHA_1Edge,
|
||
|
.hw_spi.config.input_sel = QL_SPI_DI_1,
|
||
|
.hw_spi.config.transmode = QL_SPI_DMA_IRQ,
|
||
|
.hw_spi.config.cs = QL_SPI_CS0,
|
||
|
.hw_spi.config.clk_delay = QL_SPI_CLK_DELAY_0,
|
||
|
};
|
||
|
if (QL_ETHERNET_SUCCESS != ql_ethernet_phy_init(&spi_ctx))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
if(QL_OSI_SUCCESS != ql_rtos_timer_create(&(manager->timer),manager->task,ethernet_phy_hot_plug_timer_cb,&(manager->gpio_num)))
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("timer create fail!");
|
||
|
goto exit;
|
||
|
}
|
||
|
if (!ch395_app_cb_register(CH395_APP_CB_TYPE_RESET, ethernet_phy_ch395_app_reset_cb))
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("ch395 register fail!");
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
if (!ch395_app_cb_register(CH395_APP_CB_TYPE_NOTIFY, ethernet_phy_ch395_app_notify_cb))
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("ch395 register fail!");
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
if (0 != ethernet_phy_int_gpio(ch395_app_get_gpio_cb(), NULL))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
/* Wait for nw register and start datacall. */
|
||
|
if(false == ethernet_phy_start_data_call(sim_id,datacall_profile_idx))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/* Router mode. */
|
||
|
ql_ethernet_ctx_s ctx =
|
||
|
{
|
||
|
.mode = QL_ETHERNET_MODE_ROUTER,
|
||
|
.option.cover = 0,
|
||
|
.option.dhcp = 1,
|
||
|
.option.ecid.sim_id = sim_id,
|
||
|
.option.ecid.cid = profile_idx,
|
||
|
.option.prefer = QL_ETHERNET_ROUTE_PREFER_PDN,
|
||
|
};
|
||
|
if (!ch395_app_init(&ctx))
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("ch395 init fail!");
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
ql_event_t event;
|
||
|
if (ql_event_try_wait(&event) != 0)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
if (event.id == 0)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
QL_ETHERNET_DEMO_LOG("ethernet event:%x", event.id);
|
||
|
switch (event.id)
|
||
|
{
|
||
|
case QUEC_ETHERNET_APP_CONNECTED: {
|
||
|
/* Get ethernet info. */
|
||
|
ret = ql_get_data_call_info(sim_id, profile_idx, &info);
|
||
|
QL_ETHERNET_DEMO_LOG("ql_get_data_call_info ret: 0x%x", ret);
|
||
|
QL_ETHERNET_DEMO_LOG("info.profile_idx: %d, info.ip_version: %d", info.profile_idx, info.ip_version);
|
||
|
QL_ETHERNET_DEMO_LOG("info->v4.state: %d, info.v6.state: %d", info.v4.state, info.v6.state);
|
||
|
if(info.v4.state)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("info.v4.addr.ip: %s", ip4addr_ntoa(&(info.v4.addr.ip)));
|
||
|
QL_ETHERNET_DEMO_LOG("info.v4.addr.pri_dns: %s", ip4addr_ntoa(&(info.v4.addr.pri_dns)));
|
||
|
QL_ETHERNET_DEMO_LOG("info.v4.addr.sec_dns: %s", ip4addr_ntoa(&(info.v4.addr.sec_dns)));
|
||
|
}
|
||
|
ethernet_phy_tcp_open(&info);
|
||
|
break;
|
||
|
}
|
||
|
case QUEC_ETHERNET_APP_DISCONNECTED: {
|
||
|
QL_ETHERNET_DEMO_LOG("phy discon");
|
||
|
ethernet_phy_tcp_close();
|
||
|
break;
|
||
|
}
|
||
|
default: {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
exit:
|
||
|
QL_ETHERNET_DEMO_LOG("ethernet demo end");
|
||
|
if(manager->timer)
|
||
|
{
|
||
|
ql_rtos_timer_stop(manager->timer);
|
||
|
ql_rtos_timer_delete(manager->timer);
|
||
|
manager->timer = NULL;
|
||
|
}
|
||
|
if (manager->mutex)
|
||
|
{
|
||
|
ql_rtos_mutex_delete(manager->mutex);
|
||
|
manager->mutex = NULL;
|
||
|
}
|
||
|
#endif
|
||
|
if (manager->task)
|
||
|
{
|
||
|
manager->task = NULL;
|
||
|
ql_rtos_task_delete(NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ql_ethernet_demo_init(void)
|
||
|
{
|
||
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
||
|
QlOSStatus err = QL_OSI_SUCCESS;
|
||
|
err = ql_rtos_task_create(&(manager->task), 4 * 1024, APP_PRIORITY_NORMAL, "q_phy_demo", ethernet_phy_thread, NULL, 10);
|
||
|
if (err != QL_OSI_SUCCESS)
|
||
|
{
|
||
|
QL_ETHERNET_DEMO_LOG("task created failed");
|
||
|
return;
|
||
|
}
|
||
|
}
|