forked from gary/BCU
2
0
Fork 0
BCU/library/drv_peripheral/drv_w5500.c

417 lines
14 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* @file drv_w5500.c
* @brief w5500 drivers
* @version V1.0
* @author Gary
* @copyright
******************************************************************************/
#include "drv_gpio.h"
#include "drv_w5500.h"
#include "bsp_task.h"
#include "kit_time.h"
#include "kit_data.h"
#include "kit_debug.h"
#include "ucos_ii.h"
OS_EVENT *w5500_semaphore;
void drv_w5500_init(W5500Item *item, uint32_t ip, uint16_t *port_array, uint32_t gateway_ip, uint32_t net_mask, uint8_t *mac, uint16_t timeout)
{
uint8_t buf[20];
uint32_t cnt = 0;
item->server_port = port_array;
//自动协商 最高位置位否则PHY重启
buf[0] = 0x38 | 0x80 | 0x40;
drv_w5500_write_comm_reg(item, W5500_PHYCFGR_REG_0x2E, buf, 1);
buf[0] = 0;
while(((buf[0] & 0x01) == 0x00) && (cnt++ < 50))
{
bsp_task_delay_ms(100);
drv_w5500_read_comm_reg(item, W5500_PHYCFGR_REG_0x2E, buf, 1);
}
KIT_MODULE_PRINTF(W5500_PRT_EN, "w5500 connet res %d\r\n", cnt < 100);
cnt = 0;
//设置网关IP 子网掩码 MAC 源IP
WRITE_LT_INT32U(buf, cnt, gateway_ip);
WRITE_LT_INT32U(buf, cnt, net_mask);
kit_copy_buf(&buf[cnt], mac, 6);
cnt += 6;
WRITE_LT_INT32U(buf, cnt, ip);
drv_w5500_write_comm_reg(item, W5500_GAR0_REG_0x01, buf, 4 + 4 + 6 + 4);
buf[0] = timeout / 200;
drv_w5500_write_comm_reg(item, W5500_GAR0_REG_0x01, buf, 1);
#ifdef W5500_DEBUG
drv_w5500_read_comm_reg(item, W5500_GAR0_REG_0x01, buf, 4 + 4 + 6 + 4);
KIT_MODULE_PRINTF(W5500_PRT_EN, "w5500 param:");
KIT_DEBUG_PRINTF_U8_BUF(buf, 4 + 4 + 6 + 4);
#endif
w5500_semaphore = OSSemCreate(1);
}
uint8_t drv_w5500_get_socket_status(W5500Item *item, uint8_t socket)
{
uint8_t buf[1];
uint8_t socket_reg = W5500_CREAT_SOCKET_REG(socket);
//读取当前socket状态
drv_w5500_read_socket_reg(item, socket_reg, Sn_SR_0x03, buf, 1);
return buf[0];
}
bool drv_w5500_close_socket(W5500Item *item, uint8_t socket)
{
bool res = false;
uint8_t tmp_buf[1];
uint32_t cnt;
uint8_t socket_reg = W5500_CREAT_SOCKET_REG(socket);
//读取当前socket状态
if(item->close_call != NULL)
{
item->close_call(socket);
}
drv_w5500_read_socket_reg(item, socket_reg, Sn_SR_0x03, tmp_buf, 1);
KIT_MODULE_PRINTF(W5500_PRT_EN, "socket %d close st %x\r\n", socket, tmp_buf[0]);
if(tmp_buf[0] != SOCK_CLOSED)
{
tmp_buf[0] = SOCKET_CMD_CLOSE;
drv_w5500_write_socket_reg(item, socket_reg, Sn_CR_0x01, tmp_buf, 1);
cnt = 0;
while((tmp_buf[0] != SOCK_CLOSED) && (cnt++ < 20))
{
drv_w5500_read_socket_reg(item, socket_reg, Sn_SR_0x03, tmp_buf, 1);
kit_time_dly_ms(1);
}
if(cnt < 20)
{
//强制关闭一个socket
tmp_buf[0] = 0;
drv_w5500_write_socket_reg(item, socket_reg, Sn_MR_0x00, tmp_buf, 1);
//清除socket所有中断
tmp_buf[0] = 0xFF;
drv_w5500_write_socket_reg(item, socket_reg, Sn_IR_0x02, tmp_buf, 1);
//关闭所有中断
tmp_buf[0] = 0;
drv_w5500_write_socket_reg(item, socket_reg, Sn_IMR_0x2C, tmp_buf, 1);
res = true;
}
}
return res;
}
//MTU
#define SOCKET_UDP_PACKSIZE 1472 //1-1472
#define SOCKET_TCP_PACKSIZE 1460 //1-1460
#define SOCKET_PPPOE_PACKSIZE 1464 //1-1464
#define SOCKET_MACRAW_PACKSIZE 1514 //1-1514
bool drv_w5500_creat_tcp_server(W5500Item *item, uint8_t socket, uint16_t local_port)
{
uint8_t tmp_buf[4];
uint32_t cnt;
uint8_t socket_reg = W5500_CREAT_SOCKET_REG(socket);
if(socket < W5500_MAX_SOCKET_NUM)
{
//尝试关闭socket
drv_w5500_close_socket(item, socket);
kit_time_dly_ms(1);
//设置位TCP模式 无延时ACK
tmp_buf[0] = (SOCKET_TCP & 0x07) | 0x20;
drv_w5500_write_socket_reg(item, socket_reg, Sn_MR_0x00, tmp_buf, 1);
//设置本地端口号
WRITE_BT_INT16U_BY_CONST_POS(tmp_buf, 0, local_port);
drv_w5500_write_socket_reg(item, socket_reg, Sn_PORT_0x04, tmp_buf, 2);
drv_w5500_read_socket_reg(item, socket_reg, Sn_PORT_0x04, tmp_buf, 2);
KIT_MODULE_PRINTF(W5500_PRT_EN, "socket %d creat port %d\r\n", socket, READ_BT_INT16U_BY_CONST_POS(tmp_buf, 0));
//打开socket
tmp_buf[0] = SOCKET_CMD_OPEN;
drv_w5500_write_socket_reg(item, socket_reg, Sn_CR_0x01, tmp_buf, 1);
cnt = 0;
while((tmp_buf[0] != SOCK_INIT) && (cnt++ < 50))
{
drv_w5500_read_socket_reg(item, socket_reg, Sn_SR_0x03, tmp_buf, 1);
//KIT_MODULE_PRINTF(W5500_PRT_EN, "socket sr %x\r\n", tmp_buf[0]);
kit_time_dly_ms(1);
}
if(cnt < 50)
{
//监听socket
tmp_buf[0] = SOCKET_CMD_LISTEN;
drv_w5500_write_socket_reg(item, socket_reg, Sn_CR_0x01, tmp_buf, 1);
for(cnt = 0; cnt < 40; cnt++)
{
drv_w5500_read_socket_reg(item, socket_reg, Sn_SR_0x03, tmp_buf, 1);
//KIT_MODULE_PRINTF(W5500_PRT_EN, "socket sr %x\r\n", tmp_buf[0]);
if(tmp_buf[0] == SOCK_LISTEN)
{
//设置MTU
WRITE_BT_INT16U_BY_CONST_POS(tmp_buf, 0, SOCKET_TCP_PACKSIZE);
drv_w5500_write_socket_reg(item, socket_reg, Sn_MSSR_0x12, tmp_buf, 2);
//心跳包间隔
tmp_buf[0] = 1;
drv_w5500_write_socket_reg(item, socket_reg, Sn_KPALVTR_0x2F, tmp_buf, 1);
KIT_MODULE_PRINTF(W5500_PRT_EN, "w5500 server %d register success\r\n", socket);
//清除socket所有中断
tmp_buf[0] = 0xFF;
drv_w5500_write_socket_reg(item, socket_reg, Sn_IR_0x02, tmp_buf, 1);
//关闭所有中断
tmp_buf[0] = 0xFF;
drv_w5500_write_socket_reg(item, socket_reg, Sn_IMR_0x2C, tmp_buf, 1);
tmp_buf[0] = 1;
drv_w5500_read_socket_reg(item, socket_reg, Sn_IMR_0x2C, tmp_buf, 1);
KIT_MODULE_PRINTF(W5500_PRT_EN, "w5500 server %d ir %d \r\n", socket, tmp_buf[0]);
return true;
}
kit_time_dly_ms(100);
}
}
}
KIT_MODULE_PRINTF(W5500_PRT_EN, "w5500 server %d register fail\r\n", socket);
return false;
}
bool drv_w5500_read_socket_reg(W5500Item *item, uint8_t ctrl_phase, uint16_t reg, uint8_t *value, uint16_t len)
{
bool res = false;
uint8_t buf[3], err;
buf[0] = reg >> 8;
buf[1] = (uint8_t)reg;
buf[2] = ctrl_phase << 3 | W5500_READ_ACCESS_MODE;
OSSemPend(w5500_semaphore, 500, &err);
if(err == OS_ERR_NONE)
{
drv_gpio_set_pin_status(item->cs, kGpioStatus_Low);
res = (drv_spi_series_sync_send_receive(item->spi, buf, 3, value, len) == kKit_Ret_Ok);
drv_gpio_set_pin_status(item->cs, kGpioStatus_High);
OSSemPost(w5500_semaphore);
}
return res;
}
//len > 实际长度 + 3
bool drv_w5500_dma_read_socket_reg(W5500Item *item, uint8_t ctrl_phase, uint16_t reg, uint8_t *value, uint16_t len)
{
bool res = false;
uint32_t i;
uint8_t err;
value[0] = reg >> 8;
value[1] = (uint8_t)reg;
value[2] = ctrl_phase << 3 | W5500_READ_ACCESS_MODE;
OSSemPend(w5500_semaphore, 500, &err);
if(err == OS_ERR_NONE)
{
drv_gpio_set_pin_status(item->cs, kGpioStatus_Low);
res = (drv_spi_dma_sync_receive(item->spi, value, len + 3) == kKit_Ret_Ok);
drv_gpio_set_pin_status(item->cs, kGpioStatus_High);
OSSemPost(w5500_semaphore);
for(i = 0 ; i < len; i++)
{
value[i] = value[i + 3];
}
}
return res;
}
bool drv_w5500_write_socket_reg(W5500Item *item, uint8_t ctrl_phase, uint16_t reg, uint8_t *value, uint16_t len)
{
bool res = false;
uint8_t buf[3], err;
buf[0] = reg >> 8;
buf[1] = reg;
buf[2] = ctrl_phase << 3 | W5500_WRITE_ACCESS_MODE;
OSSemPend(w5500_semaphore, 500, &err);
if(err == OS_ERR_NONE)
{
drv_gpio_set_pin_status(item->cs, kGpioStatus_Low);
res = (drv_spi_series_sync_send_receive(item->spi, buf, 3, NULL, 0) == kKit_Ret_Ok);
res &= (drv_spi_series_sync_send_receive(item->spi, value, len, NULL, 0) == kKit_Ret_Ok);
drv_gpio_set_pin_status(item->cs, kGpioStatus_High);
OSSemPost(w5500_semaphore);
}
return res;
}
bool drv_w5500_dma_write_socket_reg(W5500Item *item, uint8_t ctrl_phase, uint16_t reg, uint8_t *value, uint16_t len)
{
bool res = false;
uint8_t w5500_send_buf[300], err;
if(len + 3 < 300)
{
w5500_send_buf[0] = reg >> 8;
w5500_send_buf[1] = reg;
w5500_send_buf[2] = ctrl_phase << 3 | W5500_WRITE_ACCESS_MODE;
kit_copy_buf(&w5500_send_buf[3], value, len);
OSSemPend(w5500_semaphore, 0, &err);
drv_gpio_set_pin_status(item->cs, kGpioStatus_Low);
res = (drv_spi_dma_sync_send(item->spi, w5500_send_buf, len + 3) == kKit_Ret_Ok);
drv_gpio_set_pin_status(item->cs, kGpioStatus_High);
OSSemPost(w5500_semaphore);
}
return res;
}
bool drv_w5500_read_comm_reg(W5500Item *item, uint16_t reg, uint8_t *value, uint16_t len)
{
bool res = false;
uint8_t buf[3];
buf[0] = reg >> 8;
buf[1] = reg;
buf[2] = SELECT_GREG_00 | W5500_READ_ACCESS_MODE;
drv_gpio_set_pin_status(item->cs, kGpioStatus_Low);
res = (drv_spi_series_sync_send_receive(item->spi, buf, 3, value, len) == kKit_Ret_Ok);
drv_gpio_set_pin_status(item->cs, kGpioStatus_High);
return res;
}
bool drv_w5500_write_comm_reg(W5500Item *item, uint8_t reg, uint8_t *value, uint16_t len)
{
bool res = true;
uint8_t buf[3];
buf[0] = reg >> 8;
buf[1] = reg;
buf[2] = SELECT_GREG_00 | W5500_WRITE_ACCESS_MODE;
drv_gpio_set_pin_status(item->cs, kGpioStatus_Low);
res &= (drv_spi_series_sync_send_receive(item->spi, buf, 3, NULL, 0) == kKit_Ret_Ok);
res &= (drv_spi_series_sync_send_receive(item->spi, value, len, NULL, 0) == kKit_Ret_Ok);
drv_gpio_set_pin_status(item->cs, kGpioStatus_High);
return res;
}
void drv_w5500_poll(W5500Item *item)
{
static uint8_t link_off_cnt = 0;
uint8_t socket_reg, buf[4];
uint16_t addr, len;
uint32_t i;
if((item->rcv_call != NULL) && (item->server_port != NULL))
{
drv_w5500_read_comm_reg(item, W5500_PHYCFGR_REG_0x2E, buf, 1);
if((buf[0] & 0x01) == 0)
{
buf[1] = (link_off_cnt++ > 10) ? 0x80 : 0;
}
else
{
buf[1] = link_off_cnt = 0;
}
for(i = 0; i < W5500_MAX_SOCKET_NUM; i++)
{
if(buf[1] != 0x80)
{
socket_reg = W5500_CREAT_SOCKET_REG(i);
//读取w5500 socket状态
drv_w5500_read_socket_reg(item, socket_reg, Sn_IR_0x02, buf, 2);
}
else
{
link_off_cnt = 11;
}
switch(buf[1])
{
//建立连接后可能存在有通信数据
case SOCK_ESTABLISHED:
item->close_cnt[i] = 0;
drv_w5500_read_socket_reg(item, socket_reg, Sn_RX_RSR_0x26, buf, 4);
len = READ_BT_INT16U_BY_CONST_POS(buf, 0);
if((len > 0) && (len < W5500_MAX_READ_BUF_SIZE))
{
//获取地址并读数据
addr = READ_BT_INT16U_BY_CONST_POS(buf, 2);
drv_w5500_dma_read_socket_reg(item, W5500_CREAT_SOCKET_READ_BUF(i), addr, item->read_buf, len);
item->rcv_call(i, item->read_buf, len);
addr += len;
WRITE_BT_INT16U_BY_CONST_POS(buf, 0, addr);
drv_w5500_write_socket_reg(item, socket_reg, Sn_RX_RD_0x28, buf, 2);
buf[0] = SOCKET_CMD_RECV;
drv_w5500_write_socket_reg(item, socket_reg, Sn_CR_0x01, buf, 1);
// cnt = buf[0] = 1;
// while((buf[0] != 0) && (cnt++ < 4))
// {
// drv_w5500_read_socket_reg(&w5500, socket_reg, Sn_CR_0x01, buf, 1);
// }
}
break;
case SOCK_CLOSED:
case SOCK_CLOSE_WAIT:
if(item->close_cnt[i]++ >= 5)
{
if((buf[0] & 0x08) == 0x08)
{
buf[0] = 0x08;
item->close_cnt[i] = 0;
drv_w5500_write_socket_reg(item, socket_reg, Sn_IR_0x02, buf, 1);
}
else
{
drv_w5500_close_socket(item, i);
drv_w5500_creat_tcp_server(item, i, item->server_port[i]);
}
}
break;
case SOCK_LISTEN:
item->close_cnt[i] = 0;
break;
case 0x80:
drv_w5500_close_socket(item, i);
break;
default :
break;
}
}
}
}
void drv_w5500_set_close_call(W5500Item *item, W5500CloseCall call)
{
item->close_call = call;
}