701 lines
20 KiB
C
701 lines
20 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
|
|
// HTTP
|
|
#define QL_ETHERNET_HTTP_ALIGN 8
|
|
#define QL_ETHERNET_HTTP_BUFSIZE 8096
|
|
|
|
#define QL_ETHERNET_HTTP_SEND_BYTES (2 * 1024) // send 2KB each time
|
|
#define QL_ETHERNET_HTTP_CONTENT_LEN (10 * 1024 * 1024) // 10MB
|
|
#endif
|
|
|
|
/*========================================================================
|
|
* Enumeration Definition
|
|
*========================================================================*/
|
|
|
|
/*========================================================================
|
|
* Type Definition
|
|
*=========================================================================*/
|
|
#ifdef ETHERNET_PHY_CH395
|
|
|
|
typedef struct
|
|
{
|
|
int id;
|
|
int fd;
|
|
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;
|
|
#endif
|
|
|
|
typedef struct
|
|
{
|
|
ql_task_t task;
|
|
#ifdef ETHERNET_PHY_CH395
|
|
ql_mutex_t mutex;
|
|
// TCP
|
|
ethernet_phy_tcp_ctx_s server_ctx;
|
|
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};
|
|
|
|
/*========================================================================
|
|
* 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);
|
|
}
|
|
}
|
|
|
|
static void ethernet_phy_http_error(int nClientScok, int nStatusCode)
|
|
{
|
|
char str[256] = {0};
|
|
int ret = 0;
|
|
|
|
char *pStrError = "HTTP/1.1 %d NOT FOUND\
|
|
Content-Type: text/html\
|
|
Accept-Ranges: bytes\
|
|
Server: HFS 2.3k\
|
|
Set-Cookie: HFS_SID_=0.974440259393305; path=/; HttpOnly\
|
|
Content-Encoding: gzip";
|
|
|
|
QL_ETHERNET_DEMO_LOG("httpd status code:%d", nStatusCode);
|
|
ret = snprintf(str, 256, pStrError, nStatusCode);
|
|
|
|
if (0 != ret)
|
|
{
|
|
if (ret != write(nClientScok, str, ret))
|
|
{
|
|
QL_ETHERNET_DEMO_LOG("socket send failed\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ethernet_phy_http_send(int nClientScok)
|
|
{
|
|
int ret = 0, len = 0;
|
|
int len_temp = 0;
|
|
|
|
char *buffer_align = NULL;
|
|
char *buffer = NULL;
|
|
buffer_align = (char *)malloc(QL_ETHERNET_HTTP_ALIGN + QL_ETHERNET_HTTP_BUFSIZE);
|
|
if (NULL == buffer_align)
|
|
{
|
|
ethernet_phy_http_error(nClientScok, 500);
|
|
close(nClientScok);
|
|
return;
|
|
}
|
|
buffer = (char *)OSI_ALIGN_UP(buffer_align, QL_ETHERNET_HTTP_ALIGN);
|
|
memset(buffer, 0, QL_ETHERNET_HTTP_BUFSIZE + QL_ETHERNET_HTTP_ALIGN);
|
|
|
|
// read any http streams,no need to parse
|
|
struct timeval timeout = {3,0};
|
|
setsockopt(nClientScok,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));
|
|
ret = read(nClientScok, buffer, QL_ETHERNET_HTTP_BUFSIZE);
|
|
if (ret <= 0)
|
|
{
|
|
ethernet_phy_http_error(nClientScok, 400);
|
|
goto exit;
|
|
}
|
|
else
|
|
{
|
|
QL_ETHERNET_DEMO_LOG("recv : %s\n", buffer);
|
|
}
|
|
len = QL_ETHERNET_HTTP_CONTENT_LEN;
|
|
snprintf(buffer, QL_ETHERNET_HTTP_BUFSIZE, "HTTP/1.1 200 OK\nServer: Quectel\nContent-Length: %d\nConnection: close\nContent-Type: %s\n\n", len, "application/octet-stream");
|
|
// send http header
|
|
len_temp = strlen(buffer);
|
|
if (len_temp != write(nClientScok, buffer, len_temp))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// send QL_ETHERNET_HTTP_SEND_BYTES each time
|
|
int send_bytes = 0;
|
|
int has_sent = 0;
|
|
while (has_sent < len)
|
|
{
|
|
if (has_sent + QL_ETHERNET_HTTP_SEND_BYTES > len)
|
|
{
|
|
send_bytes = len - QL_ETHERNET_HTTP_SEND_BYTES;
|
|
}
|
|
else
|
|
{
|
|
send_bytes = QL_ETHERNET_HTTP_SEND_BYTES;
|
|
}
|
|
ret = write(nClientScok, buffer, send_bytes);
|
|
if (ret < 0)
|
|
{
|
|
QL_ETHERNET_DEMO_LOG("socket send failed, return %d\n", ret);
|
|
break;
|
|
}
|
|
QL_ETHERNET_DEMO_LOG("phy http send %d/%d/%d", send_bytes, has_sent, len);
|
|
has_sent += send_bytes;
|
|
}
|
|
exit:
|
|
close(nClientScok);
|
|
free(buffer_align);
|
|
return;
|
|
}
|
|
|
|
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;
|
|
|
|
QL_ETHERNET_DEMO_LOG("client start:%s:%d", inet_ntoa(ctx->addr_in.sin_addr), ctx->addr_in.sin_port);
|
|
// Better use "select" for deleting clients quickly and safely once detecting phy status change.
|
|
ethernet_phy_http_send(ctx->fd);
|
|
QL_ETHERNET_DEMO_LOG("client end:%s:%d", inet_ntoa(ctx->addr_in.sin_addr), ctx->addr_in.sin_port);
|
|
|
|
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_server(void *argv)
|
|
{
|
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
|
ethernet_phy_tcp_ctx_s *ctx = (ethernet_phy_tcp_ctx_s *)argv;
|
|
int socket_fd = -1;
|
|
int ret = 0;
|
|
struct sockaddr_in local4, client4;
|
|
|
|
ip4_addr_t int_srcip;
|
|
|
|
IP4_ADDR(&int_srcip, ctx->srcip[0], ctx->srcip[1], ctx->srcip[2], ctx->srcip[3]);
|
|
|
|
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;
|
|
}
|
|
ret = bind(socket_fd, (struct sockaddr *)&local4, sizeof(struct sockaddr));
|
|
if (ret < 0)
|
|
{
|
|
goto exit;
|
|
}
|
|
ret = listen(socket_fd, 1);
|
|
if (ret < 0)
|
|
{
|
|
goto exit;
|
|
}
|
|
ethernet_phy_try_lock(manager->mutex);
|
|
ctx->fd = socket_fd;
|
|
ethernet_phy_unlock(manager->mutex);
|
|
QL_ETHERNET_DEMO_LOG("tcp server wait for clients");
|
|
// Better use "select" for deleting server quickly and safely once detecting phy status change.
|
|
while (1)
|
|
{
|
|
int len = sizeof(struct sockaddr);
|
|
int con_fd = accept(socket_fd, (struct sockaddr *)&client4, &len);
|
|
if (con_fd < 0)
|
|
{
|
|
QL_ETHERNET_DEMO_LOG("con fd err");
|
|
goto exit;
|
|
}
|
|
ethernet_phy_try_lock(manager->mutex);
|
|
|
|
//Find NULL task
|
|
ethernet_phy_tcp_ctx_s *client_ctx = NULL;
|
|
int i = 0;
|
|
for (i = 0; i < QL_ETHERNET_PHY_TCP_CLIENTS_CNT; i++)
|
|
{
|
|
client_ctx = &(manager->client_ctx[i]);
|
|
if(NULL == client_ctx->task)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(i < QL_ETHERNET_PHY_TCP_CLIENTS_CNT)
|
|
{
|
|
client_ctx->id = i;
|
|
client_ctx->fd = con_fd;
|
|
memcpy((void *)(&(client_ctx->addr_in)), &client4, sizeof(struct sockaddr));
|
|
if (0 == ethernet_phy_tcp_client_create((void *)client_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);
|
|
}
|
|
exit:
|
|
QL_ETHERNET_DEMO_LOG("tcp server end");
|
|
close(socket_fd);
|
|
ethernet_phy_try_lock(manager->mutex);
|
|
memset(ctx, 0, sizeof(ethernet_phy_tcp_ctx_s));
|
|
ctx->fd = -1;
|
|
ethernet_phy_unlock(manager->mutex);
|
|
ql_rtos_task_delete(NULL);
|
|
return;
|
|
}
|
|
|
|
void ethernet_phy_tcp_server_create(void *argv)
|
|
{
|
|
if (!argv)
|
|
{
|
|
QL_ETHERNET_DEMO_LOG("server param err");
|
|
return;
|
|
}
|
|
ethernet_phy_tcp_ctx_s *ctx = (ethernet_phy_tcp_ctx_s *)argv;
|
|
if (ctx->task)
|
|
{
|
|
QL_ETHERNET_DEMO_LOG("server exist");
|
|
return;
|
|
}
|
|
QlOSStatus err = QL_OSI_SUCCESS;
|
|
err = ql_rtos_task_create(&(ctx->task), 4 * 1024, APP_PRIORITY_NORMAL, "phy_server", ethernet_phy_tcp_server, argv, 10);
|
|
if (err != QL_OSI_SUCCESS)
|
|
{
|
|
QL_ETHERNET_DEMO_LOG("task created failed");
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void ethernet_phy_thread(void *argv)
|
|
{
|
|
ethernet_phy_manager_s *manager = ðernet_phy_manager;
|
|
#ifdef ETHERNET_PHY_CH395
|
|
uint8_t srcip[QL_ETHERNET_PHY_TCP_IP4_SIZE] = {192, 168, 1, 100};
|
|
uint16_t srcport = 8252; // Zero for random port.
|
|
|
|
uint8_t gw[QL_ETHERNET_PHY_TCP_IP4_SIZE] = {192, 168, 1, 1};
|
|
uint8_t netmask[QL_ETHERNET_PHY_TCP_IP4_SIZE] = {255, 255, 255, 0};
|
|
|
|
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_12_5MHZ,
|
|
#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;
|
|
}
|
|
/*
|
|
QUECTEL------------------CH395Q--------------------PC
|
|
IP_LAN|192.168.1.100(port) 192.168.1.100(port) 192.168.1.200(8252)
|
|
GW |192.168.1.1 192.168.1.1 Any except for 192.168.1.100
|
|
*/
|
|
ql_ethernet_ctx_s ctx =
|
|
{
|
|
.ip4 = srcip,
|
|
.gw = gw,
|
|
.netmask = netmask,
|
|
.mode = QL_ETHERNET_MODE_NONE,
|
|
};
|
|
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: {
|
|
ethernet_phy_tcp_ctx_s *ctx = &(manager->server_ctx);
|
|
ethernet_phy_try_lock(manager->mutex);
|
|
memcpy(ctx->srcip, srcip, QL_ETHERNET_PHY_TCP_IP4_SIZE);
|
|
ctx->srcport = srcport;
|
|
ethernet_phy_unlock(manager->mutex);
|
|
ethernet_phy_tcp_server_create(ctx);
|
|
break;
|
|
}
|
|
case QUEC_ETHERNET_APP_DISCONNECTED: {
|
|
QL_ETHERNET_DEMO_LOG("phy discon");
|
|
/*
|
|
Server and clients can be set deleting flag here.
|
|
Better use "select" for deleting server/clients quickly and safely once detecting phy status change.
|
|
*/
|
|
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;
|
|
}
|
|
}
|