STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)

STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)

HTML5标准支持WEBSOCKET Client,因此对于基于HTML5标准的桌面型应用(如Electron APP)以及移动APP(如HBUILDERX APP),可以通过WIFI模块,实现与嵌入式端WEBSOCKET Server的通讯。WIFI模块与嵌入式端的接口有多种包括SPI和TTL串口等,WIFI转TTL串口在物联网领域用得比较多。这里设计基于WIFI转TTL模块HC-25的STM32 WEBSOCKET Server。STM32与HC-25之间为透传通讯。HC-25为3.3V供电模块。相同类型的透传模块还有HLK-M20。
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第1张图片

HC-25基本配置

HC-25支持网页配置模式,上电HC-25模块后,PC或手机搜索并连接HC-25热点如:
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第2张图片

打开浏览器,在地址栏输入 http://192.168.4.1,回车,出现模块网页界面:
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第3张图片
输入密码后,点击登录,可以进入网页设置。初始密码为空。可以点击“设置密码”框,进行密码设置,密码不小于 8 位。
然后可以修改串口的波特率,以及重设网络名称,网络密码以及网络地址:
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第4张图片
设置模块工作为Server模式:
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第5张图片

无需设置MQTT参数:
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第6张图片
保存后就可以将HC-25模块连接到STM32开发板。
然后重新从PC或手机连接HC-25热点后,就可以进行TCP连接,连接完成后,就可以与STM32的UART串口进行透明数据传输。也就完成了实现Websocket通讯的基础设置。

如果采用HLK-M20模块,则没有网页配置方式,需要先将模块接到串口工具上,上电后切换到AT模式,通过AT指令进行配置和保存,再重启后就进入透明传输模式。

STM32CUBEIDE配置

这里基于HAL库采用STM32L476RGT6开发板和STM32CUBEIDE开发环境实现范例。
首先建立工程并配置时钟:
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第7张图片
配置USART3作为连接HC-25模块的TTL串口:
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第8张图片
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第9张图片
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第10张图片
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第11张图片
保存并生成初始工程文件:
STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第12张图片
在工程目录的包含文件目录(\Core\Inc)建立websocket.h文件内容如下:

/*
Note: currently only for single websocket frame communication, can be expanded if necessary.
*/

#include 
#include   

#define WS_MIN_LEN_READ 1088
#define WS_MAX_LEN_WRITE 512

char g_ws_read_buf[WS_MIN_LEN_READ] = {0};
char g_ws_write_buf[WS_MAX_LEN_WRITE] = {0};
char g_ws_write_buf_t[WS_MAX_LEN_WRITE] = {0};

unsigned short int ws_handshake_done = 0; 
unsigned long long payloadLen = 0;  
unsigned long long pack_data_length;

#ifdef __cplusplus
extern "C"{
#endif
	
#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits)))) 	
const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	
typedef struct SHA1Context
{  
	unsigned Message_Digest[5];        
	unsigned Length_Low;               
	unsigned Length_High;              
	unsigned char Message_Block[64];   
	int Message_Block_Index;           
	int Computed;                      
	int Corrupted;                     
}SHA1Context; 

int tolower(int c);
int htoi(const char s[],int start,int len);
	
char fetch_sec_key(void); 
char compute_accept_key(void)	;
char shake_hand(void); 
	
void base64_encode(void);  	
char sha1_hash(void);
void SHA1Reset(SHA1Context * context); 
int SHA1Result(SHA1Context * context);
void SHA1Input(SHA1Context * context,const char * message_array,unsigned length);    
void SHA1ProcessMessageBlock(SHA1Context *); 
void SHA1PadMessage(SHA1Context * context); 

char analy_data(void); 
void pack_data(char * message, unsigned long long dn); 
void pack_data_bin(char * message, 	unsigned long long dn) ;

//if error, return 0, else return 1
char fetch_sec_key(void)  
{   
	const char * flag = "Sec-WebSocket-Key: "; 
	char * keyBegin = NULL; 
	int i = 0;	
 
	memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);    

	keyBegin = strstr(g_ws_read_buf, flag);  
	if(! keyBegin)   //w/o effective request head 
	{  
		return 0;  
	}
	
	//w/ effective request head
	keyBegin += strlen(flag);  

	for(i = 0; i < strlen(g_ws_read_buf); i++)  
	{  
		if((keyBegin[i] == 0x0A) || (keyBegin[i] == 0x0D))  //0x0A: new line; 0x0D: return
		{  
			break;  
		}  
		g_ws_write_buf[i] = keyBegin[i];  
	}  

	return 1;  
}  

//if error, return 0, else return 1
char compute_accept_key(void)  
{  
	const char * GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";  	  
	int i = 0, n = 0;   
	
	//websocket key
	if(! fetch_sec_key())
		return 0;

	strcat(g_ws_write_buf, GUID);  

	if(! sha1_hash())
		return 0;
 
	n = strlen(g_ws_write_buf); 
 
	memset(g_ws_read_buf, '\0', WS_MIN_LEN_READ);  

	for(i = 0; i < n; i += 2)  
	{        
		g_ws_read_buf[i / 2] = htoi(g_ws_write_buf, i, 2);      
	}   

	base64_encode();   

	return 1;  
}  

//if error, return 0, else return 1
char shake_hand(void)  
{  
	memset(g_ws_read_buf, '\0', WS_MIN_LEN_READ);  

	sprintf(g_ws_read_buf, "HTTP/1.1 101 Switching Protocols\r\n");  
	sprintf(g_ws_read_buf, "%sUpgrade: websocket\r\n", g_ws_read_buf);  
	sprintf(g_ws_read_buf, "%sConnection: Upgrade\r\n", g_ws_read_buf);  
	sprintf(g_ws_read_buf, "%sSec-WebSocket-Accept: %s\r\n\r\n", g_ws_read_buf, g_ws_write_buf);  

	return 1;
}


/*base64 function*/
void base64_encode(void)   
{    
	int tmp = 0, i = 0;	
	int prepare = 0;     
	int temp = strlen(g_ws_read_buf) % 3;     
	char * f = NULL;   	   
	char changed[4];   

	memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);   
	f = g_ws_write_buf;
	while (tmp < strlen(g_ws_read_buf))   
	{   
		temp = 0;   
		prepare = 0;   
		memset(changed, '\0', 4);   
		while (temp < 3)   
		{      
			if (tmp >= strlen(g_ws_read_buf))   
			{   
				break;   
			}   
			prepare = ((prepare << 8) | (g_ws_read_buf[tmp] & 0xFF));   
			tmp++;   
			temp++;   
		}   
		prepare = (prepare << ((3 - temp) * 8));      
		for (i = 0; i < 4 ;i++ )   
		{   
			if (temp < i)   
			{   
				changed[i] = 0x40;   
			}   
			else   
			{   
				changed[i] = (prepare >> ((3 - i) * 6)) & 0x3F;   
			}
			*f = base[changed[i]];     
			f++;   
		}   
	}   
	*f = '\0';
} 


/*SHA1 function*/
void SHA1Reset(SHA1Context * context)
{
	context->Length_Low             = 0;  
	context->Length_High            = 0;  
	context->Message_Block_Index    = 0;  

	context->Message_Digest[0]      = 0x67452301;  
	context->Message_Digest[1]      = 0xEFCDAB89;  
	context->Message_Digest[2]      = 0x98BADCFE;  
	context->Message_Digest[3]      = 0x10325476;  
	context->Message_Digest[4]      = 0xC3D2E1F0;  

	context->Computed   = 0;  
	context->Corrupted  = 0;  
}  


int SHA1Result(SHA1Context * context)
{
	if (context->Corrupted)
	{  
		return 0;  
	}  
	if (!context->Computed) 
	{  
		SHA1PadMessage(context);  
		context->Computed = 1;  
	}  
	return 1;  
}  


void SHA1Input(SHA1Context * context,const char * message_array,unsigned length)
{  
	if (!length) 
		return;  

	if (context->Computed || context->Corrupted)
	{  
		context->Corrupted = 1;  
		return;  
	}  

	while(length-- && !context->Corrupted)
	{  
		context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF);  

		context->Length_Low += 8;  

		context->Length_Low &= 0xFFFFFFFF;  
		if (context->Length_Low == 0)
		{  
			context->Length_High++;  
			context->Length_High &= 0xFFFFFFFF;  
			if (context->Length_High == 0) context->Corrupted = 1;  
		}  

		if (context->Message_Block_Index == 64)
		{  
			SHA1ProcessMessageBlock(context);  
		}  
		message_array++;  
	}  
}  

void SHA1ProcessMessageBlock(SHA1Context * context)
{  
	const unsigned K[] = {0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };  
	int         t;                  
	unsigned    temp;               
	unsigned    W[80];              
	unsigned    A, B, C, D, E;      

	for(t = 0; t < 16; t++)
	{  
		W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;  
		W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;  
		W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;  
		W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);  
	}  

	for(t = 16; t < 80; t++)
		W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);  

	A = context->Message_Digest[0];  
	B = context->Message_Digest[1];  
	C = context->Message_Digest[2];  
	D = context->Message_Digest[3];  
	E = context->Message_Digest[4];  

	for(t = 0; t < 20; t++)
	{  
		temp =  SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];  
		temp &= 0xFFFFFFFF;  
		E = D;  
		D = C;  
		C = SHA1CircularShift(30,B);  
		B = A;  
		A = temp;  
	}  
	for(t = 20; t < 40; t++)
	{  
		temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];  
		temp &= 0xFFFFFFFF;  
		E = D;  
		D = C;  
		C = SHA1CircularShift(30,B);  
		B = A;  
		A = temp;  
	}  
	for(t = 40; t < 60; t++)
	{  
		temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];  
		temp &= 0xFFFFFFFF;  
		E = D;  
		D = C;  
		C = SHA1CircularShift(30,B);  
		B = A;  
		A = temp;  
	}  
	for(t = 60; t < 80; t++)
	{  
		temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];  
		temp &= 0xFFFFFFFF;  
		E = D;  
		D = C;  
		C = SHA1CircularShift(30,B);  
		B = A;  
		A = temp;  
	}  
	context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;  
	context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;  
	context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;  
	context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;  
	context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;  
	context->Message_Block_Index = 0;  
}  

void SHA1PadMessage(SHA1Context *context)
{  
	if (context->Message_Block_Index > 55)
	{  
		context->Message_Block[context->Message_Block_Index++] = 0x80;  
		while(context->Message_Block_Index < 64)  
			context->Message_Block[context->Message_Block_Index++] = 0;  
		SHA1ProcessMessageBlock(context);  
		while(context->Message_Block_Index < 56) 
			context->Message_Block[context->Message_Block_Index++] = 0;  
	} 
	else
	{  
		context->Message_Block[context->Message_Block_Index++] = 0x80;  
		while(context->Message_Block_Index < 56)
			context->Message_Block[context->Message_Block_Index++] = 0;  
	}  
	context->Message_Block[56] = (context->Length_High >> 24 ) & 0xFF;  
	context->Message_Block[57] = (context->Length_High >> 16 ) & 0xFF;  
	context->Message_Block[58] = (context->Length_High >> 8 ) & 0xFF;  
	context->Message_Block[59] = (context->Length_High) & 0xFF;  
	context->Message_Block[60] = (context->Length_Low >> 24 ) & 0xFF;  
	context->Message_Block[61] = (context->Length_Low >> 16 ) & 0xFF;  
	context->Message_Block[62] = (context->Length_Low >> 8 ) & 0xFF;  
	context->Message_Block[63] = (context->Length_Low) & 0xFF;  

	SHA1ProcessMessageBlock(context);  
}  

//if error, return 0, else return 1
char sha1_hash(void)
{ 
	SHA1Context sha = {0};
	SHA1Reset(&sha);  
	SHA1Input(&sha, g_ws_write_buf, strlen(g_ws_write_buf));  

	if (! SHA1Result(&sha))
	{  
		printf("%s-%d:Could not compute message digest.\n", __func__, __LINE__);  
		return 0;  
	}
	else
	{  
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);  
		sprintf(g_ws_write_buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],  
				sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);  

		return 1;  
	}  
}


/*convertion function*/
int tolower(int c)   
{   
	if (c >= 'A' && c <= 'Z')   
	{   
		return c + 'a' - 'A';   
	}   
	else   
	{   
		return c;   
	}   
}   

int htoi(const char s[],int start,int len)   
{   
	int i,j;   
	int n = 0;
	if (s[0] == '0' && (s[1]=='x' || s[1]=='X'))
	{   
		i = 2;   
	}   
	else   
	{   
		i = 0;   
	}   
	i+=start;  
	j=0;  
	for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'f') || (s[i] >='A' && s[i] <= 'F');++i)   
	{     
		if(j>=len)  
		{  
			break;  
		}  
		if (tolower(s[i]) > '9')   
		{   
			n = 16 * n + (10 + tolower(s[i]) - 'a');   
		}   
		else   
		{   
			n = 16 * n + (tolower(s[i]) - '0');   
		}   
		j++;  
	}   
	return n;   
}   	

/*
Frame format:  
      0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 ......
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+
*/
char analy_data(void)  
{   
	char fin = 0;
	char maskFlag = 0;
	char masks[4] = {0};  
	char temp[8]; 
	unsigned long long i = 0;


  payloadLen = 0;
	if (strlen(g_ws_read_buf) < 2)   
	{  
    //data len error.
		return 0;  
	}  

	fin = (g_ws_read_buf[0] & 0x80) == 0x80; 
	if (!fin)  
	{  
    //fin error.
		return 0;
	}  

	maskFlag = (g_ws_read_buf[1] & 0x80) == 0x80;   
	if (!maskFlag)  
	{  
    //mask flag error.
		return 0;
	}  

	payloadLen = g_ws_read_buf[1] & 0x7F;  
	if (payloadLen == 126)  
	{        
		memcpy(masks, g_ws_read_buf + 4, 4);        
		payloadLen = (((unsigned short)g_ws_read_buf[2] ) << 8) | ((unsigned short)g_ws_read_buf[3]);      
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);  
		memcpy(g_ws_write_buf, g_ws_read_buf + 8, payloadLen);  
	}  
	else if (payloadLen == 127)  
	{  
		memcpy(masks, g_ws_read_buf + 10, 4);    
		for ( i = 0; i < 8; i++)  
		{  
			temp[i] = g_ws_read_buf[2 + i];  
		}   

		memcpy(&payloadLen,temp,8);      
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);   
		memcpy(g_ws_write_buf, g_ws_read_buf + 14, payloadLen);//toggle error(core dumped) if data is too long.  
     
	}  
	else  
	{     
		memcpy(masks, g_ws_read_buf + 2, 4);       
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);  
		memcpy(g_ws_write_buf, g_ws_read_buf + 6, payloadLen);   
	}  

	memset(g_ws_write_buf_t, '\0', WS_MAX_LEN_WRITE); 
	for (i = 0; i < payloadLen; i++)  
	{  
		g_ws_write_buf_t[i] = (char)(g_ws_write_buf[i] ^ masks[i % 4]);
	}  
	
  //get data: g_ws_write_buf_t w/ data length: payloadLen  
	
	return 1; 
}  

void pack_data(char * message, 	unsigned long long dn)  // message: input; dn: input; len: output
{   
  if (dn<=0) pack_data_length = 0;  
	else if ((dn > 0)&&(dn < 126))  
	{   
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);      
		g_ws_write_buf[0] = 0x81;  
		g_ws_write_buf[1] = dn;  
		memcpy(g_ws_write_buf + 2, message, dn);  
		pack_data_length = dn + 2;  
	}  
	else if ((dn >= 126)&&(dn <= 0xFFFF)) 
	{    
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x81;  
		g_ws_write_buf[1] = 126;  
		g_ws_write_buf[2] = ((dn >> 8) & 0xFF);  
		g_ws_write_buf[3] = (dn & 0xFF);  
		memcpy(g_ws_write_buf + 4, message, dn);      
		pack_data_length = dn + 4;  
	}  
	else  
	{  
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x81;  
		g_ws_write_buf[1] = 127;  
		g_ws_write_buf[2] = ((dn >> 56) & 0xFF);
		g_ws_write_buf[3] = ((dn >> 48) & 0xFF);
		g_ws_write_buf[4] = ((dn >> 40) & 0xFF);
		g_ws_write_buf[5] = ((dn >> 32) & 0xFF);
		g_ws_write_buf[6] = ((dn >> 24) & 0xFF);
		g_ws_write_buf[7] = ((dn >> 16) & 0xFF);
		g_ws_write_buf[8] = ((dn >> 8) & 0xFF);
		g_ws_write_buf[9] = ((dn >> 0) & 0xFF);
		
 
		memcpy(g_ws_write_buf + 10, message, dn);      
		pack_data_length = dn + 10;  
	} 
	

	
	//get data: g_ws_write_buf w/ length: *len
	//*len is essential for byte communication beyond character communication
}  

void pack_data_bin(char * message, 	unsigned long long dn)  // message: input; dn: input; len: output
{
  if (dn<=0) pack_data_length = 0;
	else if ((dn > 0)&&(dn < 126))
	{
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x82;
		g_ws_write_buf[1] = dn;
		memcpy(g_ws_write_buf + 2, message, dn);
		pack_data_length = dn + 2;
	}
	else if ((dn >= 126)&&(dn <= 0xFFFF))
	{
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x82;
		g_ws_write_buf[1] = 126;
		g_ws_write_buf[2] = ((dn >> 8) & 0xFF);
		g_ws_write_buf[3] = (dn & 0xFF);
		memcpy(g_ws_write_buf + 4, message, dn);
		pack_data_length = dn + 4;
	}
	else
	{
		memset(g_ws_write_buf, '\0', WS_MAX_LEN_WRITE);
		g_ws_write_buf[0] = 0x82;
		g_ws_write_buf[1] = 127;
		g_ws_write_buf[2] = ((dn >> 56) & 0xFF);
		g_ws_write_buf[3] = ((dn >> 48) & 0xFF);
		g_ws_write_buf[4] = ((dn >> 40) & 0xFF);
		g_ws_write_buf[5] = ((dn >> 32) & 0xFF);
		g_ws_write_buf[6] = ((dn >> 24) & 0xFF);
		g_ws_write_buf[7] = ((dn >> 16) & 0xFF);
		g_ws_write_buf[8] = ((dn >> 8) & 0xFF);
		g_ws_write_buf[9] = ((dn >> 0) & 0xFF);


		memcpy(g_ws_write_buf + 10, message, dn);
		pack_data_length = dn + 10;
	}



	//get data: g_ws_write_buf w/ length: *len
	//*len is essential for byte communication beyond character communication
}

#ifdef __cplusplus
}
#endif


STM32主代码

STM32主代码实现接受WEBSOCKET连接,范例功能设计为在接收到两个字节时,返回这两个字节, 在接收到其他数据时,返回"F" (fault)。
代码里用到延时函数原理参考 STM32 HAL us delay(微秒延时)的指令延时实现方式及优化 。
完整的main.c文件代码如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * 

© Copyright (c) 2021 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "websocket.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ #define WRXMAX 1460 float usDelayBase; void PY_usDelayTest(void) { uint32_t firstms, secondms; uint32_t counter = 0; firstms = HAL_GetTick()+1; secondms = firstms+1; while(uwTick!=firstms) ; while(uwTick!=secondms) counter++; usDelayBase = ((float)counter)/1000; } void PY_Delay_us_t(uint32_t Delay) { uint32_t delayReg; uint32_t usNum = (uint32_t)(Delay*usDelayBase); delayReg = 0; while(delayReg!=usNum) delayReg++; } uint32_t PY_usDelayOptimize(void) { uint32_t firstms, secondms; float coe = 1.0; firstms = HAL_GetTick(); PY_Delay_us_t(1000000) ; secondms = HAL_GetTick(); coe = ((float)1000)/(secondms-firstms); usDelayBase = coe*usDelayBase; } void PY_Delay_us(uint32_t Delay) { uint32_t delayReg; uint32_t usNum = (uint32_t)(Delay*usDelayBase); delayReg = 0; while(delayReg!=usNum) delayReg++; } void PY_Delay_us_enh(uint32_t Delay) { uint32_t delayReg; uint32_t msNum = Delay/1000; uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase); if(msNum>0) HAL_Delay(msNum); delayReg = 0; while(delayReg!=usNum) delayReg++; } /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ uint8_t Uart3_RxBuff[WRXMAX+1]={0}; //for max length of one package of Ethernet uint8_t uart3_rx_status = 0; /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ UART_HandleTypeDef huart3; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART3_UART_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART3_UART_Init(); /* USER CODE BEGIN 2 */ PY_usDelayTest(); PY_usDelayOptimize(); PY_Delay_us(2000000); uart3_rx_status=0; HAL_UART_Receive_IT(&huart3, Uart3_RxBuff, 1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { //start of websocket connection if(uart3_rx_status==1) { HAL_UART_Receive(&huart3, (uint8_t *)&Uart3_RxBuff[1], WS_MIN_LEN_READ-1, 2000); memcpy(g_ws_read_buf, Uart3_RxBuff, WS_MIN_LEN_READ); //Receving data ends with "0x0A" and "0x0D" for recognition if (compute_accept_key()==0) { uart3_rx_status = 0; } else { uart3_rx_status = 2; shake_hand() ; HAL_UART_Transmit(&huart3, g_ws_read_buf, strlen(g_ws_read_buf), 2000); } memset(&Uart3_RxBuff[1], '\0', WRXMAX); //Set "end character" for recognition HAL_UART_Receive_IT(&huart3, (uint8_t *)&Uart3_RxBuff[0], 1); } //end of websocket connection //start of data receiving and processing if(uart3_rx_status==3) { HAL_UART_Receive(&huart3, (uint8_t *)&Uart3_RxBuff[1], WS_MIN_LEN_READ-1, 2000); memcpy(g_ws_read_buf, Uart3_RxBuff, WS_MIN_LEN_READ); analy_data() ; if(payloadLen==2) { pack_data(g_ws_write_buf_t, 2) ; HAL_UART_Transmit(&huart3, g_ws_write_buf, pack_data_length, 2000); } else{ g_ws_write_buf_t[0]='F'; //Failure for data receiving length pack_data(g_ws_write_buf_t, 1) ; HAL_UART_Transmit(&huart3, g_ws_write_buf, pack_data_length, 2000); } uart3_rx_status=2; memset(&Uart3_RxBuff[0], '\0', WRXMAX); //Set "end character" for recognition HAL_UART_Receive_IT(&huart3, (uint8_t *)&Uart3_RxBuff[0], 1); } //end of data receiving and processing /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) { Error_Handler(); } /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 1; RCC_OscInitStruct.PLL.PLLN = 10; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } } /** * @brief USART3 Initialization Function * @param None * @retval None */ static void MX_USART3_UART_Init(void) { /* USER CODE BEGIN USART3_Init 0 */ /* USER CODE END USART3_Init 0 */ /* USER CODE BEGIN USART3_Init 1 */ /* USER CODE END USART3_Init 1 */ huart3.Instance = USART3; huart3.Init.BaudRate = 115200; huart3.Init.WordLength = UART_WORDLENGTH_8B; huart3.Init.StopBits = UART_STOPBITS_1; huart3.Init.Parity = UART_PARITY_NONE; huart3.Init.Mode = UART_MODE_TX_RX; huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart3.Init.OverSampling = UART_OVERSAMPLING_16; huart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart3) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART3_Init 2 */ /* USER CODE END USART3_Init 2 */ } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); } /* USER CODE BEGIN 4 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) { if(UartHandle==&huart3) { if(uart3_rx_status==0) { uart3_rx_status=1; } if(uart3_rx_status==2) { uart3_rx_status=3; } } } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */

测试过程

  1. 嵌入式端上电后,打开PC或手机WIFI,查找对应的热点如HC-25-TEST,然后输入密码连接。如果有出现当前WIFI热点不能上网的提示时,选择保持此连接;
  2. 用Chrome浏览器打开下面代码的websocket_test.html文件;
  3. 点击”Run WebSocket“链接,触发websocket连接及发送两个字符"OK";
  4. 从开发者工具的控制台查看过程及接收信息。


   
   
   Websocket Demo
    
      
        
   
   
   
      
      
   

STM32串口WEBSOCKET Server设计(基于HC-25 WIFI模块透传模式)_第13张图片

WEBSOCKET协议应用特征

这里的WEBSOCKET协议应用特征如下:

  1. 只接受客户端发来的单帧数据,即FIN为0时认为错误不做处理。因此如果要发来的数据很长时,要在客户端自行先做分段,再将分段按单帧进行发送;
  2. 只接受客户端发来的加密数据,未加密时认为错误不做处理;
  3. 客户端发来的opcode对服务器端没有价值,嵌入式服务器端当作字节数据处理即可;
  4. 服务器端向客户端发送数据时不做数据加密;
  5. 服务器端向客户端发送的opcode有意义,浏览器客户端的处理方式会不同。

–End–

你可能感兴趣的:(STM32,websocket,stm32,串口websocket,HC-25透传模式,server)