Porting the MQTT protocol to STM32 and using the W5500 Ethernet chip to connect to Ali Cloud

ORIGINAL POST
By None
components
Hardware Components
stm32f103RCT6
X 1
W5500
X 1
network cable*1
X 1
Software Apps and online services
Keil5
pahoMqtt package
details

porting.PNG

Porting the MQTT protocol to STM32 and using the W5500 Ethernet chip to connect to Ali Cloud

Preface

I am very happy to have the opportunity to do this project. I have learned a lot. But when I first started, I really started from scratch. The information I found on the Internet was very different. There were problems with many codes, and it was really useful to transplant the modules made by others one by one. Very troublesome, in order to prevent everyone who needs to do something like this Internet of Things project from going wrong, I try my best to clarify the core affairs of my project this time, my personal ability is limited, it is troublesome to spray and give advice if there is a mistake. Thank you all.

Topic

First, figure out what to do. As the name implies, the content of this project is:
① Port the MQTT protocol to stm32;
② Connect to the local router with a network cable through the W5500 Ethernet chip;
③Connect to Alibaba Cloud via stm32 local network port

Tools used: Keil5, pahoMqtt package, stm32f103RCT6, W5500, network cable*1
Debugging tools: 485 communication usart port serial communication, serial debugging assistant, communication modem, Alibaba Cloud, MQTTfx, MQTTBOX (Of course, if the serial port is not used, single-step debugging is also possible, I was just like that , I was about to crash, and finally got a serial port, which is much more convenient and simple)

Learning materials: Here, Amway and promote an up host called Orange on station B. The video he made is very good, very suitable for newbies to start, and you can understand a lot of things by watching the video;
Friendship link:stm32 mqtt transplant
Please kindly remind me if there is a violation of authority, so I can delete it.

Enter the topic, MQTT protocol, not much to say about the hardware part.
The first is to download the Mqtt package, which can be downloaded on github. Many other mqtt ported blog posts have links, but I also post them here;
Friendship link:PahoMqtt-Github download
After downloading, decompress, import all the source files under paho.mqtt.embedded-c-masterMQTTPacketsrc into your project, and then import all the header file paths of src , And finally import the transport.c and .h under /sample;
So the first step is to transplant successfully. Many people say that there are many functions in transport.c that are compiled under Linux, so they can’t be used. It must be 2333, which is not used. We want What it does is to rewrite the functions in the transport.c and transport.h files. There are

transport_sendPacketBuffer //Send data packet to the server
transport_getdata //Get data from the server
transport_open // Create socket, bind, connect, etc.
transport_close // Close the socket
these four functions;
The subsequent Connect, Pub, Sub, and Disconnect are based on these four functions, as well as some of the functions in MQTT_Package that do not require you to write;
The most important thing is to figure out the working mode of the MQTT protocol in order to realize the function, whether you use some commonly used communication channels such as SIM800C, 8266, Lora, W5500, etc. Are similar;
How it works: I won’t elaborate on specific terms. Connect to the server locally as a client, and the server as a Broker. You can subscribe to topics from Broker or publish topics to Broker. Similarly, as a server, Broker can also treat your Pub and Sub, macroscopically, they are equal;
First, you need to have the domain name or IP of the server. Only the domain name needs to do DNS resolution. If there is IP, you can connect directly to the IP. The port number depends on the server you want to connect to. Alibaba Cloud is fixed 1883. , Communication cat 18831, etc. Before connecting to Alibaba Cloud, I strongly recommend that the connection of the communication cat be adjusted as an experiment as a hand training;
When connecting, there are several parameters:
data.clientID.cstring // Client ID
data.keepAliveInterval //The length of the heartbeat. The so-called heartbeat is the waiting time. Alibaba Cloud stipulates that it must be // greater than 60, otherwise the connection is refused
data.cleansession// Clear bit, default 1
data.username.cstring//User name
data.password.cstring//password
data.MQTTVersion //Specify the version number, such as Viersion4, connect to Alibaba Cloud, pass through
Don’t elaborate on Qos;
The specific process of connecting to Alibaba Cloud: send a connection message> receive CONNACK (the cloud confirms your connection receipt)> subscribe> receive SUBACK, return to Qos> continue to read for polling , What to do, such as Pub, heartbeat and waiting for cloud Pub;
Alibaba Cloud says in the JDK manual for C that the message format of Pub and Sub is specified as Json format, so you should pay attention to the Json format when parsing Pub and Sub. Whether it conforms to the Json format, there are many online tests on the Internet, please search by yourself;
is very important. Generally speaking, the read in the built-in Socket library is blocking. If you need to (approximately) Pub and Sub at the same time, you must modify it to non-blocking. , Not difficult;

Core code

The core code is posted below.

/**
*@Todo: Send data to the server via tcp
*/
int transport_sendPacketBuffer(unsigned char* buf, int buflen)
{
  return send(SOCK_TCPS,buf,buflen);
}

/**
 *@Todo: Receiving data sent by tcp server in blocking mode
*/
int transport_getdata(unsigned char* buf, int count)
{
  return recv(SOCK_TCPS,buf,count);
}

/**
 *@Todo: Open a socket and connect to the server
 *@retval less than means fail
*/
int transport_open(void){
	int32_t ret;
	//New socket
	ret = socket(1, Sn_MR_TCP,2001, 0x00);
	 if(ret != SOCK_TCPS){
    printf("%d:Socket Errorrn",SOCK_TCPS);
    while(1);
  }else{
    printf("%d:Openedrn",SOCK_TCPS);
  }
	 //Connect to TCP server
	ret = connect(SOCK_TCPS,domain_ip,1883); 
	if(ret != SOCK_OK){
    printf("%d:Socket Connect Errorrn",SOCK_TCPS);
    //while(1);
  }else{
    printf("%d:Connectedrn",SOCK_TCPS);
  }		
	return 0;
}

/**
 *@Todo: Close Socket
*/
int transport_close(void)
{
  disconnect(SOCK_TCPS);
  close(SOCK_TCPS);
  return 0;
}
/***************************The above are the basic four functions***************** *******/


	while(1){
		timeh++;
			if(connect_flag == 1&&timeh==1000)
		  {  // Json format, data is released according to variables defined in Ailiyun, payload is the payload
				Ua = 56.7 -rand()%10+1;
				Ub = 34.8 -rand()%10+1;
				Uc = 69.2 -rand()%10+1;
	      sprintf((char*)payload_out,"{"params":{"nUa":+%0.1f,"Ub":+%0.1f,"Uc":+%0.1f},"method":"thing.event.property.post"}",Ua,Ub,Uc);
				payload_out_len = strlen((char*)payload_out);
				topicString.cstring = topic_pub_set_info;		//Publish push topic
				len = MQTTSerialize_publish(buf, buflen, 0, req_qos, retained, msgid, topicString, payload_out, payload_out_len);
				rc = transport_sendPacketBuffer(buf, len);
				if(rc == len)															//
					printf("send PUBLISH Successfullyrn"); // The length of the sent out and the received back are the same, which means the release is ok
		  }
			if(timeh>=1000)
				timeh = 0;
			switch(msgtypes)
		{

			case CONNECT:	len = MQTTSerialize_connect(buf, buflen, &data); 						//Send connection information
							rc = transport_sendPacketBuffer(buf, len);		//Send connection information
							if(rc == len){															//
								printf("send CONNECT Successfullyrn");
							}
							else{
								msgtypes =  CONNECT; 
								continue;
							}
							break;

			case CONNACK:   if(MQTTDeserialize_connack(&sessionPresent, &connack_rc,buf, buflen))	//Retract the execution
							{
								printf("MQTT is conncet OK!rn");									//Receipt of receipt, connection is successful
								connect_flag = 1;
								msgtypes = SUBSCRIBE;													//Subscription operation
							}
							else
							{
								printf("Unable to connect, return code %drn", connack_rc);		//failure
							}
							break;
			case SUBSCRIBE: topicString.cstring = topic_sub_set_info;
							len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);
							rc = transport_sendPacketBuffer(buf, len);
							if(rc == len){
								goto tt;
							}
							else
							{
								continue;
							}
							break;
			case SUBACK: 	rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos,buf, buflen);	//Subscription is successful QoS                                                     
							printf("granted qos is %drn", granted_qos);       							 
							if (granted_qos != 0)
								//goto exit;
							printf("Get qos");
	
							break;
			case PUBLISH:	rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,&payload_in, &payloadlen_in, (unsigned char*)buf, buflen);	//Receive server message
							printf("message arrived : %srn", payload_in);
							json = cJSON_Parse((char *)payload_in);			//Analyze the data packet
							if (!json)  
							{  
								printf("Error before: [%s]rn",cJSON_GetErrorPtr());  
							} 
							else
							{
								json_id = cJSON_GetObjectItem(json , "id"); 
								if(json_id->type == cJSON_String)
								{
									printf("id:%srn", json_id->valuestring);  
								}
								json_params = cJSON_GetObjectItem(json , "params");
								if(json_params)  
								{  
									
									if(cJSON_GetObjectItem(json_params, "LEDSwitch"))
									{
                      
									}
									if(cJSON_GetObjectItem(json_params, "p2"))
									{
										
										}  
									}
								} 
							cJSON_Delete(json);   //Free up space
							if(qos == 1)
							{
								printf("publish qos is 1,send publish ack.rn");							//
								memset(buf,0,buflen);
								len = MQTTSerialize_ack(buf,buflen,PUBACK,dup,msgid);   					//publish ack                       
								rc = transport_sendPacketBuffer(buf, len);			
								if(rc == len)
									printf("send PUBACK Successfullyrn");
								else
									printf("send PUBACK failedrn");                                       
							}
							break;
			case PUBACK:    printf("PUBACK!rn");	
							break;

			case PUBREC:    printf("PUBREC!rn");     				//just for qos2
							USART2_sendbyte(12);
							break;
							
			case PUBREL:    printf("PUBREL!rn");        			//just for qos2
							break;
			case PUBCOMP:   printf("PUBCOMP!rn");        			//just for qos2
							break;
			case PINGREQ:   len = MQTTSerialize_pingreq(buf, buflen);							
							rc = transport_sendPacketBuffer(buf, len);
							break;
			case PINGRESP:	printf("mqtt server Pongrn");  			   
 							msgtypes = PINGREQ;
							break;
			default:
							break;
		}
		
		if(msgtypes!=SUBSCRIBE){
  tt:			
			    rc=MQTTPacket_read(buf, buflen, transport_getdata);       	       Polling, corresponding processing according to the received receipt
			    if(rc >0)													//If you receive the correct, existing receipt, then enter the corresponding state
				  {
				  	msgtypes = rc;
				  }else msgtypes=PINGREQ;
		  }

	}
	exit:
	transport_close();

 

The MQTT communication part uses the above state machine. In fact, most of the codes are available online, but they are not completely correct, and the understanding of the code is different according to each person’s situation.
may be considered original for the time being (? After all, I did it myself, if it violates, please remind me to modify it.

Regarding the DNS resolution of the domain name, you can transplant it yourself on the Internet. I tried to write it myself. After writing it for a day, I didn’t write it out. It is more convenient to transplant it directly;

in conclusion

I feel that there is a lot of text when I write. I don’t know how to write articles. If you have any questions, please ask. If you see them, you will answer them. I personally think that you don’t need to spend money to buy information on this project. Yes, it is really hard to start from 0… I also spent a few days to figure it out. The most important thing is to understand that blind liver code is of no use (to myself…)

porting.PNG

Porting the MQTT protocol to STM32 and using the W5500 Ethernet chip to connect to Ali Cloud

Preface

I am very happy to have the opportunity to do this project. I have learned a lot. But when I first started, I really started from scratch. The information I found on the Internet was very different. There were problems with many codes, and it was really useful to transplant the modules made by others one by one. Very troublesome, in order to prevent everyone who needs to do something like this Internet of Things project from going wrong, I try my best to clarify the core affairs of my project this time, my personal ability is limited, it is troublesome to spray and give advice if there is a mistake. Thank you all.

Topic

First, figure out what to do. As the name implies, the content of this project is:
① Port the MQTT protocol to stm32;
② Connect to the local router with a network cable through the W5500 Ethernet chip;
③Connect to Alibaba Cloud via stm32 local network port

Tools used: Keil5, pahoMqtt package, stm32f103RCT6, W5500, network cable*1
Debugging tools: 485 communication usart port serial communication, serial debugging assistant, communication modem, Alibaba Cloud, MQTTfx, MQTTBOX (Of course, if the serial port is not used, single-step debugging is also possible, I was just like that , I was about to crash, and finally got a serial port, which is much more convenient and simple)

Learning materials: Here, Amway and promote an up host called Orange on station B. The video he made is very good, very suitable for newbies to start, and you can understand a lot of things by watching the video;
Friendship link:stm32 mqtt transplant
Please kindly remind me if there is a violation of authority, so I can delete it.

Enter the topic, MQTT protocol, not much to say about the hardware part.
The first is to download the Mqtt package, which can be downloaded on github. Many other mqtt ported blog posts have links, but I also post them here;
Friendship link:PahoMqtt-Github download
After downloading, decompress, import all the source files under paho.mqtt.embedded-c-masterMQTTPacketsrc into your project, and then import all the header file paths of src , And finally import the transport.c and .h under /sample;
So the first step is to transplant successfully. Many people say that there are many functions in transport.c that are compiled under Linux, so they can’t be used. It must be 2333, which is not used. We want What it does is to rewrite the functions in the transport.c and transport.h files. There are

transport_sendPacketBuffer //Send data packet to the server
transport_getdata //Get data from the server
transport_open // Create socket, bind, connect, etc.
transport_close // Close the socket
these four functions;
The subsequent Connect, Pub, Sub, and Disconnect are based on these four functions, as well as some of the functions in MQTT_Package that do not require you to write;
The most important thing is to figure out the working mode of the MQTT protocol in order to realize the function, whether you use some commonly used communication channels such as SIM800C, 8266, Lora, W5500, etc. Are similar;
How it works: I won’t elaborate on specific terms. Connect to the server locally as a client, and the server as a Broker. You can subscribe to topics from Broker or publish topics to Broker. Similarly, as a server, Broker can also treat your Pub and Sub, macroscopically, they are equal;
First, you need to have the domain name or IP of the server. Only the domain name needs to do DNS resolution. If there is IP, you can connect directly to the IP. The port number depends on the server you want to connect to. Alibaba Cloud is fixed 1883. , Communication cat 18831, etc. Before connecting to Alibaba Cloud, I strongly recommend that the connection of the communication cat be adjusted as an experiment as a hand training;
When connecting, there are several parameters:
data.clientID.cstring // Client ID
data.keepAliveInterval //The length of the heartbeat. The so-called heartbeat is the waiting time. Alibaba Cloud stipulates that it must be // greater than 60, otherwise the connection is refused
data.cleansession// Clear bit, default 1
data.username.cstring//User name
data.password.cstring//password
data.MQTTVersion //Specify the version number, such as Viersion4, connect to Alibaba Cloud, pass through
Don’t elaborate on Qos;
The specific process of connecting to Alibaba Cloud: send a connection message> receive CONNACK (the cloud confirms your connection receipt)> subscribe> receive SUBACK, return to Qos> continue to read for polling , What to do, such as Pub, heartbeat and waiting for cloud Pub;
Alibaba Cloud says in the JDK manual for C that the message format of Pub and Sub is specified as Json format, so you should pay attention to the Json format when parsing Pub and Sub. Whether it conforms to the Json format, there are many online tests on the Internet, please search by yourself;
is very important. Generally speaking, the read in the built-in Socket library is blocking. If you need to (approximately) Pub and Sub at the same time, you must modify it to non-blocking. , Not difficult;

Core code

The core code is posted below.

/**
*@Todo: Send data to the server via tcp
*/
int transport_sendPacketBuffer(unsigned char* buf, int buflen)
{
  return send(SOCK_TCPS,buf,buflen);
}

/**
 *@Todo: Receiving data sent by tcp server in blocking mode
*/
int transport_getdata(unsigned char* buf, int count)
{
  return recv(SOCK_TCPS,buf,count);
}

/**
 *@Todo: Open a socket and connect to the server
 *@retval less than means fail
*/
int transport_open(void){
	int32_t ret;
	//New socket
	ret = socket(1, Sn_MR_TCP,2001, 0x00);
	 if(ret != SOCK_TCPS){
    printf("%d:Socket Errorrn",SOCK_TCPS);
    while(1);
  }else{
    printf("%d:Openedrn",SOCK_TCPS);
  }
	 //Connect to TCP server
	ret = connect(SOCK_TCPS,domain_ip,1883); 
	if(ret != SOCK_OK){
    printf("%d:Socket Connect Errorrn",SOCK_TCPS);
    //while(1);
  }else{
    printf("%d:Connectedrn",SOCK_TCPS);
  }		
	return 0;
}

/**
 *@Todo: Close Socket
*/
int transport_close(void)
{
  disconnect(SOCK_TCPS);
  close(SOCK_TCPS);
  return 0;
}
/***************************The above are the basic four functions***************** *******/


	while(1){
		timeh++;
			if(connect_flag == 1&&timeh==1000)
		  {  // Json format, data is released according to variables defined in Ailiyun, payload is the payload
				Ua = 56.7 -rand()%10+1;
				Ub = 34.8 -rand()%10+1;
				Uc = 69.2 -rand()%10+1;
	      sprintf((char*)payload_out,"{"params":{"nUa":+%0.1f,"Ub":+%0.1f,"Uc":+%0.1f},"method":"thing.event.property.post"}",Ua,Ub,Uc);
				payload_out_len = strlen((char*)payload_out);
				topicString.cstring = topic_pub_set_info;		//Publish push topic
				len = MQTTSerialize_publish(buf, buflen, 0, req_qos, retained, msgid, topicString, payload_out, payload_out_len);
				rc = transport_sendPacketBuffer(buf, len);
				if(rc == len)															//
					printf("send PUBLISH Successfullyrn"); // The length of the sent out and the received back are the same, which means the release is ok
		  }
			if(timeh>=1000)
				timeh = 0;
			switch(msgtypes)
		{

			case CONNECT:	len = MQTTSerialize_connect(buf, buflen, &data); 						//Send connection information
							rc = transport_sendPacketBuffer(buf, len);		//Send connection information
							if(rc == len){															//
								printf("send CONNECT Successfullyrn");
							}
							else{
								msgtypes =  CONNECT; 
								continue;
							}
							break;

			case CONNACK:   if(MQTTDeserialize_connack(&sessionPresent, &connack_rc,buf, buflen))	//Retract the execution
							{
								printf("MQTT is conncet OK!rn");									//Receipt of receipt, connection is successful
								connect_flag = 1;
								msgtypes = SUBSCRIBE;													//Subscription operation
							}
							else
							{
								printf("Unable to connect, return code %drn", connack_rc);		//failure
							}
							break;
			case SUBSCRIBE: topicString.cstring = topic_sub_set_info;
							len = MQTTSerialize_subscribe(buf, buflen, 0, msgid, 1, &topicString, &req_qos);
							rc = transport_sendPacketBuffer(buf, len);
							if(rc == len){
								goto tt;
							}
							else
							{
								continue;
							}
							break;
			case SUBACK: 	rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos,buf, buflen);	//Subscription is successful QoS                                                     
							printf("granted qos is %drn", granted_qos);       							 
							if (granted_qos != 0)
								//goto exit;
							printf("Get qos");
	
							break;
			case PUBLISH:	rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,&payload_in, &payloadlen_in, (unsigned char*)buf, buflen);	//Receive server message
							printf("message arrived : %srn", payload_in);
							json = cJSON_Parse((char *)payload_in);			//Analyze the data packet
							if (!json)  
							{  
								printf("Error before: [%s]rn",cJSON_GetErrorPtr());  
							} 
							else
							{
								json_id = cJSON_GetObjectItem(json , "id"); 
								if(json_id->type == cJSON_String)
								{
									printf("id:%srn", json_id->valuestring);  
								}
								json_params = cJSON_GetObjectItem(json , "params");
								if(json_params)  
								{  
									
									if(cJSON_GetObjectItem(json_params, "LEDSwitch"))
									{
                      
									}
									if(cJSON_GetObjectItem(json_params, "p2"))
									{
										
										}  
									}
								} 
							cJSON_Delete(json);   //Free up space
							if(qos == 1)
							{
								printf("publish qos is 1,send publish ack.rn");							//
								memset(buf,0,buflen);
								len = MQTTSerialize_ack(buf,buflen,PUBACK,dup,msgid);   					//publish ack                       
								rc = transport_sendPacketBuffer(buf, len);			
								if(rc == len)
									printf("send PUBACK Successfullyrn");
								else
									printf("send PUBACK failedrn");                                       
							}
							break;
			case PUBACK:    printf("PUBACK!rn");	
							break;

			case PUBREC:    printf("PUBREC!rn");     				//just for qos2
							USART2_sendbyte(12);
							break;
							
			case PUBREL:    printf("PUBREL!rn");        			//just for qos2
							break;
			case PUBCOMP:   printf("PUBCOMP!rn");        			//just for qos2
							break;
			case PINGREQ:   len = MQTTSerialize_pingreq(buf, buflen);							
							rc = transport_sendPacketBuffer(buf, len);
							break;
			case PINGRESP:	printf("mqtt server Pongrn");  			   
 							msgtypes = PINGREQ;
							break;
			default:
							break;
		}
		
		if(msgtypes!=SUBSCRIBE){
  tt:			
			    rc=MQTTPacket_read(buf, buflen, transport_getdata);       	       Polling, corresponding processing according to the received receipt
			    if(rc >0)													//If you receive the correct, existing receipt, then enter the corresponding state
				  {
				  	msgtypes = rc;
				  }else msgtypes=PINGREQ;
		  }

	}
	exit:
	transport_close();

 

The MQTT communication part uses the above state machine. In fact, most of the codes are available online, but they are not completely correct, and the understanding of the code is different according to each person’s situation.
may be considered original for the time being (? After all, I did it myself, if it violates, please remind me to modify it.

Regarding the DNS resolution of the domain name, you can transplant it yourself on the Internet. I tried to write it myself. After writing it for a day, I didn’t write it out. It is more convenient to transplant it directly;

in conclusion

I feel that there is a lot of text when I write. I don’t know how to write articles. If you have any questions, please ask. If you see them, you will answer them. I personally think that you don’t need to spend money to buy information on this project. Yes, it is really hard to start from 0… I also spent a few days to figure it out. The most important thing is to understand that blind liver code is of no use (to myself…)

COMMENTS

Please Login to comment
  Subscribe  
Notify of
POSTED BY
TAGS