mokongking

移植正点原子CH395Q代码

网线连接到电脑上开启DHCP自动获取ip地址,一定要在电脑还是那个开启网络共享,

可看以下链接:原文链接:https://blog.csdn.net/Dontla/article/details/132422418

 

#include "spi.h"


SPI_HandleTypeDef g_spi1_handler; /* SPI1句柄 */


/**
 * @brief       SPI底层驱动,时钟使能,引脚配置
 *   @note      此函数会被HAL_SPI_Init()调用
 * @param       hspi:SPI句柄
 * @retval      无
 */
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    if (hspi->Instance == SPI1_SPI)
    {
        SPI1_SCK_GPIO_CLK_ENABLE();  /* SPI1_SCK脚时钟使能 */
        SPI1_MISO_GPIO_CLK_ENABLE(); /* SPI1_MISO脚时钟使能 */
        SPI1_MOSI_GPIO_CLK_ENABLE(); /* SPI1_MOSI脚时钟使能 */

        /* SCK引脚模式设置(复用输出) */
        gpio_init_struct.Pin = SPI1_SCK_GPIO_PIN;
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;
        gpio_init_struct.Pull = GPIO_PULLUP;
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(SPI1_SCK_GPIO_PORT, &gpio_init_struct);

        /* MISO引脚模式设置(复用输出) */
        gpio_init_struct.Pin = SPI1_MISO_GPIO_PIN;
        HAL_GPIO_Init(SPI1_MISO_GPIO_PORT, &gpio_init_struct);

        /* MOSI引脚模式设置(复用输出) */
        gpio_init_struct.Pin = SPI1_MOSI_GPIO_PIN;
        HAL_GPIO_Init(SPI1_MOSI_GPIO_PORT, &gpio_init_struct);
    }
    
}

/**
 * @brief       SPI初始化代码
 *   @note      主机模式,8位数据,禁止硬件片选
 * @param       无
 * @retval      无
 */
void spi1_init(void)
{
    SPI1_SPI_CLK_ENABLE(); /* SPI1时钟使能 */

    g_spi1_handler.Instance = SPI1_SPI;                                /* SPI1 */
    g_spi1_handler.Init.Mode = SPI_MODE_MASTER;                        /* 设置SPI工作模式,设置为主模式 */
    g_spi1_handler.Init.Direction = SPI_DIRECTION_2LINES;              /* 设置SPI单向或者双向的数据模式:SPI设置为双线模式 */
    g_spi1_handler.Init.DataSize = SPI_DATASIZE_8BIT;                  /* 设置SPI的数据大小:SPI发送接收8位帧结构 */
    g_spi1_handler.Init.CLKPolarity = SPI_POLARITY_HIGH;               /* 串行同步时钟的空闲状态为高电平 */
    g_spi1_handler.Init.CLKPhase = SPI_PHASE_2EDGE;                    /* 串行同步时钟的第二个跳变沿(上升或下降)数据被采样 */
    g_spi1_handler.Init.NSS = SPI_NSS_SOFT;                            /* NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制 */
    g_spi1_handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; /* 定义波特率预分频的值:波特率预分频值为256 */
    g_spi1_handler.Init.FirstBit = SPI_FIRSTBIT_MSB;                   /* 指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始 */
    g_spi1_handler.Init.TIMode = SPI_TIMODE_DISABLE;                   /* 关闭TI模式 */
    g_spi1_handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;   /* 关闭硬件CRC校验 */
    g_spi1_handler.Init.CRCPolynomial = 7;                             /* CRC值计算的多项式 */
    HAL_SPI_Init(&g_spi1_handler);                                     /* 初始化 */
//    spi1_set_speed(SPI_BAUDRATEPRESCALER_2);
    __HAL_SPI_ENABLE(&g_spi1_handler); /* 使能SPI2 */

    spi1_read_write_byte(0Xff); /* 启动传输, 实际上就是产生8个时钟脉冲, 达到清空DR的作用, 非必需 */
}

/**
 * @brief       SPI1速度设置函数
 *   @note      SPI2时钟选择来自APB1, 即PCLK1, 为36Mhz
 *              SPI速度 = PCLK1 / 2^(speed + 1)
 * @param       speed   : SPI2时钟分频系数
                        取值为SPI_BAUDRATEPRESCALER_2~SPI_BAUDRATEPRESCALER_2 256
 * @retval      无
 */
void spi1_set_speed(uint8_t speed)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(speed)); /* 判断有效性 */
    __HAL_SPI_DISABLE(&g_spi1_handler);             /* 关闭SPI */
    g_spi1_handler.Instance->CR1 &= 0XFFC7;         /* 位3-5清零,用来设置波特率 */
    g_spi1_handler.Instance->CR1 |= speed << 3;     /* 设置SPI速度 */
    __HAL_SPI_ENABLE(&g_spi1_handler);              /* 使能SPI */
}

/**
 * @brief       SPI1读写一个字节数据
 * @param       txdata  : 要发送的数据(1字节)
 * @retval      接收到的数据(1字节)
 */
uint8_t spi1_read_write_byte(uint8_t txdata)
{
    uint8_t rxdata;
    HAL_SPI_TransmitReceive(&g_spi1_handler, &txdata, &rxdata, 1, 1000);
    return rxdata; /* 返回收到的数据 */
}
#include "ch395inc.h"
#include "ch395cmd.h"
#include "ch395.h"



/**
 * @brief       复位ch395芯片
 * @param       无
 * @retval      无
 */
void ch395_cmd_reset(void)
{
        ch395_scs_low;
    ch395_write_cmd(CMD00_RESET_ALL);
    ch395_scs_hign;
}

/**
 * @brief       使ch395进入睡眠状态
 * @param       无
 * @retval      无
 */
void ch395_cmd_sleep(void)
{
    ch395_scs_low;
    ch395_write_cmd(CMD00_ENTER_SLEEP);
    ch395_scs_hign;
}

/**
 * @brief       获取芯片以及固件版本号,1字节,高四位表示芯片版本,
 * @param       无
 * @retval      1字节芯片及固件版本号
 */
uint8_t ch395_cmd_get_ver(void)
{
    uint8_t i;
    ch395_scs_low;
    ch395_write_cmd(CMD01_GET_IC_VER);
    i = ch395_read_data();
    ch395_scs_hign;
    return i;
}

/**
 * @brief       测试命令,用于测试硬件以及接口通讯,
 * @param       1字节测试数据
 * @retval      硬件ok,返回 testdata按位取反
 */
uint8_t ch395_cmd_check_exist(uint8_t testdata)
{
    uint8_t i;
        ch395_scs_low;
    ch395_write_cmd(CMD11_CHECK_EXIST);
    ch395_write_data(testdata);
    i = ch395_read_data();
    ch395_scs_hign;
    return i;
}

/**
 * @brief       设置phy,主要设置ch395 phy为100/10m 或者全双工半双工,ch395默为自动协商。
 * @param       参考phy 命令参数/状态
 * @retval      无
 */
void ch395_cmd_set_phy(uint8_t phystat)
{ch395_scs_low;
    ch395_write_cmd(CMD10_SET_PHY);
    ch395_write_data(phystat);
    ch395_scs_hign;
}

/**
 * @brief       获取phy的状态
 * @param       无
 * @retval      当前ch395phy状态,参考phy参数/状态定义
 */
uint8_t ch395_cmd_get_phy_status(void)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD01_GET_PHY_STATUS);
    i = ch395_read_data();
    ch395_scs_hign;
    return i;
}

/**
 * @brief       获取全局中断状态,收到此命令ch395自动取消中断,0x43及以下版本使用
 * @param       无
 * @retval      返回当前的全局中断状态
 */
uint8_t ch395_cmd_get_glob_int_status(void)
{
    uint8_t init_status;
ch395_scs_low;
    ch395_write_cmd(CMD01_GET_GLOB_INT_STATUS);
    init_status = ch395_read_data();
    ch395_scs_hign;
    return  init_status;
}

/**
 * @brief       初始化ch395芯片
 * @param       无
 * @retval      返回执行结果
 */
uint8_t ch395_cmd_init(void)
{
    uint8_t i = 0;
    uint8_t s = 0;
ch395_scs_low;
    ch395_write_cmd(CMD0W_INIT_CH395);
    ch395_scs_hign;

    while (1)
    {
        HAL_Delay(10);                          /* 延时查询,建议2MS以上 */
        s = ch395_get_cmd_status();            /* 不能过于频繁查询 */

        if (s != CH395_ERR_BUSY)
        {
            break;         /* 如果CH395芯片返回忙状态 */
        }

        if (i++ > 200)
        {
            return CH395_ERR_UNKNOW; /* 超时退出,本函数需要500MS以上执行完毕 */
        }
    }

    return s;
}

/**
 * @brief       设置ch395串口波特率,仅在串口模式下有效
 * @param       baudrate 串口波特率
 * @retval      无
 */
void ch395_cmd_set_uart_baud_rate(uint32_t baudrate)
{
    ch395_scs_low;
    ch395_write_cmd(CMD31_SET_BAUDRATE);
    ch395_write_data((uint8_t)baudrate);
    ch395_write_data((uint8_t)((uint16_t)baudrate >> 8));
    ch395_write_data((uint8_t)(baudrate >> 16));
    uint8_t i = ch395_read_data();
    ch395_scs_hign;
}

/**
 * @brief       获取命令执行状态,某些命令需要等待命令执行结果
 * @param       无
 * @retval      返回上一条命令执行状态
 */
uint8_t ch395_get_cmd_status(void)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD01_GET_CMD_STATUS);
    i = ch395_read_data();
    ch395_scs_hign;
    return i;
}

/**
 * @brief       设置ch395的ip地址
 * @param       ipaddr 指ip地址
 * @retval      无
 */
void ch395_cmd_set_ipaddr(uint8_t *ipaddr)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD40_SET_IP_ADDR);

    for (i = 0; i < 4; i++)
    {
        ch395_write_data(*ipaddr++);
    }

    ch395_scs_hign;
}

/**
 * @brief       设置ch395的网关ip地址
 * @param       ipaddr 指向网关ip地址
 * @retval      无
 */
void ch395_cmd_set_gw_ipaddr(uint8_t *gwipaddr)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD40_SET_GWIP_ADDR);

    for (i = 0; i < 4; i++)
    {
        ch395_write_data(*gwipaddr++);
    }

    ch395_scs_hign;
}

/**
 * @brief       设置ch395的子网掩码,默认为255.255.255.0
 * @param       maskaddr 指子网掩码地址
 * @retval      无
 */
void ch395_cmd_set_maskaddr(uint8_t *maskaddr)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD40_SET_MASK_ADDR);

    for (i = 0; i < 4; i++)
    {
        ch395_write_data(*maskaddr++);
    }

    ch395_scs_hign;
}

/**
 * @brief       设置ch395的mac地址。
 * @param       mcaddr mac地址指针
 * @retval      无
 */
void ch395_cmd_set_macaddr(uint8_t *amcaddr)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD60_SET_MAC_ADDR);

    for (i = 0; i < 6; i++)
    {
        ch395_write_data(*amcaddr++);
    }

    ch395_scs_hign;
    HAL_Delay(100);
}

/**
 * @brief       获取ch395的mac地址。
 * @param       amcaddr mac地址指针
 * @retval      无
 */
void ch395_cmd_get_macaddr(uint8_t *amcaddr)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD06_GET_MAC_ADDR);

    for (i = 0; i < 6; i++)
    {
        *amcaddr++ = ch395_read_data();
    }

    ch395_scs_hign;
}

/**
 * @brief       设置mac过滤。
 * @param       filtype 参考 mac过滤
 * @param       table0 hash0
 * @param       table1 hash1
 * @retval      无
 */
void ch395_cmd_set_macfilt(uint8_t filtype, uint32_t table0, uint32_t table1)
{ch395_scs_low;
    ch395_write_cmd(CMD90_SET_MAC_FILT);
    ch395_write_data(filtype);
    ch395_write_data((uint8_t)table0);
    ch395_write_data((uint8_t)((uint16_t)table0 >> 8));
    ch395_write_data((uint8_t)(table0 >> 16));
    ch395_write_data((uint8_t)(table0 >> 24));

    ch395_write_data((uint8_t)table1);
    ch395_write_data((uint8_t)((uint16_t)table1 >> 8));
    ch395_write_data((uint8_t)(table1 >> 16));
    ch395_write_data((uint8_t)(table1 >> 24));
    ch395_scs_hign;
}

/**
 * @brief       获取不可达信息 (ip,port,protocol type)
 * @param       list 保存获取到的不可达
     @arg       第1个字节为不可达代码,请参考 不可达代码(ch395inc.h)
     @arg       第2个字节为ip包协议类型
     @arg       第3-4字节为端口号
     @arg       第4-8字节为ip地址
 * @retval      无
 */
void ch395_cmd_get_unreachippt(uint8_t *list)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD08_GET_UNREACH_IPPORT);

    for (i = 0; i < 8; i++)
    {
        *list++ = ch395_read_data();
    }

    ch395_scs_hign;
}

/**
 * @brief       获取远端的ip和端口地址,一般在tcp server模式下使用
 * @param       sockindex socket索引
 * @param       list 保存ip和端口
 * @retval      无
 */
void ch395_cmd_get_remoteipp(uint8_t sockindex, uint8_t *list)
{
    uint8_t i;
ch395_scs_low;
    ch395_write_cmd(CMD06_GET_REMOT_IPP_SN);
    ch395_write_data(sockindex);

    for (i = 0; i < 6; i++)
    {
        *list++ = ch395_read_data();
    }

    ch395_scs_hign;
}

/**
 * @brief       设置socket n的目的ip地址
 * @param       sockindex socket索引
 * @param       ipaddr 指向ip地址
 * @retval      无
 */
void ch395_set_socket_desip(uint8_t sockindex, uint8_t *ipaddr)
{ch395_scs_low;
    ch395_write_cmd(CMD50_SET_IP_ADDR_SN);
    ch395_write_data(sockindex);
    ch395_write_data(*ipaddr++);
    ch395_write_data(*ipaddr++);
    ch395_write_data(*ipaddr++);
    ch395_write_data(*ipaddr++);
    ch395_scs_hign;
}

/**
 * @brief       设置socket 的协议类型
 * @param       sockindex socket索引,prottype 协议类型
 * @param       请参考 socket协议类型定义(ch395inc.h)
 * @retval      无
 */
void ch395_set_socket_prot_type(uint8_t sockindex, uint8_t prottype)
{ch395_scs_low;
    ch395_write_cmd(CMD20_SET_PROTO_TYPE_SN);
    ch395_write_data(sockindex);
    ch395_write_data(prottype);
    ch395_scs_hign;
}

/**
 * @brief       设置socket n的协议类型
 * @param       sockindex socket索引
 * @param       desprot 2字节目的端口
 * @retval      无
 */
void ch395_set_socket_desport(uint8_t sockindex, uint16_t desprot)
{ch395_scs_low;
    ch395_write_cmd(CMD30_SET_DES_PORT_SN);
    ch395_write_data(sockindex);
    ch395_write_data((uint8_t)desprot);
    ch395_write_data((uint8_t)(desprot >> 8));
    ch395_scs_hign;
}

/**
 * @brief       设置socket n的协议类型
 * @param       sockindex socket索引
 * @param       desprot 2字节源端口
 * @retval      无
 */
void ch395_set_socket_sourport(uint8_t sockindex, uint16_t surprot)
{ch395_scs_low;
    ch395_write_cmd(CMD30_SET_SOUR_PORT_SN);
    ch395_write_data(sockindex);
    ch395_write_data((uint8_t)surprot);
    ch395_write_data((uint8_t)(surprot >> 8));
    ch395_scs_hign;
}

/**
 * @brief       ip模式下,socket ip包协议字段
 * @param       sockindex socket索引
 * @param       prototype ipraw模式1字节协议字段
 * @retval      无
 */
void ch395_set_socket_ipraw_proto(uint8_t sockindex, uint8_t prototype)
{ch395_scs_low;
    ch395_write_cmd(CMD20_SET_IPRAW_PRO_SN);
    ch395_write_data(sockindex);
    ch395_write_data(prototype);
    ch395_scs_hign;
}

/**
 * @brief       开启/关闭 ping
 * @param       senable :0 / 1, 具体含义如下:
 *   @arg       1:  开启ping
 *   @arg       0:  关闭ping
 * @retval      无
 */
void ch395_enable_ping(uint8_t enable)
{ch395_scs_low;
    ch395_write_cmd(CMD01_PING_ENABLE);
    ch395_write_data(enable);
    ch395_scs_hign;
}

/**
 * @brief       向发送缓冲区写数据
 * @param       sockindex socket索引
 * @param       databuf  数据缓冲区
 * @param       len   长度
 * @retval      无
 */
void ch395_send_data(uint8_t sockindex, uint8_t *databuf, uint16_t len)
{
    uint16_t i;
ch395_scs_low;
    ch395_write_cmd(CMD30_WRITE_SEND_BUF_SN);
    ch395_write_data((uint8_t)sockindex);
    ch395_write_data((uint8_t)len);
    ch395_write_data((uint8_t)(len >> 8));

    for (i = 0; i < len; i++)
    {
        ch395_write_data(*databuf++);
    }

    ch395_scs_hign;
}

/**
 * @brief       获取接收缓冲区长度
 * @param       sockindex socket索引
 * @retval      返回接收缓冲区有效长度
 */
uint16_t ch395_get_recv_length(uint8_t sockindex)
{
    uint16_t i;
ch395_scs_low;
    ch395_write_cmd(CMD12_GET_RECV_LEN_SN);
    ch395_write_data((uint8_t)sockindex);
    i = ch395_read_data();
    i = (uint16_t)(ch395_read_data() << 8) + i;
    ch395_scs_hign;
    return i;
}

/**
 * @brief       清除接收缓冲区
 * @param       sockindex socket索引
 * @retval      无
 */
void ch395_clear_recv_buf(uint8_t sockindex)
{ch395_scs_low;
    ch395_write_cmd(CMD10_CLEAR_RECV_BUF_SN);
    ch395_write_data((uint8_t)sockindex);
    ch395_scs_hign;
}

/**
 * @brief       读取接收缓冲区数据
 * @param       sockindex socket索引
 * @param       len  长度
 * @param       pbuf  缓冲区
 * @retval      无
 */
void ch395_get_recv_data(uint8_t sockindex, uint16_t len, uint8_t *pbuf)
{
    uint16_t i;

    if (!len)return;
ch395_scs_low;
    ch395_write_cmd(CMD30_READ_RECV_BUF_SN);
    ch395_write_data(sockindex);
    ch395_write_data((uint8_t)len);
    ch395_write_data((uint8_t)(len >> 8));
    HAL_Delay(1);

    for (i = 0; i < len; i++)
    {
        *pbuf = ch395_read_data();
        pbuf++;
    }

    ch395_scs_hign;
}

/**
 * @brief       设置重试次数
 * @param       count 重试值,最大为20次
 * @retval      无
 */
void ch395_cmd_set_retry_count(uint8_t count)
{ch395_scs_low;
    ch395_write_cmd(CMD10_SET_RETRAN_COUNT);
    ch395_write_data(count);
    ch395_scs_hign;
}

/**
 * @brief       设置重试周期
 * @param       period 重试周期单位为毫秒,最大1000ms
 * @retval      无
 */
void ch395_cmd_set_retry_period(uint16_t period)
{ch395_scs_low;
    ch395_write_cmd(CMD10_SET_RETRAN_COUNT);
    ch395_write_data((uint8_t)period);
    ch395_write_data((uint8_t)(period >> 8));
    ch395_scs_hign;
}

/**
 * @brief       获取socket
 * @param       sockindex socket索引
 * @retval      socket n的状态信息,第1字节为socket 打开或者关闭,第2字节为tcp状态
 */
void ch395_cmd_get_socket_status(uint8_t sockindex, uint8_t *status)
{ch395_scs_low;
    ch395_write_cmd(CMD12_GET_SOCKET_STATUS_SN);
    ch395_write_data(sockindex);
    *status++ = ch395_read_data();
    *status++ = ch395_read_data();
    ch395_scs_hign;
}

/**
 * @brief       打开socket,此命令需要等待执行成功
 * @param       sockindex socket索引
 * @retval      返回执行结果
 */
uint8_t  ch395_open_socket(uint8_t sockindex)
{ch395_scs_low;
    uint8_t i = 0;
    uint8_t s = 0;
    ch395_write_cmd(CMD1W_OPEN_SOCKET_SN);
    ch395_write_data(sockindex);
    ch395_scs_hign;

    while (1)
    {
        HAL_Delay(5);                          /* 延时查询,建议2MS以上 */
        s = ch395_get_cmd_status();           /* 不能过于频繁查询 */

        if (s != CH395_ERR_BUSY)
        {
            break;        /* 如果CH395芯片返回忙状态 */
        }

        if (i++ > 200)
        {
            return CH395_ERR_UNKNOW; /* 超时退出 */
        }
    }

    return s;
}

/**
 * @brief       关闭socket,
 * @param       sockindex socket索引
 * @retval      返回执行结果
 */
uint8_t  ch395_close_socket(uint8_t sockindex)
{ch395_scs_low;
    uint8_t i = 0;
    uint8_t s = 0;
    ch395_write_cmd(CMD1W_CLOSE_SOCKET_SN);
    ch395_write_data(sockindex);
    ch395_scs_hign;

    while (1)
    {
        HAL_Delay(5);                            /* 延时查询,建议2MS以上 */
        s = ch395_get_cmd_status();             /* 不能过于频繁查询 */

        if (s != CH395_ERR_BUSY)
        {
            break;          /* 如果CH395芯片返回忙状态 */
        }

        if (i++ > 200)
        {
            return CH395_ERR_UNKNOW;  /* 超时退出 */
        }
    }

    return s;
}

/**
 * @brief       tcp连接,仅在tcp模式下有效,此命令需要等待执行成功
 * @param       sockindex socket索引
 * @retval      返回执行结果
 */
uint8_t ch395_tcp_connect(uint8_t sockindex)
{ch395_scs_low;
    uint8_t i = 0;
    uint8_t s = 0;
    ch395_write_cmd(CMD1W_TCP_CONNECT_SN);
    ch395_write_data(sockindex);
    ch395_scs_hign;

    while (1)
    {
        HAL_Delay(5);                            /* 延时查询,建议2MS以上 */
        s = ch395_get_cmd_status();             /* 不能过于频繁查询 */

        if (s != CH395_ERR_BUSY)
        {
            break;          /* 如果CH395芯片返回忙状态 */
        }

        if (i++ > 200)
        {
            return CH395_ERR_UNKNOW;  /* 超时退出 */
        }
    }

    return s;
}

/**
 * @brief       tcp监听,仅在tcp模式下有效,此命令需要等待执行成功
 * @param       sockindex socket索引
 * @retval      返回执行结果
 */
uint8_t ch395_tcp_listen(uint8_t sockindex)
{ch395_scs_low;
    uint8_t i = 0;
    uint8_t s = 0;
    ch395_write_cmd(CMD1W_TCP_LISTEN_SN);
    ch395_write_data(sockindex);
    ch395_scs_hign;

    while (1)
    {
        HAL_Delay(5);                           /* 延时查询,建议2MS以上 */
        s = ch395_get_cmd_status();            /* 不能过于频繁查询 */

        if (s != CH395_ERR_BUSY)
        {
            break;         /* 如果CH395芯片返回忙状态 */
        }

        if (i++ > 200)
        {
            return CH395_ERR_UNKNOW; /* 超时退出 */
        }
    }

    return s;
}

/**
 * @brief       tcp断开,仅在tcp模式下有效,此命令需要等待执行成功
 * @param       sockindex socket索引
 * @retval      无
 */
uint8_t ch395_tcp_disconnect(uint8_t sockindex)
{ch395_scs_low;
    uint8_t i = 0;
    uint8_t s = 0;
    ch395_write_cmd(CMD1W_TCP_DISNCONNECT_SN);
    ch395_write_data(sockindex);
    ch395_scs_hign;

    while (1)
    {
        HAL_Delay(5);                           /* 延时查询,建议2MS以上 */
        s = ch395_get_cmd_status();               /* 不能过于频繁查询 */

        if (s != CH395_ERR_BUSY)
        {
            break;         /* 如果CH395芯片返回忙状态 */
        }

        if (i++ > 200)
        {
            return CH395_ERR_UNKNOW; /* 超时退出 */
        }
    }

    return s;
}

/**
 * @brief       获取socket n的中断状态
 * @param       sockindex   socket索引
 * @retval      中断状态
 */
uint8_t ch395_get_socket_int(uint8_t sockindex)
{ch395_scs_low;
    uint8_t intstatus;
    ch395_write_cmd(CMD11_GET_INT_STATUS_SN);
    ch395_write_data(sockindex);
    HAL_Delay(2);
    intstatus = ch395_read_data();
    ch395_scs_hign;
    return intstatus;
}

/**
 * @brief       对多播地址进行crc运算,并取高6位。
 * @param       mac_addr   mac地址
 * @retval      返回crc32的高6位
 */
uint8_t ch395_crcret_6bit(uint8_t *mac_addr)
{ch395_scs_low;
    signed long perbyte;
    signed long perbit;
    const uint32_t poly = 0x04c11db7;
    uint32_t crc_value = 0xffffffff;
    uint8_t c;

    for ( perbyte = 0; perbyte < 6; perbyte ++ )
    {
        c = *(mac_addr++);

        for ( perbit = 0; perbit < 8; perbit++ )
        {
            crc_value = (crc_value << 1) ^ ((((crc_value >> 31)^c) & 0x01) ? poly : 0);
            c >>= 1;
        }
    }

    crc_value = crc_value >> 26;
    return ((uint8_t)crc_value);
}

/**
 * @brief       启动/停止dhcp
 * @param       flag:0 / 1, 具体含义如下:
 *   @arg       1:启动dhcp
 *   @arg       0:停止dhcp
 * @retval      执行状态
 */
uint8_t  ch395_dhcp_enable(uint8_t flag)
{ch395_scs_low;
    uint8_t i = 0;
    uint8_t s;
    ch395_write_cmd(CMD10_DHCP_ENABLE);
    ch395_write_data(flag);
    ch395_scs_hign;

    while (1)
    {
        HAL_Delay(20);
        s = ch395_get_cmd_status();            /* 不能过于频繁查询 */

        if (s != CH395_ERR_BUSY)
        {
            break;         /* 如果ch395芯片返回忙状态 */
        }

        if (i++ > 200)
        {
            return CH395_ERR_UNKNOW; /* 超时退出 */
        }
    }

    return s;
}

/**
 * @brief       获取dhcp状态
 * @param       无
 * @retval      dhcp状态,0为成功,其他值表示错误
 */
uint8_t ch395_get_dhcp_status(void)
{ch395_scs_low;
    uint8_t status;
    ch395_write_cmd(CMD01_GET_DHCP_STATUS);
    status = ch395_read_data();
    ch395_scs_hign;
    return status;
}

/**
 * @brief       获取ip,子网掩码和网关地址
 * @param       sockindex socket索引
 * @retval      12个字节的ip,子网掩码和网关地址
 */
void ch395_get_ipinf(uint8_t *addr)
{ch395_scs_low;
    uint8_t i;
    ch395_write_cmd(CMD014_GET_IP_INF);

    for (i = 0; i < 20; i++)
    {
        *addr++ = ch395_read_data();
    }

    ch395_scs_hign;
}

/**
 * @brief       写gpio寄存器
 * @param       regadd   寄存器地址
 * @param       regval   寄存器值
 * @retval      无
 */
void ch395_write_gpio_addr(uint8_t regadd, uint8_t regval)
{ch395_scs_low;
    ch395_write_cmd(CMD20_WRITE_GPIO_REG);
    ch395_write_data(regadd);
    ch395_write_data(regval);
}

/**
 * @brief       读gpio寄存器
 * @param       regadd   寄存器地址
 * @retval      寄存器的值
 */
uint8_t ch395_read_gpio_addr(uint8_t regadd)
{ch395_scs_low;
    uint8_t i;
    ch395_write_cmd(CMD10_READ_GPIO_REG);
    ch395_write_data(regadd);
    HAL_Delay(1);
    i = ch395_read_data();
    return i;
}

/**
 * @brief       擦除eeprom
 * @param       无
 * @retval      执行状态
 */
uint8_t ch395_eeprom_erase(void)
{ch395_scs_low;
    uint8_t i;
    ch395_write_cmd(CMD00_EEPROM_ERASE);

    while (1)
    {
        HAL_Delay(20);
        i = ch395_get_cmd_status();

        if (i == CH395_ERR_BUSY)
        {
            continue;
        }

        break;
    }

    return i;
}

/**
 * @brief       写eeprom
 * @param       eepaddr  eeprom地址
 * @param       buf      缓冲区地址
 * @param       len      长度
 * @retval      无
 */
uint8_t ch395_eeprom_write(uint16_t eepaddr, uint8_t *buf, uint8_t len)
{ch395_scs_low;
    uint8_t i;
    ch395_write_cmd(CMD30_EEPROM_WRITE);
    ch395_write_data((uint8_t)(eepaddr));
    ch395_write_data((uint8_t)(eepaddr >> 8));
    ch395_write_data(len);

    while (len--)ch395_write_data(*buf++);

    while (1)
    {
        HAL_Delay(20);
        i = ch395_get_cmd_status();

        if (i == CH395_ERR_BUSY)
        {
            continue;
        }

        break;
    }

    return i;
}

/**
 * @brief       写eeprom
 * @param       eepaddr  eeprom地址
 * @param       buf      缓冲区地址
 * @param       len      长度
 * @retval      无
 */
void ch395_eeprom_read(uint16_t eepaddr, uint8_t *buf, uint8_t len)
{
    ch395_write_cmd(CMD30_EEPROM_READ);
    ch395_write_data((uint8_t)(eepaddr));
    ch395_write_data((uint8_t)(eepaddr >> 8));
    ch395_write_data(len);
    HAL_Delay(1);

    while (len--)
    {
        *buf++ = ch395_read_data();
    }
}

/**
 * @brief       设置tcp mss值
 * @param       tcpmss
 * @retval      无
 */
void ch395_set_tcpmss(uint16_t tcpmss)
{
    ch395_write_cmd(CMD20_SET_TCP_MSS);
    ch395_write_data((uint8_t)(tcpmss));
    ch395_write_data((uint8_t)(tcpmss >> 8));
}

/**
 * @brief       设置socket接收缓冲区
 * @param       sockindex  socket索引,址,blknum
 * @param       startblk   起始地
 * @param       单位缓冲区个数 ,单位为512字节
 * @retval      无
 */
void ch395_set_socket_recv_buf(uint8_t sockindex, uint8_t startblk, uint8_t blknum)
{
    ch395_write_cmd(CMD30_SET_RECV_BUF);
    ch395_write_data(sockindex);
    ch395_write_data(startblk);
    ch395_write_data(blknum);
}

/**
 * @brief       设置socket发送缓冲区
 * @param       sockindex  socket索引
 * @param       startblk   起始地址
 * @param       blknum     单位缓冲区个数
 * @retval      无
 */
void ch395_set_socket_send_buf(uint8_t sockindex, uint8_t startblk, uint8_t blknum)
{
    ch395_write_cmd(CMD30_SET_SEND_BUF);
    ch395_write_data(sockindex);
    ch395_write_data(startblk);
    ch395_write_data(blknum);
}

/**
 * @brief       udp向指定的ip和端口发送数据
 * @param       buf     : 发送数据缓冲区
 * @param       len     : 发送数据长度
 * @param       ip      : 目标ip
 * @param       port    : 目标端口
 * @param       sockeid : socket索引值
 * @retval      无
 */
void ch395_udp_send_data(uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint8_t sockindex)
{
    ch395_set_socket_desip(sockindex, ip);   /* 设置socket 0目标IP地址 */
    ch395_set_socket_desport(sockindex, port);
    ch395_send_data(sockindex, buf, len);
}

/**
 * @brief       设置ch395启动参数
 * @param       mdata 设置的参数
 * @retval      无
 */
void ch395_set_start_para(uint32_t mdata)
{
    ch395_write_cmd(CMD40_SET_FUN_PARA);
    ch395_write_data((uint8_t)mdata);
    ch395_write_data((uint8_t)((uint16_t)mdata >> 8));
    ch395_write_data((uint8_t)(mdata >> 16));
    ch395_write_data((uint8_t)(mdata >> 24));
}

/**
 * @brief       获取全局中断状态,收到此命令ch395自动取消中断,0x44及以上版本使用
 * @param       无
 * @retval      返回当前的全局中断状态
 */
uint16_t ch395_cmd_get_glob_int_status_all(void)
{ch395_scs_low;
    uint16_t init_status;
    ch395_write_cmd(CMD02_GET_GLOB_INT_STATUS_ALL);
    HAL_Delay(2);
    init_status = ch395_read_data();
    init_status = (uint16_t)(ch395_read_data() << 8) + init_status;
    ch395_scs_hign;
    return  init_status;
}

/**
 * @brief       设置keepalive功能
 * @param       sockindex socket号
 * @param       cmd 0:关闭 1:开启
 * @retval      无
 */
void ch395_set_keeplive(uint8_t sockindex, uint8_t cmd)
{
    ch395_write_cmd(CMD20_SET_KEEP_LIVE_SN);
    ch395_write_data(sockindex);
    ch395_write_data(cmd);
}

/**
 * @brief       设置keepalive重试次数
 * @param       cnt 重试次数()
 * @retval      无
 */
void ch395_keeplive_cnt(uint8_t cnt)
{
    ch395_write_cmd(CMD10_SET_KEEP_LIVE_CNT);
    ch395_write_data(cnt);
}

/**
 * @brief       设置keeplive空闲
 * @param       idle 空闲时间(单位:ms)
 * @retval      无
 */
void ch395_keeplive_idle(uint32_t idle)
{
    ch395_write_cmd(CMD40_SET_KEEP_LIVE_IDLE);
    ch395_write_data((uint8_t)idle);
    ch395_write_data((uint8_t)((uint16_t)idle >> 8));
    ch395_write_data((uint8_t)(idle >> 16));
    ch395_write_data((uint8_t)(idle >> 24));
}

/**
 * @brief       设置keeplive间隔时间
 * @param       intvl 间隔时间(单位:ms)
 * @retval      无
 */
void ch395_keeplive_intvl(uint32_t intvl)
{
    ch395_write_cmd(CMD40_SET_KEEP_LIVE_INTVL);
    ch395_write_data((uint8_t)intvl);
    ch395_write_data((uint8_t)((uint16_t)intvl >> 8));
    ch395_write_data((uint8_t)(intvl >> 16));
    ch395_write_data((uint8_t)(intvl >> 24));
}

/**
 * @brief       设置ttl
 * @param       ssockindex socket号
 * @param       ttlnum:ttl数
 * @retval      无
 */
void ch395_setttl_num(uint8_t sockindex, uint8_t ttlnum)
{
    ch395_write_cmd(CMD20_SET_TTL);
    ch395_write_data(sockindex);
    ch395_write_data(ttlnum);
}
#include "ch395.h"
#include "spi2.h"


struct ch395q_t g_ch395q_sta;

/**
 * @brief       ch395_gpio初始化
 * @param       无
 * @retval      无
 */
void ch395_gpio_init( void )
{
    GPIO_InitTypeDef gpio_init_struct;

    CH395_SCS_GPIO_CLK_ENABLE();     /* 使能SCS时钟 */
    CH395_INT_GPIO_CLK_ENABLE();     /* 使能INT时钟 */
    CH395_RST_GPIO_CLK_ENABLE();     /* 使能RST时钟 */

    /* SCS */
    gpio_init_struct.Pin = CH395_SCS_GPIO_PIN;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;    /* 推拉输出 */
    HAL_GPIO_Init( CH395_SCS_GPIO_PORT, &gpio_init_struct );

    /* 初始化中断引脚 */
    gpio_init_struct.Pin = CH395_INT_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_INPUT;        /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;            /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;  /* 高速 */
    HAL_GPIO_Init( CH395_INT_GPIO_PORT, &gpio_init_struct );

    gpio_init_struct.Pin = CH395_RST_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;    /* 输出 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;  /* 高速 */
    gpio_init_struct.Pull = GPIO_PULLUP;            /* 上拉 */
    HAL_GPIO_Init( CH395_RST_GPIO_PORT, &gpio_init_struct );
    HAL_GPIO_WritePin(CH395_RST_GPIO_PORT, CH395_RST_GPIO_PIN, GPIO_PIN_SET);
    HAL_Delay(20);
}

/**
 * @brief       硬件SPI输出且输入8个位数据
 * @param       d:将要送入到ch395的数据
 * @retval      无
 */
uint8_t ch395_read_write_byte( uint8_t data )
{
    uint8_t rxdata;
    rxdata = spi1_read_write_byte(data);       /* SPI写入一个CH395Q数据并返回一个数据 */
    return rxdata;                             /* 返回收到的数据 */
}

/**
 * @brief       向ch395写命令
 * @param       将要写入ch395的命令码
 * @retval      无
 */
void ch395_write_cmd( uint8_t mcmd )
{
    ch395_scs_hign;                         /* 防止CS原来为低,先将CS置高 */
    ch395_scs_low;                          /* 命令开始,CS拉低 */
    ch395_read_write_byte(mcmd);            /* SPI发送命令码 */
    HAL_Delay(2);                            /* 必要延时,延时1.5uS确保读写周期不小于1.5uS */

}

/**
 * @brief       向ch395写数据
 * @param       将要写入ch395的数据
 * @retval      无
 */
void ch395_write_data( uint8_t mdata )
{
    ch395_read_write_byte(mdata);           /* SPI发送数据 */
}

/**
 * @brief       从ch395读数据
 * @param       无
 * @retval      返回读取的数据
 */
uint8_t ch395_read_data( void )
{
    uint8_t i;
    i = ch395_read_write_byte(0xff);        /* SPI读数据 */
    return i;
}

/**
 * @brief       ch395_keeplive_set 保活定时器参数设置
 * @param       无
 * @retval      无
 */
void ch395_keeplive_set(void)
{
    ch395_keeplive_cnt(DEF_KEEP_LIVE_CNT);
    ch395_keeplive_idle(DEF_KEEP_LIVE_IDLE);
    ch395_keeplive_intvl(DEF_KEEP_LIVE_PERIOD);
}

/**
 * @brief       ch395 socket配置
 * @param       ch395_sokect:Socket配置信息
 * @retval      无
 */
uint8_t ch395q_socket_config(ch395_socket * ch395_sokect)
{
    if (ch395_sokect == NULL)
    {
        return 0;
    }
    
    if (g_ch395q_sta.dhcp_status == DHCP_UP)                                    /* DHCP获取成功状态 */
    {
        ch395_sokect->net_info.ip[0] = g_ch395q_sta.ipinf_buf[0];
        ch395_sokect->net_info.ip[1] = g_ch395q_sta.ipinf_buf[1];
        ch395_sokect->net_info.ip[2] = g_ch395q_sta.ipinf_buf[2];
        ch395_sokect->net_info.ip[3] = g_ch395q_sta.ipinf_buf[3];
        
        ch395_sokect->net_info.gwip[0] = g_ch395q_sta.ipinf_buf[4];
        ch395_sokect->net_info.gwip[1] = g_ch395q_sta.ipinf_buf[5];
        ch395_sokect->net_info.gwip[2] = g_ch395q_sta.ipinf_buf[6];
        ch395_sokect->net_info.gwip[3] = g_ch395q_sta.ipinf_buf[7];
        
        ch395_sokect->net_info.mask[0] = g_ch395q_sta.ipinf_buf[8];
        ch395_sokect->net_info.mask[1] = g_ch395q_sta.ipinf_buf[9];
        ch395_sokect->net_info.mask[2] = g_ch395q_sta.ipinf_buf[10];
        ch395_sokect->net_info.mask[3] = g_ch395q_sta.ipinf_buf[11];
        
        ch395_sokect->net_info.dns1[0] = g_ch395q_sta.ipinf_buf[12];
        ch395_sokect->net_info.dns1[1] = g_ch395q_sta.ipinf_buf[13];
        ch395_sokect->net_info.dns1[2] = g_ch395q_sta.ipinf_buf[14];
        ch395_sokect->net_info.dns1[3] = g_ch395q_sta.ipinf_buf[15];
        
        ch395_sokect->net_info.dns2[0] = g_ch395q_sta.ipinf_buf[16];
        ch395_sokect->net_info.dns2[1] = g_ch395q_sta.ipinf_buf[17];
        ch395_sokect->net_info.dns2[2] = g_ch395q_sta.ipinf_buf[18];
        ch395_sokect->net_info.dns2[3] = g_ch395q_sta.ipinf_buf[19];
    }
    else                                                                      /* DHCP获取失败状态,设置静态IP地址信息 */
    {
        ch395_cmd_set_ipaddr(ch395_sokect->net_config.ipaddr);                /* 设置CH395的IP地址 */
        ch395_cmd_set_gw_ipaddr(ch395_sokect->net_config.gwipaddr);           /* 设置网关地址 */
        ch395_cmd_set_maskaddr(ch395_sokect->net_config.maskaddr);            /* 设置子网掩码,默认为255.255.255.0*/
        ch395_cmd_init();
        HAL_Delay(10);
    }
    
    ch395_cmd_set_macaddr(ch395_sokect->net_config.macaddr);                  /* 设置MAC地址 */

    memcpy(&g_ch395q_sta.socket[ch395_sokect->socket_index].config, ch395_sokect, sizeof(ch395_socket));
    
    switch(ch395_sokect->proto)
    {
        case CH395Q_SOCKET_UDP:
            /* socket 为UDP模式 */
            ch395_set_socket_desip(ch395_sokect->socket_index, ch395_sokect->des_ip);                                           /* 设置socket 0目标IP地址 */
            ch395_set_socket_prot_type(ch395_sokect->socket_index,  PROTO_TYPE_UDP);                                            /* 设置socket 0协议类型 */
            ch395_set_socket_desport(ch395_sokect->socket_index, ch395_sokect->des_port);                                       /* 设置socket 0目的端口 */
            ch395_set_socket_sourport(ch395_sokect->socket_index, ch395_sokect->sour_port);                                     /* 设置socket 0源端口 */
            g_ch395q_sta.ch395_error(ch395_open_socket(ch395_sokect->socket_index));                                            /* 检查是否成功 */
            break;
        case CH395Q_SOCKET_TCP_CLIENT:
            /* socket 为TCPClient模式 */
            ch395_keeplive_set();                                                                                               /* 保活设置 */
            ch395_set_socket_desip(ch395_sokect->socket_index, ch395_sokect->des_ip);                                           /* 设置socket 0目标IP地址 */
            ch395_set_socket_prot_type(ch395_sokect->socket_index,  PROTO_TYPE_TCP);                                            /* 设置socket 0协议类型 */
            ch395_set_socket_desport(ch395_sokect->socket_index, ch395_sokect->des_port);                                       /* 设置socket 0目的端口 */
            ch395_set_socket_sourport(ch395_sokect->socket_index, ch395_sokect->sour_port);                                     /* 设置socket 0源端口 */
            g_ch395q_sta.ch395_error(ch395_open_socket(ch395_sokect->socket_index));                                            /* 检查sokect是否打开成功 */
            g_ch395q_sta.ch395_error(ch395_tcp_connect(ch395_sokect->socket_index));                                            /* 检查tcp连接是否成功 */
            break;
        case CH395Q_SOCKET_TCP_SERVER:
            /* socket 为TCPServer模式 */
            ch395_set_socket_desip(ch395_sokect->socket_index, ch395_sokect->des_ip);                                           /* 设置socket 0目标IP地址 */
            ch395_set_socket_prot_type(ch395_sokect->socket_index,  PROTO_TYPE_TCP);                                            /* 设置socket 0协议类型 */
            ch395_set_socket_sourport(ch395_sokect->socket_index, ch395_sokect->sour_port);                                     /* 设置socket 0源端口 */
            g_ch395q_sta.ch395_error(ch395_open_socket(ch395_sokect->socket_index));                                            /* 检查sokect是否打开成功 */
            g_ch395q_sta.ch395_error(ch395_tcp_listen(ch395_sokect->socket_index));                                             /* 监听tcp连接 */
            break;
        case CH395Q_SOCKET_MAC_RAW:
            ch395_set_socket_prot_type(ch395_sokect->socket_index,  PROTO_TYPE_MAC_RAW);                                        /* 设置socket 0协议类型 */
            g_ch395q_sta.ch395_error(ch395_open_socket(ch395_sokect->socket_index));                                            /* 检查sokect是否打开成功 */
            break;
    }
    
    return 1;
}
 
/**
 * @brief       调试使用,显示错误代码,并停机
 * @param       ierror 检测命令
 * @retval      无
 */
void ch395_error(uint8_t ierror)
{
    if (ierror == CMD_ERR_SUCCESS)
    {
        return;          /* 操作成功 */
    }
    
    printf("Error: %02X\r\n", (uint16_t)ierror);    /* 显示错误 */
    
    while ( 1 )
    {
        HAL_Delay(200);
        HAL_Delay(200);
    }
}

/**
 * @brief       CH395 PHY状态   
 * @param       phy_status:PHY状态值
 * @retval      无
 */
void ch395_phy_status(uint8_t phy_status)
{
    switch (phy_status)
    {
        case PHY_DISCONN:
            printf("PHY DISCONN\r\n");
            break;
        case PHY_10M_FLL:
            printf("PHY 10M_FLL\r\n");
            break;
        case PHY_10M_HALF:
            printf("PHY 10M_HALF\r\n");
            break;
        case PHY_100M_FLL:
            printf("PHY 100M_FLL\r\n");
            break;
        case PHY_100M_HALF:
            printf("PHY 100M_HALF\r\n");
            break;
        default:
            printf("PHY AUTO\r\n");
            break;
    }
    
    HAL_Delay(1000);
}

/**
 * @brief      设置socket接口的接收与发送缓冲区
 * @param      无
 * @retval     无
 */
void ch395_socket_r_s_buf_modify(void)
{

   ch395_set_socket_recv_buf(0,0,4);                                                            /* Socket 0 ,接收缓冲区4*512 = 2K,发送缓冲区2*512 = 1K*/
   ch395_set_socket_send_buf(0,4,2);  
  
   ch395_set_socket_recv_buf(1,6,4);                                                            /* Socket 1 */
   ch395_set_socket_send_buf(1,10,2);  
  
   ch395_set_socket_recv_buf(2,12,4);                                                           /* Socket 2 */
   ch395_set_socket_send_buf(2,16,2);  
  
   ch395_set_socket_recv_buf(3,18,4);                                                           /* Socket 3 */
   ch395_set_socket_send_buf(3,22,2);  
  
   ch395_set_socket_recv_buf(4,24,4);                                                           /* Socket 4 */
   ch395_set_socket_send_buf(4,28,2);  
  
   ch395_set_socket_recv_buf(5,30,4);                                                           /* Socket 5 */
   ch395_set_socket_send_buf(5,34,2);
  
   ch395_set_socket_recv_buf(6,36,4);                                                           /* Socket 6 */
   ch395_set_socket_send_buf(6,40,2);  
  
   ch395_set_socket_recv_buf(7,42,4);                                                           /* Socket 7 */
   ch395_set_socket_send_buf(7,46,2);  

}

/**
 * @brief      ch395_tcp初始化
 * @param      无
 * @retval     无
 */
void ch395_hardware_init(void)
{
    uint8_t i;
    ch395_gpio_init();
    spi1_init();

    g_ch395q_sta.ch395_error = ch395_error;
    g_ch395q_sta.ch395_phy_cb = ch395_phy_status;
    g_ch395q_sta.ch395_reconnection = ch395_reconnection;
    g_ch395q_sta.dhcp_status = DHCP_STA;
    
    i = ch395_cmd_check_exist(0x65);                                                            /* 测试命令,用于测试硬件以及接口通讯 */
        HAL_Delay(5);
    if (i != 0x9a)
    {
        g_ch395q_sta.ch395_error(i);                                                            /* ch395q检测错误 */
    }
    
    ch395_cmd_reset();                                                                          /* 对ch395q复位 */
    HAL_Delay(100);                                                                              /* 这里必须等待100以上延时 */
    
    g_ch395q_sta.ch395_error(ch395_cmd_init());                                                 /* 初始化ch395q命令 */
    ch395_socket_r_s_buf_modify();
//    ch395_set_tcpmss(536);
//    ch395_set_start_para(FUN_PARA_FLAG_TCP_SERVER | SOCK_CTRL_FLAG_SOCKET_CLOSE);
    
    do
    {
        g_ch395q_sta.phy_status = ch395_cmd_get_phy_status();                                   /* 获取PHY状态 */ 
        g_ch395q_sta.ch395_phy_cb(g_ch395q_sta.phy_status);                                     /* 判断双工和网速模式 */ 
    }
    while(g_ch395q_sta.phy_status == PHY_DISCONN);
    
    g_ch395q_sta.version = ch395_cmd_get_ver();                                                 /* 获取版本 */
    printf("CH395VER : %2x\r\n", (uint16_t)g_ch395q_sta.version);
    
    i = ch395_dhcp_enable(1);                                                                   /* 开启DHCP */
    g_ch395q_sta.ch395_error(i);                                                                /* ch395q检测错误 */
    
    HAL_Delay(1000);                                                                             /* ch395q初始化延时 */
}

/**
 * @brief       CH395 socket 中断,在全局中断中被调用
 * @param       sockindex (0~7)
 * @retval      无
 */
void ch395_socket_interrupt(uint8_t sockindex)
{
    uint8_t  sock_int_socket;
    uint16_t rx_len = 0;
    
    sock_int_socket = ch395_get_socket_int(sockindex);                                          /* 获取socket 的中断状态 */

    if (sock_int_socket & SINT_STAT_SENBUF_FREE)                                                /* 发送缓冲区空闲,可以继续写入要发送的数据 */
    {
        
    }

    if (sock_int_socket & SINT_STAT_SEND_OK)                                                    /* 发送完成中断 */
    {
        
    }

    if (sock_int_socket & SINT_STAT_RECV)                                                       /* 接收中断 */
    {
        g_ch395q_sta.socket[sockindex].config.recv.size = ch395_get_recv_length(sockindex);     /* 获取当前缓冲区内数据长度 */
        rx_len = g_ch395q_sta.socket[sockindex].config.recv.size;
        ch395_get_recv_data(sockindex, rx_len, g_ch395q_sta.socket[sockindex].config.recv.buf); /* 读取数据 */
        g_ch395q_sta.socket[sockindex].config.recv.buf[rx_len] = '\0';
        printf("%s", g_ch395q_sta.socket[sockindex].config.recv.buf);
        g_ch395q_sta.socket[sockindex].config.recv.recv_flag |= 0x04;
    }

    if (sock_int_socket & SINT_STAT_CONNECT)                                                    /* 连接中断,仅在TCP模式下有效 */
    {
        if (g_ch395q_sta.socket[sockindex].config.proto == CH395Q_SOCKET_TCP_CLIENT)
        {
            ch395_set_keeplive(sockindex,1);                                                    /* 打开KEEPALIVE保活定时器 */
            ch395_setttl_num(sockindex,60);                                                     /* 设置TTL */
        }
    }

    if (sock_int_socket & SINT_STAT_DISCONNECT)                                                 /* 断开中断,仅在TCP模式下有效 */
    {
        g_ch395q_sta.ch395_error(ch395_open_socket(g_ch395q_sta.socket[sockindex].config.socket_index));
        
        switch(g_ch395q_sta.socket[sockindex].config.proto)
        {
            case CH395Q_SOCKET_TCP_CLIENT:
                g_ch395q_sta.ch395_error(ch395_tcp_connect(g_ch395q_sta.socket[sockindex].config.socket_index));
                break;
            case CH395Q_SOCKET_TCP_SERVER:
                g_ch395q_sta.ch395_error(ch395_tcp_listen(g_ch395q_sta.socket[sockindex].config.socket_index));
                break;
            default:
                break;
        }
        HAL_Delay(200);                                                                          /* 延时200MS后再次重试,没有必要过于频繁连接 */
    }

    if (sock_int_socket & SINT_STAT_TIM_OUT)                                                    /* 超时中断,仅在TCP模式下有效 */
    {
        if (g_ch395q_sta.socket[sockindex].config.proto == CH395Q_SOCKET_TCP_CLIENT)
        {
            HAL_Delay(200);                                                                      /* 延时200MS后再次重试,没有必要过于频繁连接 */
            g_ch395q_sta.ch395_error(ch395_open_socket(g_ch395q_sta.socket[sockindex].config.socket_index));
            g_ch395q_sta.ch395_error(ch395_tcp_connect(g_ch395q_sta.socket[sockindex].config.socket_index));
        }
    }
}

/**
 * @brief       CH395全局中断函数
 * @param       无
 * @retval      无
 */
void ch395_interrupt_handler(void)
{
    uint16_t  init_status;
    uint8_t i;
    
    init_status = ch395_cmd_get_glob_int_status_all();

    if (init_status & GINT_STAT_UNREACH)                                    /* 不可达中断,读取不可达信息 */
    {
         ch395_cmd_get_unreachippt(g_ch395q_sta.ipinf_buf);
    }

    if (init_status & GINT_STAT_IP_CONFLI)                                  /* 产生IP冲突中断,建议重新修改CH395的 IP,并初始化CH395 */
    {
        
    }

    if (init_status & GINT_STAT_PHY_CHANGE)                                 /* 产生PHY改变中断 */
    {
        g_ch395q_sta.phy_status = ch395_cmd_get_phy_status();               /* 获取PHY状态 */
    }

    if (init_status & GINT_STAT_DHCP)                                       /* 处理DHCP中断 */
    {

        i = ch395_get_dhcp_status();
        
        switch (i)
        {
            case DHCP_UP:
                ch395_get_ipinf(g_ch395q_sta.ipinf_buf);
                printf("IP:%02d.%02d.%02d.%02d\r\n", (uint16_t)g_ch395q_sta.ipinf_buf[0], (uint16_t)g_ch395q_sta.ipinf_buf[1], (uint16_t)g_ch395q_sta.ipinf_buf[2], (uint16_t)g_ch395q_sta.ipinf_buf[3]);
                printf("GWIP:%02d.%02d.%02d.%02d\r\n", (uint16_t)g_ch395q_sta.ipinf_buf[4], (uint16_t)g_ch395q_sta.ipinf_buf[5], (uint16_t)g_ch395q_sta.ipinf_buf[6], (uint16_t)g_ch395q_sta.ipinf_buf[7]);
                printf("Mask:%02d.%02d.%02d.%02d\r\n", (uint16_t)g_ch395q_sta.ipinf_buf[8], (uint16_t)g_ch395q_sta.ipinf_buf[9], (uint16_t)g_ch395q_sta.ipinf_buf[10], (uint16_t)g_ch395q_sta.ipinf_buf[11]);
                printf("DNS1:%02d.%02d.%02d.%02d\r\n", (uint16_t)g_ch395q_sta.ipinf_buf[12], (uint16_t)g_ch395q_sta.ipinf_buf[13], (uint16_t)g_ch395q_sta.ipinf_buf[14], (uint16_t)g_ch395q_sta.ipinf_buf[15]);
                printf("DNS2:%02d.%02d.%02d.%02d\r\n", (uint16_t)g_ch395q_sta.ipinf_buf[16], (uint16_t)g_ch395q_sta.ipinf_buf[17], (uint16_t)g_ch395q_sta.ipinf_buf[18], (uint16_t)g_ch395q_sta.ipinf_buf[19]);
                g_ch395q_sta.dhcp_status = DHCP_UP;
                break;
            default:
                g_ch395q_sta.dhcp_status = DHCP_DOWN;
                /* 设置默认IP地址信息 */
                printf("静态IP信息.....................................\r\n");
                break;
        }
    }

    if (init_status & GINT_STAT_SOCK0)
    {
        ch395_socket_interrupt(CH395Q_SOCKET_0);                          /* 处理socket 0中断 */
    }

    if (init_status & GINT_STAT_SOCK1)
    {
        ch395_socket_interrupt(CH395Q_SOCKET_1);                          /* 处理socket 1中断 */
    }

    if (init_status & GINT_STAT_SOCK2)
    {
        ch395_socket_interrupt(CH395Q_SOCKET_2);                          /* 处理socket 2中断 */
    }

    if (init_status & GINT_STAT_SOCK3)
    {
        ch395_socket_interrupt(CH395Q_SOCKET_3);                          /* 处理socket 3中断 */
    }

    if (init_status & GINT_STAT_SOCK4)
    {
        ch395_socket_interrupt(CH395Q_SOCKET_4);                          /* 处理socket 4中断 */
    }

    if (init_status & GINT_STAT_SOCK5)
    {
        ch395_socket_interrupt(CH395Q_SOCKET_5);                          /* 处理socket 5中断 */
    }

    if (init_status & GINT_STAT_SOCK6)
    {
        ch395_socket_interrupt(CH395Q_SOCKET_6);                          /* 处理socket 6中断 */
    }

    if (init_status & GINT_STAT_SOCK7)
    {
        ch395_socket_interrupt(CH395Q_SOCKET_7);                          /* 处理socket 7中断 */
    }
}

/**
 * @brief       CH395全局管理函数
 * @param       无
 * @retval      无
 */
void ch395q_handler(void)
{
    if (ch395_int_pin_wire == 0)
    {
        ch395_interrupt_handler();                                       /* 中断处理函数 */
    }
    
    g_ch395q_sta.ch395_reconnection();                                   /* 检测PHY状态,并重新连接 */
}

/**
 * @brief       检测PHY状态,并重新连接
 * @param       无
 * @retval      无
 */
void ch395_reconnection(void)
{
    for (uint8_t socket_index = CH395Q_SOCKET_0 ; socket_index <= CH395Q_SOCKET_7 ; socket_index ++ )
    {
        if (g_ch395q_sta.phy_status == PHY_DISCONN && (g_ch395q_sta.dhcp_status == DHCP_UP || g_ch395q_sta.dhcp_status == DHCP_DOWN || g_ch395q_sta.dhcp_status == DHCP_STA))
        {
            if (g_ch395q_sta.socket[socket_index].config.socket_enable == CH395Q_ENABLE)
            {
                ch395_close_socket(g_ch395q_sta.socket[socket_index].config.socket_index);
                g_ch395q_sta.ch395_error(ch395_dhcp_enable(0));                                                                 /* ch395q检测错误 */
                g_ch395q_sta.socket[socket_index].config.socket_enable = CH395Q_DISABLE;
                g_ch395q_sta.dhcp_status = DHCP_STA;
            }
        }
        else
        {
            if (g_ch395q_sta.phy_status != PHY_DISCONN && g_ch395q_sta.socket[socket_index].config.socket_enable == CH395Q_DISABLE)
            {
                if (g_ch395q_sta.dhcp_status == DHCP_STA)
                {
                    ch395_cmd_reset();                                                                                          /* 对ch395q复位 */
                    HAL_Delay(100);                                                                                              /* 这里必须等待100以上延时 */
                    ch395_cmd_init();
                    HAL_Delay(100);                                                                                              /* 这里必须等待100以上延时 */
                    ch395_socket_r_s_buf_modify();
//                    ch395_set_tcpmss(536);
//                    ch395_set_start_para(FUN_PARA_FLAG_TCP_SERVER | SOCK_CTRL_FLAG_SOCKET_CLOSE);
                    g_ch395q_sta.ch395_error(ch395_dhcp_enable(1));                                                             /* 开启DHCP */
                }
                
                do
                {
                    if (ch395_int_pin_wire == 0)
                    {
                        ch395_interrupt_handler();                                                                              /* 中断处理函数 */
                    }
                }
                while (g_ch395q_sta.dhcp_status == DHCP_STA);                                                                   /* 获取DHCP */
                
                switch(g_ch395q_sta.socket[socket_index].config.proto)
                {
                    case CH395Q_SOCKET_UDP:
                        /* socket 为UDP模式 */
                        ch395_set_socket_desip(socket_index, g_ch395q_sta.socket[socket_index].config.des_ip);                  /* 设置socket 0目标IP地址 */
                        ch395_set_socket_prot_type(socket_index,  PROTO_TYPE_UDP);                                              /* 设置socket 0协议类型 */
                        ch395_set_socket_desport(socket_index, g_ch395q_sta.socket[socket_index].config.des_port);              /* 设置socket 0目的端口 */
                        ch395_set_socket_sourport(socket_index, g_ch395q_sta.socket[socket_index].config.sour_port);            /* 设置socket 0源端口 */
                        g_ch395q_sta.ch395_error(ch395_open_socket(socket_index));                                              /* 检查是否成功 */
                        break;
                    case CH395Q_SOCKET_TCP_CLIENT:
                        /* socket 为TCPClient模式 */
                        ch395_keeplive_set();                                                                                   /* 保活设置 */
                        ch395_set_socket_desip(socket_index, g_ch395q_sta.socket[socket_index].config.des_ip);                  /* 设置socket 0目标IP地址 */
                        ch395_set_socket_prot_type(socket_index,  PROTO_TYPE_TCP);                                              /* 设置socket 0协议类型 */
                        ch395_set_socket_desport(socket_index,g_ch395q_sta.socket[socket_index].config.des_port);               /* 设置socket 0目的端口 */
                        ch395_set_socket_sourport(socket_index,g_ch395q_sta.socket[socket_index].config.sour_port);             /* 设置socket 0源端口 */
                        g_ch395q_sta.ch395_error(ch395_open_socket(socket_index));                                              /* 检查sokect是否打开成功 */
                        g_ch395q_sta.ch395_error(ch395_tcp_connect(socket_index));                                              /* 检查tcp连接是否成功 */
                        break;
                    case CH395Q_SOCKET_TCP_SERVER:
                        /* socket 为TCPServer模式 */
                        ch395_set_socket_desip(socket_index, g_ch395q_sta.socket[socket_index].config.des_ip);                  /* 设置socket 0目标IP地址 */
                        ch395_set_socket_prot_type(socket_index,  PROTO_TYPE_TCP);                                              /* 设置socket 0协议类型 */
                        ch395_set_socket_sourport(socket_index, g_ch395q_sta.socket[socket_index].config.sour_port);            /* 设置socket 0源端口 */
                        g_ch395q_sta.ch395_error(ch395_open_socket(socket_index));                                              /* 检查sokect是否打开成功 */
                        g_ch395q_sta.ch395_error(ch395_tcp_listen(socket_index));                                               /* 监听tcp连接 */
                        break;
                    case CH395Q_SOCKET_MAC_RAW:
                        ch395_set_socket_prot_type(socket_index,  PROTO_TYPE_MAC_RAW);                                          /* 设置socket 0协议类型 */
                        g_ch395q_sta.ch395_error(ch395_open_socket(socket_index));                                              /* 检查sokect是否打开成功 */
                        break;
                    default:
                        ch395_set_socket_prot_type(socket_index,  PROTO_TYPE_TCP);
                        ch395_set_socket_sourport(socket_index, 8080);                                                          /* 设置socket 1~7源端口 */
                        break;
                }
                g_ch395q_sta.socket[socket_index].config.socket_enable = CH395Q_ENABLE;
            }
        }
    }
}
#ifndef __CH395_H
#define __CH395_H
#include "ch395inc.h"
#include "main.h"

#include "ch395inc.h"
#include "ch395cmd.h"

#include "string.h"
#include "stdio.h"


/******************************************************************************************/
/* 引脚 定义 */

#define CH395_SCS_GPIO_PORT                  GPIOG
#define CH395_SCS_GPIO_PIN                   GPIO_PIN_9
#define CH395_SCS_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)            /* PG口时钟使能 */

#define CH395_INT_GPIO_PORT                  GPIOG
#define CH395_INT_GPIO_PIN                   GPIO_PIN_6
#define CH395_INT_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)            /* PG口时钟使能 */

#define CH395_RST_GPIO_PORT                  GPIOD
#define CH395_RST_GPIO_PIN                   GPIO_PIN_7
#define CH395_RST_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)            /* PD口时钟使能 */

/******************************************************************************************/
#define ch395_scs_low                        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_9, GPIO_PIN_RESET)   /* SPI片选引脚输出低电平 */
#define ch395_scs_hign                       HAL_GPIO_WritePin(GPIOG, GPIO_PIN_9, GPIO_PIN_SET)     /* SPI片选引脚输出高电平 */
#define ch395_sdo_pin                        HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)                     /* 获取CH395的SPI数据输出引脚电平 */
#define ch395_int_pin_wire                   HAL_GPIO_ReadPin(GPIOG,GPIO_PIN_6)                     /* 假定CH395的INT#引脚,如果未连接那么也可以通过查询兼做中断输出的SDO引脚状态实现 */


typedef struct ch395q_socket_t
{
    uint8_t socket_enable;                                          /* Socket使能 */
    uint8_t socket_index;                                           /* Socket标号 */
    uint8_t proto;                                                  /* Socket协议 */
    uint8_t des_ip[4];                                              /* 目的IP地址 */
    uint16_t des_port;                                              /* 目的端口 */
    uint16_t sour_port;                                             /* 源端口 */
    
    struct
    {
        uint8_t *buf;                                               /* 缓冲空间 */
        uint32_t size;                                              /* 缓冲空间大小 */
    } send;                                                         /* 发送缓冲 */
    
    struct
    {
        uint8_t recv_flag;                                          /* 接收数据标志位 */
        uint8_t *buf;                                               /* 缓冲空间 */
        uint32_t size;                                              /* 缓冲空间大小 */
    } recv;                                                         /* 接收缓冲 */
    
    struct
    {
        uint8_t ip[4];                                              /* IP地址 */
        uint8_t gwip[4];                                            /* 网关IP地址 */
        uint8_t mask[4];                                            /* 子网掩码 */
        uint8_t dns1[4];                                            /* DNS服务器1地址 */
        uint8_t dns2[4];                                            /* DNS服务器2地址 */
    } net_info;                                                     /* 网络信息 */
    
    struct
    {
        uint8_t ipaddr[4];                                          /* IP地址 32bit*/
        uint8_t gwipaddr[4];                                        /* 网关地址 32bit*/
        uint8_t maskaddr[4];                                        /* 子网掩码 32bit*/
        uint8_t macaddr[6];                                         /* MAC地址 48bit*/
    } net_config;                                                   /* 网络配置信息 */

} ch395_socket;

/* DHCP状态 */
enum DHCP
{
    DHCP_UP = 0,                                                    /* DHCP获取成功状态 */
    DHCP_DOWN,                                                      /* DHCP获取失败状态 */
    DHCP_STA,                                                       /* DHCP开启状态 */
};

struct ch395q_t
{
    uint8_t version;                                                /* 版本信息 */
    uint8_t phy_status;                                             /* PHY状态 */
    uint8_t dhcp_status;                                            /* DHCP状态 */
    uint8_t  ipinf_buf[20];                                         /* 获取IP信息 */
    
    struct
    {
        ch395_socket config;                                        /* 配置信息 */
    } socket[8];                                                    /* Socket状态 */
    
    void (*ch395_error)(uint8_t i);                                 /* ch395q错误检测函数 */
    void (*ch395_phy_cb)(uint8_t phy_status);                       /* ch395q phy状态回调函数 */
    void (*ch395_reconnection)(void);                               /* ch395q 重新连接函数 */
};

extern struct ch395q_t g_ch395q_sta;

/* CH395Q模块Socket标号定义 */
#define CH395Q_SOCKET_0             0                               /* Socket 0 */
#define CH395Q_SOCKET_1             1                               /* Socket 1 */
#define CH395Q_SOCKET_2             2                               /* Socket 2 */
#define CH395Q_SOCKET_3             3                               /* Socket 3 */
#define CH395Q_SOCKET_4             4                               /* Socket 4 */
#define CH395Q_SOCKET_5             5                               /* Socket 5 */
#define CH395Q_SOCKET_6             6                               /* Socket 6 */
#define CH395Q_SOCKET_7             7                               /* Socket 7 */

/* 使能定义 */
#define CH395Q_DISABLE              1                               /* 禁用 */
#define CH395Q_ENABLE               2                               /* 使能 */

/* CH395Q模块Socket协议类型定义 */
#define CH395Q_SOCKET_UDP           0                               /* UDP */
#define CH395Q_SOCKET_TCP_CLIENT    1                               /* TCP客户端 */
#define CH395Q_SOCKET_TCP_SERVER    2                               /* TCP服务器 */
#define CH395Q_SOCKET_MAC_RAW       3                               /* MAC_RAW */

#define DEF_KEEP_LIVE_IDLE          (15*1000)                       /* 空闲时间 */
#define DEF_KEEP_LIVE_PERIOD        (15*1000)                       /* 间隔为15秒,发送一次KEEPLIVE数据包 */
#define DEF_KEEP_LIVE_CNT           200

uint8_t  ch395_read_data(void ) ;
void ch395_write_cmd( uint8_t mcmd );
void ch395_write_data( uint8_t mdata );
void ch395q_handler(void);
void ch395_interrupt_handler(void);
void ch395_hardware_init(void);
uint8_t ch395q_socket_config(ch395_socket * ch395_sokect);
void ch395_reconnection(void);

#endif
#ifndef __CH395CMD_H__
#define __CH395CMD_H__
#include "ch395inc.h"
#include "main.h"


void ch395_cmd_reset(void);                                                                             /* 复位 */

void ch395_cmd_sleep(void);                                                                             /* 睡眠 */

uint8_t ch395_cmd_get_ver(void);                                                                        /* 获取芯片及固件版本号 */

uint8_t ch395_cmd_check_exist(uint8_t testdata);                                                        /* 测试命令 */

void ch395_cmd_set_phy(uint8_t phystat);                                                                /* 设置phy状态  */

uint8_t ch395_cmd_get_phy_status(void);                                                                 /* 获取phy状态 */

uint8_t ch395_cmd_get_glob_int_status(void);                                                            /* 获取ch395全局中断状态 */

uint8_t ch395_cmd_init(void);                                                                           /* 初始化ch395 */

void ch395_cmd_set_uart_baud_rate(uint32_t baudrate);                                                   /* 设置波特率 */

uint8_t ch395_get_cmd_status(void);                                                                     /* 获取命令执行状态 */

void ch395_cmd_set_ipaddr(uint8_t *ipaddr);                                                             /* 设置ch395的ip地址 */

void ch395_cmd_set_gw_ipaddr(uint8_t *gwipaddr);                                                        /* 设置ch395的网关ip地址 */

void ch395_cmd_set_maskaddr(uint8_t *maskaddr);                                                         /* 设置子网掩码 */

void ch395_cmd_set_macaddr(uint8_t *amcaddr);                                                           /* 设置ch395的mac地址 */

void ch395_cmd_get_macaddr(uint8_t *amcaddr);                                                           /* 获取mac地址 */

void ch395_cmd_set_macfilt(uint8_t filtype, uint32_t table0, uint32_t table1);                          /* 设置ch395的mac过滤 */

void ch395_cmd_get_unreachippt(uint8_t *list);                                                          /* 获取不可达地址以及端口 */

void ch395_cmd_get_remoteipp(uint8_t sockindex, uint8_t *list);                                         /* 获取远端ip和端口,一般在tcp server下使用 */

void ch395_set_socket_desip(uint8_t sockindex, uint8_t *ipaddr);                                        /* 设置scoket n的目的ip地址 */

void ch395_set_socket_prot_type(uint8_t sockindex, uint8_t prottype);                                   /* 设置socket n的协议类型 */

void ch395_set_socket_desport(uint8_t sockindex, uint16_t desprot);                                     /* 设置socket n的目的端口 */

void ch395_set_socket_sourport(uint8_t sockindex, uint16_t surprot);                                    /* 设置socket n的源端口 */

void ch395_set_socket_ipraw_proto(uint8_t sockindex, uint8_t prototype);                                /* 在ipraw模式下,设置socket n的ip包协议字段 */

void ch395_set_recv_threslen(uint8_t sockindex, uint16_t len);                                          /* 设置socket n的接收中断阀值 */

void ch395_send_data(uint8_t sockindex, uint8_t *databuf, uint16_t len);                                /* 向socket n的发送缓冲区写数据 */

uint16_t ch395_get_recv_length(uint8_t sockindex);                                                      /* 获取socket n的接收长度 */

void ch395_clear_recv_buf(uint8_t sockindex);                                                           /* 清除socket n的接收缓冲区 */

void ch395_get_recv_data(uint8_t sockindex, uint16_t len, uint8_t *pbuf);                               /* 获取接收数据 */

void ch395_cmd_set_retry_count(uint8_t count);                                                          /* 设置最大重试次数 */

void ch395_cmd_set_retry_period(uint16_t period);                                                       /* 设置最大重试周期 单位 毫秒 */

void ch395_cmd_get_socket_status(uint8_t sockindex, uint8_t *status) ;                                  /* 获取socket n的状态 */

uint8_t  ch395_open_socket(uint8_t sockindex);                                                          /* 打开socket n*/

uint8_t  ch395_close_socket(uint8_t sockindex);                                                         /* 关闭socket n*/

uint8_t ch395_tcp_connect(uint8_t sockindex);                                                           /* tcp连接 */

uint8_t ch395_tcp_listen(uint8_t sockindex);                                                            /* tcp监听 */

uint8_t ch395_tcp_disconnect(uint8_t sockindex);                                                        /* tcp断开连接 */

uint8_t ch395_get_socket_int(uint8_t sockindex);                                                        /* 获取socket n的中断状态 */

uint8_t ch395_crcret_6bit(uint8_t *mac_addr);                                                           /* 多播地址crc32,用于hash过滤 function count = 36 */

void ch395_get_ipinf(uint8_t *addr);                                                                    /* 获取ip,子网掩码和网关地址 */

uint8_t ch395_get_dhcp_status(void);                                                                    /* 获取dhcp状态 */

uint8_t  ch395_dhcp_enable(uint8_t flag);                                                               /* 启动/停止dhcp */

void ch395_write_gpio_addr(uint8_t regadd, uint8_t regval);                                             /* 写gpio寄存器 */

uint8_t ch395_read_gpio_addr(uint8_t regadd);                                                           /* 读gpio寄存器 */

uint8_t ch395_eeprom_erase(void);                                                                       /* 擦除eeprom */

uint8_t ch395_eeprom_write(uint16_t eepaddr, uint8_t *buf, uint8_t len);                                /* 写eeprom */

void ch395_eeprom_read(uint16_t eepaddr, uint8_t *buf, uint8_t len);                                    /* 读eeprom */

void ch395_set_tcpmss(uint16_t tcpmss);                                                                 /* 设置tcp mss值 */

void ch395_set_socket_recv_buf(uint8_t sockindex, uint8_t startblk, uint8_t blknum);                    /* 设置socket接收缓冲区 */

void ch395_set_socket_send_buf(uint8_t sockindex, uint8_t startblk, uint8_t blknum);                    /* 设置socket发送缓冲区 */

void ch395_udp_send_data(uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint8_t sockindex);    /* udp向指定的ip和端口发送数据 */

void ch395_set_start_para(uint32_t mdata);                                                              /* 设置ch395启动参数 */

uint16_t ch395_cmd_get_glob_int_status_all(void);                                                       /* 获取全局中断状态,收到此命令ch395自动取消中断,0x44及以上版本使用 */

void ch395_keeplive_idle(uint32_t idle);                                                                /* 设置keeplive空闲 */

void ch395_keeplive_intvl(uint32_t intvl);                                                              /* 设置keeplive间隔时间 */

void ch395_keeplive_cnt(uint8_t cnt);                                                                   /* 设置keepalive重试次数 */

void ch395_set_keeplive(uint8_t sockindex, uint8_t cmd);                                                /* 设置ttl */

void ch395_setttl_num(uint8_t sockindex, uint8_t ttlnum);                                               /* 设置ttl */

#endif
#ifndef   __CH395INC_H__
#define   __CH395INC_H__


/* ********************************************************************************************************************* */
/* 常用类型和常量定义 */
#ifdef __cplusplus
extern "C" {
#endif

#ifndef     TRUE
#define     TRUE    1
#define     FALSE   0
#endif
#ifndef     NULL
#define     NULL    0
#endif

/* 命令代码:
 * 一个命令操作顺序包含:
 * 一个命令码(对于串口方式,命令码之前还需要两个同步码)
 * 若干个输入数据(可以是0个)
 * 若干个输出数据(可以是0个)
 * 命令码起名规则: CMDxy_NAME
 * 其中的x和y都是数字, x说明最少输入数据个数(字节数), y说明最少输出数据个数(字节数), y如果是W表示需要等待命令执行成功
 * 有些命令能够实现0到多个字节的数据块读写, 数据块本身的字节数未包含在上述x或y之内
 */
#define CMD01_GET_IC_VER                  0x01        /* 获取芯片以及固件版本号 */

#define CMD31_SET_BAUDRATE                0x02        /* 串口方式: 设置串口通讯波特率(上电或者复位后的默认波特率为9600bps */

#define CMD00_ENTER_SLEEP                 0x03        /* 进入睡眠状态 */

#define CMD00_RESET_ALL                   0x05        /* 执行硬件复位 */

#define CMD11_CHECK_EXIST                 0x06        /* 测试通讯接口以及工作状态 */

#define CMD02_GET_GLOB_INT_STATUS_ALL     0x19        /* 获取全局中断状态,V44版本以后的程序由于增加了socket数量需要用此命令获取全部的中断 */

#define CMD10_SET_PHY                     0x20        /* 设置PHY,默认为Auto,自动协商 */

#define CMD60_SET_MAC_ADDR                0x21        /* 设置MAC地址 必须在CMD00H_INIT_CH395之前设置完毕 */

#define CMD40_SET_IP_ADDR                 0x22        /* 设置IP地址 必须在CMD00H_INIT_CH395之前设置完毕 */

#define CMD40_SET_GWIP_ADDR               0x23        /* 设置网关IP地址 必须在CMD00H_INIT_CH395之前设置完毕 */

#define CMD40_SET_MASK_ADDR               0x24        /* 设置子网掩码, 必须在CMD00H_INIT_CH395之前设置完毕 */

#define CMD90_SET_MAC_FILT                0x25        /* 设置MAC过滤 可以进行广播,多播等过滤 */

#define CMD01_GET_PHY_STATUS              0x26        /* 获取PHY当前状态,如断开连接,10/100M FULL/HALF */

#define CMD0W_INIT_CH395                  0x27        /* 初始化CH395 */

#define CMD08_GET_UNREACH_IPPORT          0x28        /* 获取不可达信息 */

#define CMD01_GET_GLOB_INT_STATUS         0x29        /* 获取全局中断状态,最大值为1S,不可以设置为0 */

#define CMD10_SET_RETRAN_COUNT            0x2A        /* 重试次数,仅在TCP模式下有效 */

#define CMD20_SET_RETRAN_PERIOD           0x2B        /* 重试周期,最大值为20,仅在TCP模式下有效,不可以设置为0 */

#define CMD01_GET_CMD_STATUS              0x2C        /* 获取命令执行状态 */

#define CMD06_GET_REMOT_IPP_SN            0x2D        /* 获取远端的端口以及IP地址,该命令在TCP服务器模式下使用 */

#define CMD10_CLEAR_RECV_BUF_SN           0x2E        /* 清除接收缓冲区  */

#define CMD12_GET_SOCKET_STATUS_SN        0x2F        /* 获取socket n状态 */

#define CMD11_GET_INT_STATUS_SN           0x30        /* 获取socket n的中断状态 */

#define CMD50_SET_IP_ADDR_SN              0x31        /* 设置socket n的目的IP地址 */

#define CMD30_SET_DES_PORT_SN             0x32        /* 设置socket n的目的端口 */

#define CMD30_SET_SOUR_PORT_SN            0x33        /* 设置socket n的源端口 */

#define CMD20_SET_PROTO_TYPE_SN           0x34        /* 设置socket n的协议类型 */

#define CMD1W_OPEN_SOCKET_SN              0x35        /* 打开socket n */

#define CMD1W_TCP_LISTEN_SN               0x36        /* socket n监听,收到此命令,socket n进入服务器模式,仅对TCP模式有效 */

#define CMD1W_TCP_CONNECT_SN              0x37        /* socket n连接,收到此命令,socket n进入客户端模式,仅对TCP模式有效 */

#define CMD1W_TCP_DISNCONNECT_SN          0x38        /* socket n断开连接,收到此命令,socket n断开已有连接,仅对TCP模式有效 */

#define CMD30_WRITE_SEND_BUF_SN           0x39        /* 向socket n缓冲区写入数据 */

#define CMD12_GET_RECV_LEN_SN             0x3B        /* 获取socket n接收数据的长度 */

#define CMD30_READ_RECV_BUF_SN            0x3C        /* 读取socket n接收缓冲区数据 */

#define CMD1W_CLOSE_SOCKET_SN             0x3D        /* 关闭socket n */

#define CMD20_SET_IPRAW_PRO_SN            0x3E        /* 在IP RAW下,设置socket n的IP包协议类型 */

#define CMD01_PING_ENABLE                 0x3F        /* 开启/关闭PING */

#define CMD06_GET_MAC_ADDR                0x40        /* 获取MAC地址 */

#define CMD10_DHCP_ENABLE                 0x41        /* DHCP使能 */

#define CMD01_GET_DHCP_STATUS             0x42        /* 获取DHCP状态 */

#define CMD014_GET_IP_INF                 0x43        /* IP,子网掩码,网关 */

#define CMD00_PPPOE_SET_USER_NAME         0x44        /* 设置PPPOE用户名 */

#define CMD00_PPPOE_SET_PASSWORD          0x45        /* 设置密码 */

#define CMD10_PPPOE_ENABLE                0x46        /* PPPOE使能 */

#define CMD01_GET_PPPOE_STATUS            0x47        /* 获取pppoe状态 */

#define CMD20_SET_TCP_MSS                 0x50        /* 设置TCP MSS */

#define CMD20_SET_TTL                     0x51        /* 设置TTL,TTL最大值为128 */

#define CMD30_SET_RECV_BUF                0x52        /* 设置SOCKET接收缓冲区 */

#define CMD30_SET_SEND_BUF                0x53        /* 设置SOCKET发送缓冲区 */

#define CMD10_SET_MAC_RECV_BUF            0x54        /* 设置MAC接收缓冲区 */

#define CMD40_SET_FUN_PARA                0x55        /* 设置功能参数 */

#define CMD40_SET_KEEP_LIVE_IDLE          0x56        /* 设置KEEPLIVE空闲 */

#define CMD40_SET_KEEP_LIVE_INTVL         0x57        /* 设置间隔时间 */

#define CMD10_SET_KEEP_LIVE_CNT           0x58        /* 重试次数 */

#define CMD20_SET_KEEP_LIVE_SN            0X59        /* 设置socket nkeeplive功能*/

#define CMD00_EEPROM_ERASE                0xE9        /* 擦除EEPROM*/

#define CMD30_EEPROM_WRITE                0xEA        /* 写EEPROM */

#define CMD30_EEPROM_READ                 0xEB        /* 读EEPROM */

#define CMD10_READ_GPIO_REG               0xEC        /* 读GPIO寄存器 */

#define CMD20_WRITE_GPIO_REG              0xED        /* 写GPIO寄存器 */

/* 协议类型 */
#define PROTO_TYPE_IP_RAW                 0           /* IP层原始数据 */
#define PROTO_TYPE_MAC_RAW                1           /* MAC层原始数据 */
#define PROTO_TYPE_UDP                    2           /* UDP协议类型 */
#define PROTO_TYPE_TCP                    3           /* TCP协议类型 */

/* PHY 命令参数/状态 */
#define PHY_DISCONN                       (1<<0)      /* PHY断开 */
#define PHY_10M_FLL                       (1<<1)      /* 10M全双工 */
#define PHY_10M_HALF                      (1<<2)      /* 10M半双工 */
#define PHY_100M_FLL                      (1<<3)      /* 100M全双工 */
#define PHY_100M_HALF                     (1<<4)      /* 100M半双工 */
#define PHY_AUTO                          (1<<5)      /* PHY自动模式,CMD10H_SET_PHY */

/* CH395 MAC过滤 */
#define MAC_FILT_RECV_BORADPKT            (1<<0)      /* 使能接收广播包 */
#define MAC_FILT_RECV_ALL                 (1<<1)      /* 使能接收所有数据包 */
#define MAC_FILT_RECV_MULTIPKT            (1<<2)      /* 使能接收多播包 */
#define MAC_FILT_RECV_ENABLE              (1<<3)      /* 使能接收 */
#define MAC_FILT_SEND_ENABLE              (1<<4)      /* 使能发送 */

/* 中断状态 */
/* 以下为GLOB_INT会产生的状态 */
#define GINT_STAT_UNREACH                 (1<<0)      /* 不可达中断 */
#define GINT_STAT_IP_CONFLI               (1<<1)      /* IP冲突 */
#define GINT_STAT_PHY_CHANGE              (1<<2)      /* PHY状态改变 */
#define GINT_STAT_DHCP                    (1<<3)      /* PHY状态改变 */
#define GINT_STAT_SOCK0                   (1<<4)      /* socket0 产生中断 */
#define GINT_STAT_SOCK1                   (1<<5)      /* socket1 产生中断 */
#define GINT_STAT_SOCK2                   (1<<6)      /* socket2 产生中断 */
#define GINT_STAT_SOCK3                   (1<<7)      /* socket3 产生中断 */
#define GINT_STAT_SOCK4                   (1<<8)      /* scoket4 产生中断 */
#define GINT_STAT_SOCK5                   (1<<9)      /* scoket5 产生中断 */
#define GINT_STAT_SOCK6                   (1<<10)     /* scoket6 产生中断 */
#define GINT_STAT_SOCK7                   (1<<11)     /* scoket7 产生中断 */

/* 以下为Sn_INT会产生的状态 */
#define SINT_STAT_SENBUF_FREE             (1<<0)      /* 发送缓冲区空闲 */
#define SINT_STAT_SEND_OK                 (1<<1)      /* 发送成功 */
#define SINT_STAT_RECV                    (1<<2)      /* socket端口接收到数据或者接收缓冲区不为空 */
#define SINT_STAT_CONNECT                 (1<<3)      /* 连接成功,TCP模式下产生此中断 */
#define SINT_STAT_DISCONNECT              (1<<4)      /* 连接断开,TCP模式下产生此中断 */
#define SINT_STAT_TIM_OUT                 (1<<6)      /* ARP和TCP模式下会发生此中断 */

/* 获取命令状态 */
#define CMD_ERR_SUCCESS                   0x00        /* 命令操作成功 */
#define CMD_RET_ABORT                     0x5F        /* 命令操作失败 */
#define CH395_ERR_BUSY                    0x10        /* 忙状态,表示当前正在执行命令 */
#define CH395_ERR_MEM                     0x11        /* 内存错误 */
#define CH395_ERR_BUF                     0x12        /* 缓冲区错误 */
#define CH395_ERR_TIMEOUT                 0x13        /* 超时 */
#define CH395_ERR_RTE                     0x14        /* 路由错误*/
#define CH395_ERR_ABRT                    0x15        /* 连接停止*/
#define CH395_ERR_RST                     0x16        /* 连接复位 */
#define CH395_ERR_CLSD                    0x17        /* 连接关闭/socket 在关闭状态 */
#define CH395_ERR_CONN                    0x18        /* 无连接 */
#define CH395_ERR_VAL                     0x19        /* 错误的值 */
#define CH395_ERR_ARG                     0x1a        /* 错误的参数 */
#define CH395_ERR_USE                     0x1b        /* 已经被使用 */
#define CH395_ERR_IF                      0x1c        /* MAC错误  */
#define CH395_ERR_ISCONN                  0x1d        /* 已连接 */
#define CH395_ERR_OPEN                    0X20        /* 已经打开 */
#define CH395_ERR_UNKNOW                  0xFA        /* 未知错误 */

/* PPP状态 */
#define CH395_PPP_SUCCESS                 0           /* 成功 */
#define CH395_PPPERR_PARM                 1           /* 无效参数 */
#define CH395_PPPERR_OPEN                 2           /* 无法打开PPP会话 */
#define CH395_PPPERR_DEVICE               3           /* 无效的PPP设备 */
#define CH395_PPPERR_ALLOC                4           /* 资源分配失败 */
#define CH395_PPPERR_USER                 5           /* 用户中断 */
#define CH395_PPPERR_CONNECT              6           /* 连接断开 */
#define CH395_PPPERR_AUTHFAIL             7           /* 挑战鉴别失败 */
#define CH395_PPPERR_PROTOCOL             8           /* 握手协议失败 */
#define CH395_PPPERR_TIME_OUT             9           /* 超时失败 */
#define CH395_PPPERR_CLOSE                10          /* 关闭失败 */

/* 不可达代码 */
#define UNREACH_CODE_HOST                 0           /* 主机不可达 */
#define UNREACH_CODE_NET                  1           /* 网络不可达 */
#define UNREACH_CODE_PROTOCOL             2           /* 协议不可达 */
#define UNREACH_CODE_PROT                 3           /* 端口不可达 */
/* 其他值请参考RFC792文档 */

/* 命令包头 */
#define SER_SYNC_CODE1                    0x57        /* 串口命令同步码1 */
#define SER_SYNC_CODE2                    0xAB        /* 串口命令同步码2 */

/* TCP状态 */
#define TCP_CLOSED                        0
#define TCP_LISTEN                        1
#define TCP_SYN_SENT                      2
#define TCP_SYN_RCVD                      3
#define TCP_ESTABLISHED                   4
#define TCP_FIN_WAIT_1                    5
#define TCP_FIN_WAIT_2                    6
#define TCP_CLOSE_WAIT                    7
#define TCP_CLOSING                       8
#define TCP_LAST_ACK                      9
#define TCP_TIME_WAIT                     10

/* GPIO寄存器地址 */
#define GPIO_DIR_REG                     0x80        /* 寄存器方向寄存器,1:输出;0:输入 */
#define GPIO_IN_REG                      0x81        /* GPIO输入寄存器 */
#define GPIO_OUT_REG                     0x82        /* GPIO输出寄存器 */
#define GPIO_CLR_REG                     0x83        /* GPIO输出清除: 0=keep, 1=clear */
#define GPIO_PU_REG                      0x84        /* GPIO上拉使能寄存器 */
#define GPIO_PD_REG                      0x85        /* GPIO下拉使能寄存器 */

/* 功能参数 */
#define FUN_PARA_FLAG_TCP_SERVER         (1<<1)      /* tcp server 多连接模式标志,0X44版本及以后支持 */
#define FUN_PARA_FLAG_LOW_PWR            (1<<2)      /* 低耗能模式 */
#define SOCK_CTRL_FLAG_SOCKET_CLOSE      (1<<3)      /* CH395不主动关闭Socket */
#define SOCK_DISABLE_SEND_OK_INT         (1<<4)      /* send ok中断控制位,为1表示关闭send ok中断 */

#ifdef __cplusplus
}
#endif
#endif

 

posted on 2025-03-31 15:38  虎啸岳林  阅读(168)  评论(0)    收藏  举报

导航