CH395Q之CH395Q驱动库移植与驱动库分析(二)

本节主要介绍以下内容:

一、CH395Q驱动库移植

二、源码分析

一、CH395Q驱动库移植

驱动库移植主要有两个途径,一个是南京沁恒官方网址,一个是通过正点原子官方,原子官方对沁横官方提供的驱动库进行了完善与修改。自用的话推荐原子官方。

 原子与沁横官网相比主要有以下区别:

(1)在沁恒的基础上对格式进行了规范,并且条件编译相对较少

(2)统一了接口,并且添加了部分辅助功能。

1.1 移植流程

 1.2 准备工程

在裸机例程中,以跑马灯实验作为移植基础工程

重命名工程为《网络实验1 CH395移植实验》

按照以下结构新建文件夹:

在原子的例程中拷贝ch395.c/.hch395cmd.c/.hch395inc.h到新工程的Drivers\BSP\CH395Q路径下 

1.3 文件添加 

打开工程,在Drivers/BSP分组下添加CH395Q驱动库

1.4 新建文件

 新建ch395q_demo.c/,h文件,此文件用来编写测试代码。

1.5 验证测试

ch395q_demo.c文件下编写以下测试代码

void ch395_demo(void)

{

do

{

if (ch395_int_pin_wire == 0)

{

  ch395q_handler(); /* 中断处理函数 */

}

  } while (g_ch395q_sta.dhcp_status == DHCP_STA); /* 获取DHCP */

   

while(1)

{

  ch395q_handler();

}

}

mian.c


#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./MALLOC/malloc.h"
#include "./BSP/SRAM/sram.h"
#include "./BSP/CH395Q/ch395.h"
#include "./APP/ch395_demo.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */usart_init(115200);                 /* 串口初始化为115200 */led_init();                         /* 初始化LED */lcd_init();                         /* 初始化LCD */key_init();                         /* 初始化按键 */sram_init();                        /* 初始化外部SRAM */my_mem_init(SRAMIN);                /* 初始化内部内存 */my_mem_init(SRAMEX);                /* 初始化外部内存 */ch395_hardware_init();              /* ch395初始化 */ch395_demo();                       /* 例程测试 */}

验证通过可按照上图对IP、网关掩码等进行打印。

接下来,对IP进行ping包,ping通则表示验证成功,则移植完毕。 

二、驱动库分析

2.1 驱动文件介绍

文件

说明

ch395inc.h

定义CH395Q相关命令及类型

ch395cmd.c

定义CH395Q相关命令函数

ch395cmd.h

声明函数提供外部文件调用

ch395.c

实现UDPTCP连接等相关功能

ch395.h

声明函数、结构体等信息

接下来分文件去介绍

 ch395inc.h

ch395cmd.c/.h 

ch395.h 

ch395.c 

2.2 代码分析

2.2.1 ch395_hardware_init();ch395初始化

我们go to 进去

*** @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);                                                            /* 测试命令,用于测试硬件以及接口通讯 */if (i != 0x9a){g_ch395q_sta.ch395_error(i);                                                            /* ch395q检测错误 */}ch395_cmd_reset();                                                                          /* 对ch395q复位 */delay_ms(100);                                                                              /* 这里必须等待100以上延时 */g_ch395q_sta.ch395_error(ch395_cmd_init());                                                 /* 初始化ch395q命令 */ch395_socket_r_s_buf_modify();                                                             /* 设置socket接口的接收与发送缓冲区*/
//    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检测错误 */delay_ms(1000);                                                                             /* ch395q初始化延时 */
}

接下来对该函数进行逐行解读,首先是ch395_gpio_init

/*** @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);delay_ms(20);
}

这部分没什么说的,就是对GPIO进行配置,注意模式就行

接下来是spi1_init();

/*** @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_256; /* 定义波特率预分频的值:波特率预分频值为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的作用, 非必需 */
}

对SPI进行配置和使能,这块也没什么要改的,SPI一般都这样配置

    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;

这块是对结构体成员函数进行赋值,g_ch395q_sta是一个结构体

struct ch395q_t g_ch395q_sta;

结构体定义如下:

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 重新连接函数 */
};

 接下来首先是是对CH395进行检测,该命令前面讲过,传入0x65,返回值按位取反得到0x9a,如果不是0x9a,则利用以下代码对错误码进行打印。

/*** @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 ){delay_ms(200);delay_ms(200);}
}

接下来CH395进行复位,为硬件复位

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

该命令使CH395执行硬件复位。通常情况下,硬件复位在50mS 时间之内完成。所以我们此处在初始化后面延时了100ms,保证初始化完成。

如果初始化失败,对错误码进行打印,这个上面说过,此处不作赘述。

g_ch395q_sta.ch395_error(ch395_cmd_init()); 

接下来对ch395_socket_r_s_buf_modify();  函数进行讲解,该函数对socket接口的接收与发送缓冲区大小进行设置,一共0-7,8个socket,将24K内存分成0-47,48块,每块为512K字节。比如说设置socket0的recv_buf,第一个参数是0,就是设置socket0的recv_buf,第二个参数是0,表示从块的0索引值开始,最后一个参数是4,表示分配4块,4*512= 2k,也就是说recv_buf分配了2k内存。send_buf同理,设置socket0的send_buff从4索引值开始,分配2块内存。

*** @brief      设置socket接口的接收与发送缓冲区* @param      无* @retval     无* 0-47块 每块为512K字节*/
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       设置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);
}
    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);

首先对phy的状态进行获取,接下来phy状态回调函数检测phy的状态,如果断开就一致检测

    g_ch395q_sta.version = ch395_cmd_get_ver();                                                 /* 获取版本 */printf("CH395VER : %2x\r\n", (uint16_t)g_ch395q_sta.version);

连接成功就对395Q的固件库版本进行检测并进行打印。

    i = ch395_dhcp_enable(1);                                                                   /* 开启DHCP */g_ch395q_sta.ch395_error(i);  
/*** @brief       启动/停止dhcp* @param       flag:0 / 1, 具体含义如下:*   @arg       1:启动dhcp*   @arg       0:停止dhcp* @retval      执行状态*/
uint8_t  ch395_dhcp_enable(uint8_t flag)
{uint8_t i = 0;uint8_t s;ch395_write_cmd(CMD10_DHCP_ENABLE);ch395_write_data(flag);ch395_scs_hign;while (1){delay_ms(20);s = ch395_get_cmd_status();            /* 不能过于频繁查询 */if (s != CH395_ERR_BUSY){break;         /* 如果ch395芯片返回忙状态 */}if (i++ > 200){return CH395_ERR_UNKNOW; /* 超时退出 */}}return s;
}

启动dhcp,如果启动失败就对错误值进行打印。

2.2.3 void ch395_demo(void) 例程测试

接下来对测试例程进行分析

/*** @brief       例程测试* @param       无* @retval      无*/
void ch395_demo(void)
{ch395_show_mesg();                                                                                                  /* 显示信息 */do{if (ch395_int_pin_wire == 0)	/*判断INT这个引脚是否处于低 低则有异常状态发生*/{ch395q_handler();                                                                                           /* 中断处理函数 */}}while (g_ch395q_sta.dhcp_status == DHCP_STA);                                                                       /* 获取DHCP */while(1){ch395q_handler();}
}

第一句是加了个打印这个不看

下来进来先判断int的引脚,判断INT这个引脚是否处于低 低则有异常状态发生,则进入ch395q_handler()函数,该函数为CH395全局管理函数,该函数实现为

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

首先是又判断了一下int引脚,如果为低,则进入异常中断处理函数ch395_interrupt_handler();  该函数实现为

/*** @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中断 */}
}

udp只有前面三个中断,后面时针对TCP/IP的,如果插拔网线之类的,就会进入产生PHY改变中断,那么 会获取PHY状态, 检测PHY状态,执行ch395_reconnection()并重新连接 

/*** @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);		/*关闭socker接口*/g_ch395q_sta.ch395_error(ch395_dhcp_enable(0));                               /*对DHCP进行失能*/                            /* ch395q检测错误 */g_ch395q_sta.socket[socket_index].config.socket_enable = CH395Q_DISABLE;      /*socket失能*/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)		/*DHCP是否处于开启状态*/{ch395_cmd_reset();                                                                                          /* 对ch395q复位 */delay_ms(100);                                                                                              /* 这里必须等待100以上延时 */ch395_cmd_init();delay_ms(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;}}}
}

里面也比较简单,注释都在后面写着大家可以参考~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/661867.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1个 THM 和多台 BSP 的通讯(以邦纳 BSP 系列 PLC 为例)

一&#xff0e;架构和接线如下图所示 二、建立连接 选择 PLC 的驱动&#xff0c;多台连接请勾选“次连接” “次连接总数”就是要连接的 PLC 台数。 设置触摸屏通讯参数&#xff1b;同时确保每台 PLC 的通讯参数与该设定相同&#xff08;但站号不能相同&#xff09;。 三、…

HTML -- 常用标签

标签 表示HTML网页内容的一个最基本的组织单元&#xff0c;类似于语文中的标点符号&#xff0c; 标签的作用&#xff1a;告诉浏览器当前标签中的内容是什么&#xff0c;以什么格式在页面中进行呈现 单标签 单标签&#xff08;只有一个标签名的标签&#xff09;的标签格式&…

深入解剖指针篇(2)

目录 指针的使用 strlen的模拟实现 传值调用和传址调用 数组名的理解 使用指针访问数组 一维数组传参的本质 冒泡排序 个人主页&#xff08;找往期文章&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 指针的使用 strlen的模拟实现 库函数strlen的功能是求字符串…

PySpark(二)RDD基础、RDD常见算子

目录 RDD RDD五大特性 RDD创建 RDD算子 常见的Transformation算子 map flatMap mapValues reduceByKey groupBy filter distinct union join intersection glom groupByKey groupByKey和reduceByKey的区别 ? sortBy sortByKey 常见的action算子 countByKey…

Python入门到精通(七)——Python文件操作

Python文件操作 一、文件的编码 二、文件的读取 1、操作汇总 2、model 常用的三种基础访问模式 三、文件的写入 四、文件的追加 五、综合案例 一、文件的编码 1、什么是编码&#xff1f; 编码就是一种规则集合&#xff0c;记录了内容和二进制间进行相互转换的逻辑。编…

Flink1.14新版KafkaSource和KafkaSink实践使用(自定义反序列化器、Topic选择器、序列化器、分区器)

前言 在官方文档的描述中&#xff0c;API FlinkKafkaConsumer和FlinkKafkaProducer将在后续版本陆续弃用、移除&#xff0c;所以在未来生产中有版本升级的情况下&#xff0c;新API KafkaSource和KafkaSink还是有必要学会使用的。下面介绍下基于新API的一些自定义类以及主程序的…

解析Excel文件内容,按每列首行元素名打印出某个字符串的统计占比(超详细)

1.示例&#xff1a; 开发需求&#xff1a;读取Excel文件&#xff0c;统计第3列到第5列中每列的"False"字段占比&#xff0c;统计第6列中的"Pass"字段占比&#xff0c;并按每列首行元素名打印出统计占比 1.1 实现代码1&#xff1a;列数为常量 请确保替换y…

测试access和trunk口的区别(华为)

思科设备参考&#xff1a;测试access和trunk口的区别&#xff08;思科&#xff09; 一&#xff0c;实验目的 实现同一 Vlan 内的主机互通&#xff0c;不同 Vlan 间的主机隔离。 二&#xff0c;配置前测试 PC1分别ping PC2、PC3、PC4都能通&#xff0c;因为四台PC默认同处于v…

一文掌握SpringBoot注解之@Configuration知识文集(2)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

【JAVA】单例模式的线程安全性

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 正文 我的其他博客 正文 老生常谈的问题了&#xff0c;首先要说的是单例模式的线程安全意味着&#xff1a;某个类的实例在多线程环境 下只会被…

main函数中参数argc和argv用法解析

1 基础 argc 是 argument count 的缩写&#xff0c;表示传入main函数的参数个数&#xff1b; argv 是 argument vector 的缩写&#xff0c;表示传入main函数的参数序列或指针&#xff0c;并且第一个参数argv[0]一定是程序的名称&#xff0c;并且包含了程序所在的完整路径&…

深度解读NVMe计算存储协议-2

近日&#xff0c;NVME协议组织为了解决这些性能问题并为供应商提供标准化机制&#xff0c;在其架构中集成优化的计算功能&#xff0c;开发了NVM Express (NVMe) 计算存储特性。 计算存储的核心特性包括两个命令集&#xff1a;计算程序集和子系统本地内存。 其中&#xff0c;计算…

python-分享篇-Turtle海龟-画图

文章目录 背景颜色画圆太阳花树椭圆 背景颜色 import turtlepen turtle.Turtle() turtle.Screen().bgcolor("blue") pen.color("cyan") for i in range(10):for i in range(2):pen.forward(100)pen.right(60)pen.forward(100)pen.right(120)pen.right(36…

供应商规模成倍增长,医疗器械制造商如何让采购效率更进一步|创新场景50...

ITValue 随着企业的快速发展&#xff0c;采购供应链网络日益庞大&#xff0c;企业在供应商管理上面临着管理体系分散、风险难以管控&#xff0c;采购过程环节多等问题&#xff0c;供应商内外协同亟待解决。 作者&#xff5c;秦聪慧 专题&#xff5c;创新场景50 ITValue 制造企业…

Node.js之内存限制理解_对处理前端打包内存溢出有所帮助

Node.js内存限制理解_对处理前端打包内存溢出有所帮助 文章目录 Node.js内存限制理解_对处理前端打包内存溢出有所帮助Node.js内存限制1. 查看Node.js默认内存限制1. Ndos.js_V20.10.02. Node.js_V18.16.0 2. V8引擎垃圾回收相关Heap organization堆组织 Node.js内存限制 默认情…

Lazysysadmin

信息收集 # nmap -sn 192.168.1.0/24 -oN live.port Starting Nmap 7.94 ( https://nmap.org ) at 2024-01-30 21:10 CST Nmap scan report for 192.168.1.1 (192.168.1.1) Host is up (0.00075s latency). MAC Address: 00:50:56:C0:00:08 (VMware) Nma…

Docker容器化安装SonarQube9.9

文章目录 1.环境准备1.1 版本信息1.2 系统设置 2.Docker环境安装2.1 卸载旧版本2.2 设置源2.3 安装Docker2.4 设置阿里仓库2.5 启动Docker 3.Docker Compose4.登录4.1 首页4.2 安装插件 5.制作镜像离线安装 1.环境准备 1.1 版本信息 名称版本备注Docker25.0.1当前2024-01-01最…

《C程序设计》上机实验报告(五)之一维数组二维数组与字符数组

实验内容&#xff1a; 1.运行程序 #include <stdio.h> void main( ) { int i,j,iRow0,iCol0,m; int x[3][4]{{1,11,22,33},{2,28,98,38},{3,85,20,89}}; mx[0][0]; for(i0;i<3;i) for(j0;j<4;j) if (x[i][j]>m) { mx[i][j]; iRowi…

Elasticsearch:将文档级安全性 (DLS) 添加到你的内部知识搜索

作者&#xff1a;来自 Elastic Sean Story 你的企业很可能淹没在内部数据中。 你拥有问题跟踪、笔记记录、会议记录、维基页面、视频录制、聊天以及即时消息和私信。 并且不要忘记电子邮件&#xff01; 难怪如此多的企业都在尝试创造工作场所搜索体验 - 为员工提供集中、一站…

react 之 UseReducer

UseReducer作用: 让 React 管理多个相对关联的状态数据 import { useReducer } from react// 1. 定义reducer函数&#xff0c;根据不同的action返回不同的新状态 function reducer(state, action) {switch (action.type) {case INC:return state 1case DEC:return state - 1de…