关于HTTP部分主要是解析http请求和响应,目前代码没发现问题,根据需要修改宏定义
前言:
HTTP
协议(超文本传输协议HyperText Transfer Protocol),它是基于TCP协议的应用层传输协议,简单来说就是客户端和服务端进行数据传输的一种规则。
注意:客户端与服务器的角色不是固定的,一端充当客户端,也可能在某次请求中充当服务器。这取决与请求的发起端。HTTP协议属于应用层,建立在传输层协议TCP之上。客户端通过与服务器建立TCP连接,之后发送HTTP请求与接收HTTP响应都是通过访问Socket接口来调用TCP协议实现。
HTTP
是一种无状态 (stateless) 协议, HTTP
协议本身不会对发送过的请求和相应的通信状态进行持久化处理。这样做的目的是为了保持HTTP协议的简单性,从而能够快速处理大量的事务, 提高效率。
然而,在许多应用场景中,我们需要保持用户登录的状态或记录用户购物车中的商品。由于HTTP
是无状态协议,所以必须引入一些技术来记录管理状态,例如Cookie
。
正文
HTTP URL
HTTP URL
包含了用于查找某个资源的详细信息, 格式如下:
http://host[":"port][abs_path]
HTTP请求
http请求由请求行,消息报头,请求正文三部分构成。
HTTP请求状态行
请求行由请求Method
, URL
字段和HTTP Version
三部分构成, 总的来说请求行就是定义了本次请求的请求方式, 请求的地址, 以及所遵循的HTTP协议版本例如:
GET /example.html HTTP/1.1 (CRLF)
HTTP协议的方法有: GET
: 请求获取Request-URI所标识的资源 POST
: 在Request-URI所标识的资源后增加新的数据 HEAD
: 请求获取由Request-URI所标识的资源的响应消息报头 PUT
: 请求服务器存储或修改一个资源,并用Request-URI作为其标识 DELETE
: 请求服务器删除Request-URI所标识的资源 TRACE
: 请求服务器回送收到的请求信息,主要用于测试或诊断 CONNECT
: 保留将来使用 OPTIONS
: 请求查询服务器的性能,或者查询与资源相关的选项和需求
HTTP请求头
消息报头由一系列的键值对组成,允许客户端向服务器端发送一些附加信息或者客户端自身的信息
HTTP请求正文
只有在发送POST
请求时才会有请求正文,GET
方法并没有请求正文。
HTTP请求报文
HTTP响应
与HTTP请求类似HTTP响应也由三部分组成,包括状态行,消息报头,响应正文。
HTTP响应状态行
状态行也由三部分组成,包括HTTP协议的版本,状态码,以及对状态码的文本描述。例如:
HTTP/1.1 200 OK (CRLF)
HTTP响应状态码
状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值: 1xx
:指示信息 - 表示请求已接收,继续处理 2xx
:成功 - 表示请求已被成功接收、理解、接受 3xx
:重定向 - 要完成请求必须进行更进一步的操作 4xx
:客户端错误 - 请求有语法错误或请求无法实现 * 5xx
:服务器端错误 - 服务器未能实现合法的请求
常见状态代码、状态描述、说明: 200
: OK - 客户端请求成功 400
: Bad Request - 客户端请求有语法错误,不能被服务器所理解 401
: Unauthorized - 请求未经授权,这个状态代码必须和WWW-Authenticate
报头域一起使用 403
: Forbidden - 服务器收到请求,但是拒绝提供服务 404
: Not Found - 请求资源不存在,eg:输入了错误的URL 500
: Internal Server Error - 服务器发生不可预期的错误 * 503
: Server Unavailable - 服务器当前不能处理客户端的请求,一段时间后,可能恢复正常
HTTP响应状态码说明
略
HTTP响应报文
HTTP协议详解
HTTP的五大特点
- 支持客户/服务器模式。
- 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有
GET
、HEAD
、POST
。每种方法规定了客户与服务器联系的类型不同。由于HTTP
协议简单,使得HTTP
服务器的程序规模小,因而通信速度很快。 - 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由
Content-Type
加以标记。 - 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。早期这么做的原因是请求资源少,追求快。后来通过
Connection: Keep-Alive
实现长连接 - 无状态:
HTTP
协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
正文:(创作不易,点个赞,点个收藏)
CH9121通信代码:
#include "CH9121.h"
#include "HTTP.h"
#include "API_1_1.h"
// 备注:两个读函数之间间隔510ms
// 定义接收和发送缓冲区,用动态申请大小
char net_rx_buf[512];
// 溢出标志
uint16_t overflow = 0;
uint8_t overflow_flag = 0;
void UART4_DMA_Init(void)
{
// 初始化UART4和DMA1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使用外部中断或者重配置功能必须使能
// 配置UART4的GPIO引脚
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// 配置UART4
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(UART4, &USART_InitStructure);
// 使能接收中断
//USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)net_rx_buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1024;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE);
USART_Cmd(UART4, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 启动UART4
//
}
// 串口4初始化函数
void UART4_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能GPIO和USART时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
// 配置UART4的GPIO引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; // RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// 配置USART参数
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);
USART_Init(UART4, &USART_InitStructure);
// 使能接收中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能UART4
USART_Cmd(UART4, ENABLE);
}
/**
* @brief USART GPIO 配置,工作参数配置
* @param 无
* @retval 无
*/
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
RCC_APB2PeriphClockCmd((RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD), ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(UART5, &USART_InitStructure);
USART_Cmd(UART5, ENABLE);
}
int fputc(int ch, FILE *f)
{
USART_SendData(UART5, (uint8_t) ch);
while (USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET);
return (ch);
}
// 模块串口参数初始化
Serial serial =
{
9600,
None,
0x08,
0x01,
0
};
// 模块客户端结构体成员初始化
Net_CommunitionType net_communition_Client =
{
2000, // 客户端端口号
{192, 168, 5, 202}, // 客户端ip地址
{255, 255, 255, 0}, // 客户端子网掩码
{192, 168, 5, 202}, // 客户端默认网关
};
// 模块做服务器端结构体成员
Net_CommunitionType net_communition_Server1 =
{
2001, // 服务器端口号
{192, 168, 4, 236}, // 服务器ip地址
{255, 255, 255, 0}, // 服务器子网掩码
{192, 168, 4, 1}, // 服雾器默认网关
};
// 如果模块用TCP client模式,这里的参数自行修改为目的服务器对应参数
Net_CommunitionType net_communition_DstServer =
{
1000, // 服务器端口号
{192, 168, 5, 125}, // 服务器ip地址
{255, 255, 255, 0}, // 服务器子网掩码
{192, 168, 5, 1}, // 服雾器默认网关
};
static void Usartx_SendByte(USART_TypeDef * usart, uint8_t data)
{
USART_SendData(usart, data);
while (USART_GetFlagStatus(usart, USART_FLAG_TXE) == RESET);
}
static void Usartx_SendBytes(USART_TypeDef * usart, char * data, unsigned int len)
{
for(int i = 0; i < len; i++){
Usartx_SendByte(usart, data[i]);
}
}
uint8_t config_flag = 0;
// 进入配置模式
// 对于内部读写网口需要先调用此函数进入配置模式
static void ch9121_config_mode(void)
{
config_flag = 1;
// 发送命令字进入配置模式
Usartx_SendByte(M_UARTX, 0x55);
Usartx_SendByte(M_UARTX, 0xaa);
Usartx_SendByte(M_UARTX, 0x5a);
delay_ms(30);
Usartx_SendByte(M_UARTX, 0XA5);
}
static void ch9121_exitconfige(void)
{
// 发送命令字退出配置模式
Usartx_SendByte(M_UARTX, EXIT_SERIAL_CONFIG);
delay_ms(100);
config_flag = 0;
}
// 更新配置参数到EEPROM
static void update_config(void)
{
WRITE_CMD;
Usartx_SendByte(M_UARTX, UPDATE_CONFIG);
}
// 执行配置
static void execution_config(void)
{
WRITE_CMD;
Usartx_SendByte(M_UARTX, CMD_EXECUTION);
}
// 配置为芯片为TCP Server模式
static void ch9121_TCP_Server(void)
{
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(100);
// 配置为服务器模式
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_MODE);
Usartx_SendByte(M_UARTX, TCP_Server_mode);
delay_ms(100);
// 设置芯片IP地址 192.168.1.202
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_IP);
Usartx_SendByte(M_UARTX, net_communition_Server1.ip_address[0]);
Usartx_SendByte(M_UARTX, net_communition_Server1.ip_address[1]);
Usartx_SendByte(M_UARTX, net_communition_Server1.ip_address[2]);
Usartx_SendByte(M_UARTX, net_communition_Server1.ip_address[3]);
delay_ms(100);
// 设置芯片子网掩码 255.255.255.0
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_SUBNET_MASK);
Usartx_SendByte(M_UARTX, net_communition_Server1.subnet_mask[0]);
Usartx_SendByte(M_UARTX, net_communition_Server1.subnet_mask[1]);
Usartx_SendByte(M_UARTX, net_communition_Server1.subnet_mask[2]);
Usartx_SendByte(M_UARTX, net_communition_Server1.subnet_mask[3]);
delay_ms(100);
// 设置芯片网关 192.168.1.1
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_GATEWAY);
Usartx_SendByte(M_UARTX, net_communition_Server1.gateway[0]);
Usartx_SendByte(M_UARTX, net_communition_Server1.gateway[1]);
Usartx_SendByte(M_UARTX, net_communition_Server1.gateway[2]);
Usartx_SendByte(M_UARTX, net_communition_Server1.gateway[3]);
delay_ms(100);
// 设置服务器端口2001,端口号发送字节序是先发低字节,再发高字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_LOCAL_PORT);
Usartx_SendByte(M_UARTX, net_communition_Server1.port_num & 0x0ff);
Usartx_SendByte(M_UARTX, (uint8_t)(net_communition_Server1.port_num>>8));
delay_ms(100);
// 更新配置到EEPROM
update_config();
delay_ms(100);
// 执行配置
execution_config();
delay_ms(100);
// 退出配置模式
ch9121_exitconfige();
}
// 配置为TCP Client模式
static void ch9121_TCP_Client(void)
{
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(100);
// 配置为客户端模式
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_MODE);
Usartx_SendByte(M_UARTX, TCP_Client_mode);
delay_ms(100);
/*
// 已从上位机软件配置为DHCP模式,不需要配置IP、网关和子网掩码,端口号配置为了随机
// 设置芯片IP地址 192.168.1.202
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_IP);
Usartx_SendByte(M_UARTX, net_communition_Client.ip_address[0]);
Usartx_SendByte(M_UARTX, net_communition_Client.ip_address[1]);
Usartx_SendByte(M_UARTX, net_communition_Client.ip_address[2]);
Usartx_SendByte(M_UARTX, net_communition_Client.ip_address[3]);
// 设置芯片子网掩码 255.255.255.0
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_SUBNET_MASK);
Usartx_SendByte(M_UARTX, net_communition_Client.subnet_mask[0]);
Usartx_SendByte(M_UARTX, net_communition_Client.subnet_mask[1]);
Usartx_SendByte(M_UARTX, net_communition_Client.subnet_mask[2]);
Usartx_SendByte(M_UARTX, net_communition_Client.subnet_mask[2]);
// 设置芯片网关 192.168.1.1
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_GATEWAY);
Usartx_SendByte(M_UARTX, net_communition_Client.gateway[0]);
Usartx_SendByte(M_UARTX, net_communition_Client.gateway[1]);
Usartx_SendByte(M_UARTX, net_communition_Client.gateway[2]);
Usartx_SendByte(M_UARTX, net_communition_Client.gateway[3]);
// 设置服务器端口2001,端口号发送字节序是先发低字节,再发高字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_LOCAL_PORT);
Usartx_SendByte(M_UARTX, net_communition_Client.port_num & 0x0ff);
Usartx_SendByte(M_UARTX, (uint8_t)net_communition_Client.port_num>>8);
*/
// 设置目的服务器IP地址
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_DESTINATION_IP);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[0]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[1]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[2]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[3]);
delay_ms(100);
// 设置目的服务器端口1000,端口号发送字节序是先发低字节,再发高字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_DESTINATION_PORT);
Usartx_SendByte(M_UARTX, net_communition_DstServer.port_num & 0x0ff);
Usartx_SendByte(M_UARTX, (uint8_t)(net_communition_DstServer.port_num>>8));
delay_ms(100);
// 更新配置到EEPROM
update_config();
delay_ms(100);
// 执行配置
execution_config();
delay_ms(100);
// 退出配置模式
ch9121_exitconfige();
}
// 配置为UDP Client模式
static void ch9121_UDP(void)
{
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(100);
// 配置为UDP客户端模式
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_MODE);
Usartx_SendByte(M_UARTX, UDP_Client_mode);
delay_ms(100);
// 设置目的服务器IP地址
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_DESTINATION_IP);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[0]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[1]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[2]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[3]);
delay_ms(100);
// 设置目的服务器端口1000,端口号发送字节序是先发低字节,再发高字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_DESTINATION_PORT);
Usartx_SendByte(M_UARTX, net_communition_DstServer.port_num & 0x0ff);
Usartx_SendByte(M_UARTX, (uint8_t)(net_communition_DstServer.port_num>>8));
delay_ms(100);
// 更新配置到EEPROM
update_config();
delay_ms(100);
// 执行配置
execution_config();
delay_ms(100);
// 退出配置模式
ch9121_exitconfige();
}
// 配置为UDP Server模式
static void ch9121_UDP_Server(void)
{
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(100);
// 配置为UDP服务器端模式
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_CHIP_MODE);
Usartx_SendByte(M_UARTX, UDP_Server_mode);
delay_ms(100);
// 设置目的服务器IP地址
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_DESTINATION_IP);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[0]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[1]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[2]);
Usartx_SendByte(M_UARTX, net_communition_DstServer.ip_address[3]);
delay_ms(100);
// 设置目的服务器端口1000,端口号发送字节序是先发低字节,再发高字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_DESTINATION_PORT);
Usartx_SendByte(M_UARTX, net_communition_DstServer.port_num & 0x0ff);
Usartx_SendByte(M_UARTX, (uint8_t)(net_communition_DstServer.port_num>>8));
// 更新配置到EEPROM
update_config();
delay_ms(100);
// 执行配置
execution_config();
delay_ms(100);
// 退出配置模式
ch9121_exitconfige();
}
// 选择ch9121的工作模式
// mode:0->TCP Server
// 1->TCP Client
// 2->UDP
// 3->UDP Server
static void ch9121_mode_select(uint8_t mode)
{
switch(mode)
{
case 0:
ch9121_TCP_Server();
break;
case 1:
ch9121_TCP_Client();
break;
case 2:
ch9121_UDP();
break;
case 3:
ch9121_UDP_Server();
break;
}
}
// 配置串口相关餐数
static void serial_config(void)
{
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(100);
// 设置串口波特率926100,需要筹够4字节,发送字节序是先发低字节,再发高字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_SERIAL_BOUND);
Usartx_SendByte(M_UARTX, serial.bound&0xff);
Usartx_SendByte(M_UARTX, (serial.bound>>8)&0xff);
Usartx_SendByte(M_UARTX, (serial.bound>>16)&0xff);
Usartx_SendByte(M_UARTX, (serial.bound>>24)&0xff);
delay_ms(100);
// 设置串口数据帧格式,1位停止位,无校验,8位数据位
WRITE_CMD;
Usartx_SendByte(M_UARTX, SET_SERIAL_DATA_FORMAT);
Usartx_SendByte(M_UARTX, serial.stop_bit);
Usartx_SendByte(M_UARTX, serial.serial_check);
Usartx_SendByte(M_UARTX, serial.data_bit);
delay_ms(100);
// 更新配置到EEPROM
update_config();
delay_ms(100);
// 执行配置
execution_config();
delay_ms(100);
// 退出配置模式
ch9121_exitconfige();
}
// 发送数据
void send_netdata(uint8_t * t_buf)
{
while(*t_buf != '\0')
{
Usartx_SendByte(M_UARTX, *t_buf);
t_buf++;
}
}
/*************************************************************************************************************************************************
读取相关函数
**************************************************************************************************************************************************/
// 读取芯片工作模式,返回一个字节
uint8_t read_WorkMode(void)
{
uint8_t netmode;
// 每次进来先把缓冲数组下标清零,便于取数
overflow = 0;
// 芯片进入配置模式
//ch9121_config_mode();
delay_ms(100);
// 读取芯片工作模式,返回一个字节
overflow = 0;
WRITE_CMD;
Usartx_SendByte(M_UARTX, READ_CHIP_MODE);
delay_ms(100);
// 退出配置模式
//ch9121_exitconfige();
netmode = net_rx_buf[0];
printf("%d\r\n", netmode);
switch(netmode)
{
case 0:
return TCP_Server_mode;
case 1:
return TCP_Client_mode;
case 2:
return UDP_Server_mode;
case 3:
return UDP_Client_mode;
}
return 0xff;
}
// 读取芯片IP
void read_chip_ip(uint8_t *ip_addr)
{
uint8_t i;
// 每次进来先把缓冲数组下标清零,便于取数
overflow = 0;
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(100);
overflow = 0;
// 读取芯片工作模式,返回一个字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, READ_CHIP_IP);
delay_ms(100);
for(i = 0; i < 4; i++)
{
ip_addr[i] = net_rx_buf[i];
}
// 退出配置模式
ch9121_exitconfige();
printf("%d.%d.%d.%d\r\n", ip_addr[0],ip_addr[1],ip_addr[2],ip_addr[3]);
}
// 读取芯片掩码
void read_chip_subnet_mask(uint8_t *subnet_mask)
{
uint8_t i;
// 每次进来先把缓冲数组下标清零,便于取数
overflow = 0;
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(100);
// 读取芯片工作模式,返回一个字节
overflow = 0;
WRITE_CMD;
Usartx_SendByte(M_UARTX, READ_CHIP_SUBNET_MASK);
delay_ms(300);
for(i = 0; i < 4; i++)
{
subnet_mask[i] = net_rx_buf[i];
}
// 退出配置模式
//ch9121_exitconfige();
printf("%d.%d.%d.%d\r\n", subnet_mask[0],subnet_mask[1],subnet_mask[2],subnet_mask[3]);
}
// 读取芯片掩码
void read_chip_getway(uint8_t *getway)
{
uint8_t i;
// 每次进来先把缓冲数组下标清零,便于取数
overflow = 0;
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(100);
// 读取芯片工作模式,返回一个字节
overflow = 0;
WRITE_CMD;
Usartx_SendByte(M_UARTX, READ_CHIP_GATEWAY);
delay_ms(300);
for(i = 0; i < 4; i++)
{
getway[i] = net_rx_buf[i];
}
// 退出配置模式
//ch9121_exitconfige();
printf("%d.%d.%d.%d\r\n", getway[0],getway[1],getway[2],getway[3]);
}
// 读取源端口
uint16_t read_source_port(void)
{
uint16_t _port;
// 每次进来先把缓冲数组下标清零,便于取数
overflow = 0;
// 芯片进入配置模式
//ch9121_config_mode();
delay_ms(100);
overflow = 0;
// 读取芯片工作模式,返回一个字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, READ_SOURCE_PORT);
delay_ms(300);
// 退出配置模式
//ch9121_exitconfige();
_port = net_rx_buf[0];
_port |= (net_rx_buf[1]<<8);
printf("%d\r\n", _port);
return _port;
}
// 读取目的IP
void read_distination_ip(uint8_t *ip_addr)
{
uint8_t i;
// 每次进来先把缓冲数组下标清零,便于取数
overflow = 0;
// 芯片进入配置模式
//ch9121_config_mode();
delay_ms(300);
// 读取芯片工作模式,返回一个字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, READ_DESTINATION_IP);
delay_ms(300);
for(i = 0; i < 4; i++)
{
ip_addr[i] = net_rx_buf[i];
}
// 退出配置模式
//ch9121_exitconfige();
printf("%d.%d.%d.%d\r\n", ip_addr[0],ip_addr[1],ip_addr[2],ip_addr[3]);
}
// 读取目的端口
uint16_t read_distination_port(void)
{
uint16_t _port;
// 每次进来先把缓冲数组下标清零,便于取数
overflow = 0;
// 芯片进入配置模式
//ch9121_config_mode();
delay_ms(300);
// 读取芯片工作模式,返回一个字节
WRITE_CMD;
Usartx_SendByte(M_UARTX, READ_DESTINATION_PORT);
delay_ms(300);
// 退出配置模式
//ch9121_exitconfige();
_port = net_rx_buf[2];
_port |= (net_rx_buf[3]<<8);
printf("%d\r\n", _port);
return _port;
}
// 复位芯片
void reset_chip(void)
{
// 芯片进入配置模式
ch9121_config_mode();
delay_ms(300);
WRITE_CMD;
Usartx_SendByte(M_UARTX, RESET_CHIP);
delay_ms(300);
// 退出配置模式
ch9121_exitconfige();
}
// 初始化配置函数
void init_ch9121(void)
{
// 设置工作模式
config_flag = 1;
//ch9121_mode_select(TCP_Server_mode);
read_chip_getway(net_communition_Server1.gateway);
read_chip_subnet_mask(net_communition_Server1.subnet_mask);
read_chip_ip(net_communition_Server1.ip_address);
net_communition_Server1.port_num = read_source_port();
config_flag = 0;
}
uint8_t RecvFlag = 0;
/**
* @name UART4_IRQHandler
* @brief 串口4中断服务函数,目前用于CH9121网络通信模块
* @param 空
* @return 空
* @DateTime 2019-7-20
*/
uint8_t return_val = 0;
void UART4_IRQHandler(void)
{
if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)
{
return_val = USART_ReceiveData(UART4);
if(overflow > 2047)
{
overflow = 0;
}
else
{
net_rx_buf[overflow++] = return_val;
}
}
else if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)
{
USART_ReceiveData(M_UARTX);
RecvFlag = 1;
}
}
CH9121.h
// 定义了与网络CH9121通信的基本数据结构,和配置结构,参数等
#ifndef __BSP_CH9121_H__
#define __BSP_CH9121_H__
#include "Global.h"
#include <stdio.h>
// 本程序中默认模块做为客户端
#define M_UARTX UART4
#define WRITE_CMD {Usartx_SendByte(M_UARTX, 0x57);Usartx_SendByte(M_UARTX, 0xab);}
#define delay_ms(X) os_dly_wait(X)
// 定义接收和发送缓冲区,用动态申请大小,打包长度小于1024byte
extern char net_rx_buf[512];
extern uint8_t overflow_flag;
// 网络连接状态类型
typedef enum _ConnectStatus
{
disconnect = 0,
connect_ok
} ConnectStatus;
// 校验方式数据类型
typedef enum _Serial_Check
{
Even_Check = 0,
Odd_Check,
Mark,
Space,
None
} Serial_Check;
// 工作模式类型
typedef enum _Net_Mode
{
TCP_Server_mode = 0,
TCP_Client_mode,
UDP_Server_mode,
UDP_Client_mode
} Net_Mode;
// 服务器/客户端通信相关的类型
typedef struct _Net_CommunitionType
{
uint16_t port_num; // 端口号
uint8_t ip_address[4]; // IP地址
uint8_t subnet_mask[4]; // 子网掩码
uint8_t gateway[4]; // 默认网关
uint16_t tcp_retry_count; // TCP重试次数
uint8_t mac_address[4]; // MAC地址
ConnectStatus status; // 连接状态
Net_Mode net_mode;
} Net_CommunitionType;
extern Net_CommunitionType net_communition_Client;
extern Net_CommunitionType net_communition_DstServer;
extern Net_CommunitionType net_communition_Server1;
// 串口相关数据类型
typedef struct _Serial
{
uint32_t bound; // 波特率
Serial_Check serial_check; // 校验类型
uint8_t data_bit; // 数据位数
uint8_t stop_bit; // 停止位
uint32_t timeout; // 超时时间
} Serial;
typedef struct{
unsigned char year;
unsigned char mon;
unsigned char mday;
unsigned char wday;
unsigned char hour;
unsigned char min;
unsigned char sec;
}tm_time;
typedef struct {
unsigned int batchNumber;
tm_time pointDate;
int temperatrue;
int speed;
int ascspeed;
int descspeed;
}tm_msg;
typedef struct {
unsigned int batchNumber;
int state;
char reason[30];
}tm_state;
typedef struct {
char success;
char title;
char message;
char type;
char detail[30];
char category;
}boby_result;
extern Serial serial;
// 写命令码,格式(0x57 0xab + 命令码 + 数据)
#define RESET_CHIP 0x02 // 复位命令,芯片重新运行
#define UPDATE_CONFIG 0x0d // 更新配置参数至 EEPROM
#define CMD_EXECUTION 0x0e // 命令执行
#define SET_CHIP_MODE 0x10 // 设置模式
#define SET_CHIP_IP 0x11 // 设置芯片 IP 地址
#define SET_CHIP_SUBNET_MASK 0x12 // 设置芯片掩码
#define SET_CHIP_GATEWAY 0x13 // 设置芯片网关
#define SET_LOCAL_PORT 0x14 // 设置芯片本地端口
#define SET_DESTINATION_IP 0x15 // 设置芯片目的 IP 地址
#define SET_DESTINATION_PORT 0x16 // 设置芯片目的端口
#define SET_SERIAL_BOUND 0x21 // 设置串口波特率
#define SET_SERIAL_DATA_FORMAT 0x22 // 设置串口校验位数据位停止位
#define EXIT_SERIAL_CONFIG 0x5e // 退出串口配置模式
// 读命令码,格式(0x57 0xab + 命令码)
#define READ_CHIP_MODE 0x60 // 读取芯片工作模式,返回 1 字节
#define READ_CHIP_IP 0x61 // 读取芯片 IP 地址,返回 4 字节
#define READ_CHIP_SUBNET_MASK 0x62 // 读取芯片掩码,返回 4 字节
#define READ_CHIP_GATEWAY 0X63 // 读取芯片网关,返回 4 字节
#define READ_SOURCE_PORT 0x64 // 读取芯片源端口号,返回 2 字节
#define READ_DESTINATION_IP 0x65 // 读取芯片目的 IP 地址,返回 4 字节
#define READ_DESTINATION_PORT 0x66 // 读取芯片目的端口号,返回 2 字节
#define READ_RETRY_TIMES 0x67 // 读取 TCP 重试次数,返回 1 字节
#define READ_SERIAL_BOUND 0x71 // 读取串口波特率,返回 4 字节
#define READ_SERIAL_DATA_FORMAT 0x72 // 读取串口校验位数据位停止位,返回 3 字节
#define READ_SERIAL_OVERTIME 0x73 // 读取串口超时时间,返回 1 字节
#define READ_MAC_ADDRESS 0x81 // 读取 MAC 地址,返回 6 字节
#define READ_TCP_STATUS 0x03 // 读取 TCP 连接状态(TCP CLIENT 模式下),返回 1 字节,1:连接,0:断开。
extern tm_time system_tm;
extern uint8_t ConfigFlag;
// 公有函数区域
void UART4_Init(void);
void init_ch9121(void);
void send_netdata(uint8_t * t_buf);
uint8_t read_WorkMode(void);
uint16_t read_source_port(void);
void read_chip_ip(uint8_t *ip_addr);
uint16_t read_distination_port(void);
void read_distination_ip(uint8_t *ip_addr);
void reset_chip(void);
__task void CH9121_Token_Get(void);
__task void CH9121_HTTP_CL(void);
#endif
HTTP.c
#include "HTTP.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
/*
状态码 状态消息 描述
1xx 信息性状态码 表示服务器已经接收到请求,并且正在处理请求
100 Continue 客户端应该继续发送请求
101 Switching Protocols 服务器正在切换协议
2xx 成功状态码 表示服务器成功地接收、理解并接受请求
200 OK 请求已经成功处理并返回响应
201 Created 请求已经成功处理并创建了新资源
202 Accepted 请求已经接受,但是还没有处理
204 No Content 请求已经成功处理,但是没有响应内容
3xx 重定向状态码 表示请求需要进一步处理才能完成
301 Moved Permanently 请求的资源已经被永久移动到新的URL
302 Found 请求的资源已经被暂时移动到新的URL
304 Not Modified 请求的资源没有被修改,可以使用缓存副本
4xx 客户端错误状态码 表示客户端发出的请求有问题,服务器无法处理
400 Bad Request 请求无效或无法处理
401 Unauthorized 需要认证才能访问资源
403 Forbidden 没有访问资源的权限
404 Not Found 请求的资源不存在
5xx 服务器错误状态码 表示服务器在处理请求时遇到了问题
500 Internal Server Error 服务器遇到了无法处理的错误
502 Bad Gateway 充当网关或代理服务器的服务器从上游服务器接收到的响应无效
503 Service Unavailable 服务器无法处理请求,可能是因为过载或正在维护
*/
static const char *http_codes[53] = {
"100 Continue",
"101 Switching Protocols",
"102 Processing",
"200 OK",
"201 Created",
"202 Accepted",
"203 Non-Authoritative Information",
"204 No Content",
"205 Reset Content",
"206 Partial Content",
"207 Multi-Status",
"208 Already Reported",
"226 IM Used",
"300 Multiple Choices",
"301 Moved Permanently",
"302 Found",
"303 See Other",
"304 Not Modified",
"305 Use Proxy",
"307 Temporary Redirect",
"308 Permanent Redirect",
"400 Bad Request",
"401 Unauthorized",
"402 Payment Required",
"403 Forbidden",
"404 Not Found",
"405 Method Not Allowed",
"406 Not Acceptable",
"407 Proxy Authentication Required",
"408 Request Timeout",
"409 Conflict",
"410 Gone",
"411 Length Required",
"412 Precondition Failed",
"413 Payload Too Large",
"414 URI Too Long",
"415 Unsupported Media Type",
"416 Range Not Satisfiable",
"417 Expectation Failed",
"418 I'm a teapot",
"421 Misdirected Request",
"422 Unprocessable Entity",
"423 Locked",
"424 Failed Dependency",
"426 Upgrade Required",
"428 Precondition Required",
"429 Too Many Requests",
"431 Request Header Fields Too Large",
"451 Unavailable For Legal Reasons",
"500 Internal Server Error",
"501 Not Implemented",
"502 Bad Gateway",
"503 Service Un"
};
// 获取指定状态码的状态消息
const char* get_http_status_message(int status_code) {
static const char unknown[] = "Unknown status code";
char *description = NULL;
char num_ch[30];
int i;
snprintf(num_ch, 30, "%d", status_code);
for (i = 0; i < 53; i++) {
if(strncmp(http_codes[i], num_ch, 3) == 0){
return http_codes[i];
}
}
return unknown;
}
/**
* @brief StringBF
* @param s1:源字符串
s2:子串
pos:开始查找位置
这个函数和C库函数一样的用法,但是原来的C库函数有问题,所以优化了写法
* @retval result:查找字符串出现的位置
*/
char *Strtok(char *s1, const char *s2)
{
int i = 0;//下标值与自然语言转换
int j = 0;
int m = 0;
static char* saved_ptr = NULL;
// 如果是第一次调用,则初始化 saved_ptr
if (s1 != NULL) {
saved_ptr = s1;
} else if (saved_ptr == NULL) {
// 如果 saved_ptr 为 NULL,则返回 NULL
return NULL;
}
char * token = saved_ptr;
int s2_len = strlen(s2), s1_len = strlen(saved_ptr);
while(i < s1_len && j < s2_len)//若i和j都大于字符串的长度就结束循环
{
if(saved_ptr[i] == s2[j])
{
i++;
j++;
}
else//匹配失败时回溯
{
i = i - j + 1; //被匹配字符串右移1
j = 0; //匹配字符串初始化下标值
}
}
if(j == s2_len)//联合上面的while进行对比
{
for(m = 0; m < s2_len; m++){
saved_ptr[i - m -1] = 0;
}
saved_ptr = saved_ptr + i;
return token;
}
else saved_ptr = NULL;
return token;
//返回的是第一次匹配到的字符的下自然语言(则从1开始数)
}
http_url_t* parse_http_from(http_url_t * urlt, char *query_string) {
int i = 0, j = 0;
char * pair[MAX_HTTP_URI_FROM_COUNT];
char *query = Strtok((char *)query_string, "?");
strncpy(urlt->path, query, MAX_HTTP_URI_PATH_LEN);
urlt->path[MAX_HTTP_URI_PATH_LEN - 1] = '\0';
while(i < MAX_HTTP_URI_FROM_COUNT && pair[i]){
pair[i] = Strtok((char *)NULL, "&");
if(pair[i] == NULL) break;
i++;
}
while (pair[j] && j < i) {
char *key = Strtok(pair[j], "=");
char *value = Strtok(NULL, "=");
if(key == NULL || value == NULL){
return NULL;
}
strncpy(urlt->urlf[j].key, key, MAX_HTTP_URI_FROM_LEN);
urlt->urlf[j].key[MAX_HTTP_URI_FROM_LEN - 1] = '\0';
strncpy(urlt->urlf[j].value, value, MAX_HTTP_URI_FROM_LEN);
urlt->urlf[j].value[MAX_HTTP_URI_FROM_LEN - 1] = '\0';
j++;
}
urlt->count = i;
return urlt;
}
http_request_t *parse_http_request(http_request_t *request, char * request_string) {
//http_request_t *request = (http_request_t *)malloc(sizeof(http_request_t));
if (!request) {
return NULL;
}
char *request_line_str = Strtok(request_string, "\r\n");
char *header_str = Strtok(NULL, "\r\n\r\n");
char *body_str = Strtok(NULL, "\r\n");
if(body_str != NULL){
strncpy(request->body, body_str, MAX_HTTP_BODY_LEN);
request->body[MAX_HTTP_BODY_LEN - 1] = '\0';
}
if (!request_line_str) {
free(request);
return NULL;
}
//解析请求行
char *request_line_tokens[3];
int num_request_line_tokens = 0;
char *token = Strtok(request_line_str, " ");
while (token != NULL && num_request_line_tokens < 3) {
request_line_tokens[num_request_line_tokens++] = token;
token = Strtok(NULL, " ");
}
if (num_request_line_tokens < 3) {
free(request);
return NULL;
}
strncpy(request->request_line.method, request_line_tokens[0], MAX_HTTP_METHOD_LEN);
request->request_line.method[MAX_HTTP_METHOD_LEN - 1] = '\0';
http_url_t * urls = parse_http_from(&(request->request_line.uri), request_line_tokens[1]);
strncpy(request->request_line.version, request_line_tokens[2], MAX_HTTP_VERSION_LEN);
request->request_line.version[MAX_HTTP_VERSION_LEN - 1] = '\0';
char * header_key,* header_value;
header_key = Strtok(header_str, ": ");
//解析请求头
while (header_key != NULL && request->head_count < MAX_HTTP_HEADER_COUNT) {
header_value = Strtok(NULL, "\r\n");
http_header_t *header = &(request->headers[request->head_count++]);
strncpy(header->key, header_key, MAX_HTTP_HEADER_LEN);
header->key[MAX_HTTP_HEADER_LEN - 1] = '\0';
strncpy(header->value, header_value, MAX_HTTP_HEADER_LEN);
header->value[MAX_HTTP_HEADER_LEN - 1] = '\0';
header_key = Strtok(NULL, ": ");
}
if (request->head_count == 0) {
free(request);
return NULL;
}
return request;
}
char * http_request_respond(char * http_version, char * content_type, int state_code, char * body, int content_length){
static char rec[2048];
memset(rec, 0, 2048);
snprintf(rec, 2048, HTTP_RESPOND, http_version, get_http_status_message(state_code), content_type, content_length, body);
return rec;
}
void printf_http_request(http_request_t * request){
printf("method:%s\n", request->request_line.method);
printf("version:%s\n", request->request_line.version);
printf("path:%s\n", request->request_line.uri.path);
for(int i = 0; i < request->request_line.uri.count; i++){
printf("%s:%s\n", request->request_line.uri.urlf[i].key, request->request_line.uri.urlf[i].value);
}
printf("header:{\n");
for(int i = 0; i < request->head_count; i++){
printf("\t%s:%s\n", request->headers[i].key, request->headers[i].value);
}
printf("}\n");
printf("body:%s\n", request->body);
}
char get_request_string[] = "POST /cmds?device_id=1005271920&qos=1&timeout=10 HTTP/1.1\r\nHost:api.heclouds.com\r\nConnection: keep-alive\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:16\r\napi-key:uCmAn8tHKuuqJe5KllaobZiN=Og=\r\n\r\nhhhhhhhhhhhhhhhh\r\n";
static uint32_t mt[MT_N];
static int mti = MT_N + 1;
void mt_seed(uint32_t seed) {
mt[0] = seed;
for (mti = 1; mti < MT_N; mti++) {
mt[mti] = 1812433253 * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti;
}
}
uint32_t mt_rand() {
uint32_t y;
if (mti >= MT_N) {
int i;
for (i = 0; i < MT_N - MT_M; i++) {
y = (mt[i] & MT_UPPER_MASK) | (mt[i + 1] & MT_LOWER_MASK);
mt[i] = mt[i + MT_M] ^ (y >> 1) ^ ((y & 1) * MT_MATRIX_A);
}
for (; i < MT_N - 1; i++) {
y = (mt[i] & MT_UPPER_MASK) | (mt[i + 1] & MT_LOWER_MASK);
mt[i] = mt[i + (MT_M - MT_N)] ^ (y >> 1) ^ ((y & 1) * MT_MATRIX_A);
}
y = (mt[MT_N - 1] & MT_UPPER_MASK) | (mt[0] & MT_LOWER_MASK);
mt[MT_N - 1] = mt[MT_M - 1] ^ (y >> 1) ^ ((y & 1) * MT_MATRIX_A);
mti = 0;
}
y = mt[mti++];
y ^= y >> 11;
y ^= (y << 7) & 0x9D2C5680;
y ^= (y << 15) & 0xEFC60000;
y ^= y >> 18;
return y;
}
char *generate_token(int seed) {
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // 定义Token可以使用的字符集
static char token[TOKEN_LENGTH+2];
mt_seed(seed); // 设置随机数生成器的种子
for (int i = 0; i < TOKEN_LENGTH; i++) {
int index = mt_rand() % (sizeof(charset) - 1); // 从字符集中随机选择一个字符
token[i] = charset[index];
}
token[TOKEN_LENGTH] = '\0'; // 在Token的末尾添加字符串结束符
printf("token:%s\n", token);
return token;
}
HTTP.h
#ifndef __HTTP_H
#define __HTTP_H
#define MAX_HTTP_METHOD_LEN 10
#define MAX_HTTP_URI_LEN 100
#define MAX_HTTP_URI_FROM_COUNT 10
#define MAX_HTTP_URI_PATH_LEN 100
#define MAX_HTTP_HOST_LEN 30
#define MAX_HTTP_URI_FROM_LEN 100
#define MAX_HTTP_VERSION_LEN 20
#define MAX_HTTP_HEADER_LEN 200
#define MAX_HTTP_BODY_LEN 400
#define MAX_HTTP_HEADER_COUNT 10
#define MAX_HTTP_RESPOND_LEN 500
/**
*HTTP请求行包含三个部分:
*请求方法(Request Method):指明了客户端想要执行的动作。常见的请求方法有GET、POST、PUT、DELETE等。例如,GET方法表示客户端希望从服务器获取资源。
*请求URI(Request URI):指定了要访问的资源的标识符。URI通常包括协议、主机名、端口号和路径等信息。例如,http://www.example.com/index.html是一个请求URI。
*HTTP协议版本(HTTP Version):指定了客户端所使用的HTTP协议的版本。常见的HTTP协议版本有HTTP/1.0和HTTP/1.1等。例如,HTTP/1.1表示客户端正在使用HTTP协议的1.1版本。
*例如,以下是一个HTTP请求行的例子:
*GET /index.html HTTP/1.1
* 其中,GET是请求方法,/index.html是请求URI,HTTP/1.1是HTTP协议版本。
**/
/**
* text/html:HTML文本文档类型,用于表示HTML网页。
* application/json:JSON数据类型,用于表示结构化数据。
* application/xml:XML数据类型,用于表示结构化数据。
* image/jpeg:JPEG图像类型,用于表示JPEG格式的图像。
* image/png:PNG图像类型,用于表示PNG格式的图像。
* text/plain:纯文本类型,用于表示文本文件。
* application/pdf:PDF文档类型,用于表示PDF文件。
* application/javascript:JavaScript文件类型,用于表示JavaScript代码文件。
* application/octet-stream:二进制流类型,用于表示二进制文件,如图片、视频等。
**/
#define HTTP_RESPOND "%s %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s"
#define HTTP_VERSION "HTTP/1.1"
#define CONTENT_TYPE "application/json" //"application/x-www-form-urlencoded; charset=UTF-8"
#define HTTP_GET "GET"
#define HTTP_POST "POST"
#define HTTP_404 "<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1><p>The page you requested could not be found.</p></body></html>"
#define TOKEN_LENGTH 32 // 定义Token的长度
#define MT_N 624
#define MT_M 397
#define MT_MATRIX_A 0x9908B0DF
#define MT_UPPER_MASK 0x80000000
#define MT_LOWER_MASK 0x7FFFFFFF
typedef struct {
char key[MAX_HTTP_URI_FROM_LEN];
char value[MAX_HTTP_URI_FROM_LEN];
} http_url_form;
typedef struct {
int count;
char path[MAX_HTTP_URI_PATH_LEN];
http_url_form urlf[MAX_HTTP_URI_FROM_COUNT];
} http_url_t;
typedef struct {
http_url_t uri; //请求URL
char method[MAX_HTTP_METHOD_LEN]; //请求方法
char version[MAX_HTTP_VERSION_LEN];
} http_request_line_t;
//请求头
typedef struct {
char key[MAX_HTTP_HEADER_LEN];
char value[MAX_HTTP_HEADER_LEN];
} http_header_t;
typedef struct {
http_request_line_t request_line;
int head_count;
http_header_t headers[MAX_HTTP_HEADER_COUNT];
char body[MAX_HTTP_BODY_LEN];
} http_request_t;
typedef struct {
char version[MAX_HTTP_VERSION_LEN];
int status_code;
int head_count;
char content_type[MAX_HTTP_HEADER_LEN];
http_header_t headers[MAX_HTTP_HEADER_COUNT];
char body[MAX_HTTP_RESPOND_LEN];
} http_respond_t;
char *generate_token(int seed);
void printf_http_request(http_request_t * request);
//http_request_t *parse_http_request(char *request_string);
http_request_t *parse_http_request(http_request_t *request, char *request_string);
http_url_t* parse_http_from(http_url_t * urlt, char *query_string);
const char* get_http_status_message(int status_code);
char * http_request_respond(char * http_version, char * content_type, int state_code, char * body, int content_length);
#endif
示例:
__task void CH9121_HTTP_CL(void)
{
char * tx_data;
reset_chip();
os_dly_wait(3000);
ConfigFlag = 0;
init_ch9121();
int login = 0;
overflow = 0;
RecvFlag = 0;
ConfigFlag = 1;
uint32_t old_speed = 0;
while(1)
{
if(ConfigFlag == 1)
{
// 设置工作模式
overflow = 0;
ch9121_mode_select(TCP_Server_mode);
ConfigFlag = 0;
RecvFlag = 0;
overflow = 0;
}
if(ConfigFlag == 2)
{
init_ch9121();
RecvFlag = 0;
ConfigFlag = 0;
overflow = 0;
}
if(RecvFlag == 1 && config_flag == 0)
{
RecvFlag = 0;
net_rx_buf[511] = 0;//避免溢出
overflow = 0;
//解析HTTP请求
memset(&request, 0, sizeof request);
parse_http_request(&request, net_rx_buf);
memset(net_rx_buf, 0, 511);
printf_http_request(&request);
//判断请求是否正确
if(strcmp(HTTP_VERSION, (const char *)request.request_line.method))
{
if(strcmp(HTTP_GET, request.request_line.method) == 0)
{
if(strcmp(PathState, request.request_line.uri.path) == 0)
{
//memset(&sta, 0, sizeof sta);
char *json = JSON_State(sta);
tx_data = http_request_respond(HTTP_VERSION, CONTENT_TYPE, 200, json, strlen(json));
printf("%s, %d\n",tx_data , strlen(tx_data));
free(json);
}
else if(strcmp(PathValue, request.request_line.uri.path) == 0)
{
char * json = centrifugeToJson(&cen);
printf("%s, %d\n",json , strlen(json));
tx_data = http_request_respond(HTTP_VERSION, CONTENT_TYPE, 200, json, strlen(json));
free(json);
}
else if(strcmp(PathRun, request.request_line.uri.path) == 0)
{
if(strcmp(FromKeyRun, (const char *)(request.request_line.uri.urlf[0].key)) == 0)
{
int len = atoi((const char *)(request.request_line.uri.urlf[0].value));
if(len > 3) len = 3;
memset(&runs, 0, 10 *sizeof(RunData));
char *json = runDataToJsonString(runs, len);
tx_data = http_request_respond(HTTP_VERSION, CONTENT_TYPE, 200, json, strlen(json));
printf("%s, %d\n",tx_data , strlen(tx_data));
free(json);
}
else //全部运行记录
{
memset(&runs, 0, 10 *sizeof(RunData));
char *json = runDataToJsonString(runs, 1);
printf("hhhhhhhh\n");
tx_data = http_request_respond(HTTP_VERSION, CONTENT_TYPE, 200, json, strlen(json));
printf("%s, %d\n",tx_data , strlen(tx_data));
free(json);
}
}
else
{
tx_data = http_request_respond(HTTP_VERSION, CONTENT_TYPE, 404, HTTP_404, strlen(HTTP_404));
}
}
else
{
tx_data = http_request_respond(HTTP_VERSION, CONTENT_TYPE, 404, HTTP_404, strlen(HTTP_404));
}
}
else
{
tx_data = http_request_respond(HTTP_VERSION, CONTENT_TYPE, 404, HTTP_404, strlen(HTTP_404));
}
Usartx_SendBytes(UART4, tx_data, strlen(tx_data));
tx_data = NULL;
}
RecvFlag = 0;
os_dly_wait(1);
}
}
具体工程不能直接发到网上,因为这是公司的一个项目,所以有需要的可以联系我给源码文件