450 lines
13 KiB
C
450 lines
13 KiB
C
/********************************** (C) COPYRIGHT *******************************
|
|
* File Name : main.c
|
|
* Author : WCH
|
|
* Version : V1.0.0
|
|
* Date : 2022/01/18
|
|
* Description : Main program body.
|
|
*********************************************************************************
|
|
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
|
* Attention: This software (modified or not) and binary are used for
|
|
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
|
*******************************************************************************/
|
|
/*
|
|
*@Note
|
|
MQTT example, this program is used to demonstrate TCP/IP-based MQTT protocol communication,
|
|
After the single-chip microcomputer connects to Ethernet and MQTT server, a topic will be released.
|
|
Subscribe to this topic and publish messages to this topic.
|
|
|
|
For details on the selection of engineering chips,
|
|
please refer to the "CH32V20x Evaluation Board Manual" under the CH32V20xEVT\EVT\PUB folder.
|
|
*/
|
|
#include "string.h"
|
|
#include "eth_driver.h"
|
|
#include "MQTTPacket.h"
|
|
|
|
u8 MACAddr[6]; //MAC address
|
|
u8 IPAddr[4] = {192,168,1,10}; //IP address
|
|
u8 GWIPAddr[4] = {192,168,1,1}; //Gateway IP address
|
|
u8 IPMask[4] = {255,255,255,0}; //subnet mask
|
|
u8 DESIP[4] = {0}; //MQTT server IP address,!!need to be modified manually
|
|
|
|
u8 SocketId; //socket id
|
|
u8 SocketRecvBuf[RECE_BUF_LEN]; //socket receive buffer
|
|
u8 MyBuf[RECE_BUF_LEN];
|
|
u16 desport = 1883; //MQTT server port
|
|
u16 srcport = 4200; //source port
|
|
|
|
char *username = "user1"; //Device name, unique for each device, available "/" for classification
|
|
char *password = "user1"; //Server login password
|
|
char *sub_topic = "topic/1"; //subscribed session name
|
|
char *pub_topic = "topic/1"; //Published session name
|
|
int pub_qos = 0; //Publish quality of service
|
|
int sub_qos = 0; //Subscription quality of service
|
|
char *payload = "WCHNET MQTT"; //Publish content
|
|
|
|
u8 con_flag = 0; //Connect MQTT server flag
|
|
u8 pub_flag = 0; //Publish session message flag/
|
|
u8 sub_flag = 0; //Subscription session flag
|
|
u8 tout_flag = 0; //time-out flag
|
|
u16 packetid = 5; //package id
|
|
|
|
/*********************************************************************
|
|
* @fn mStopIfError
|
|
*
|
|
* @brief check if error.
|
|
*
|
|
* @param iError - error constants.
|
|
*
|
|
* @return none
|
|
*/
|
|
void mStopIfError(u8 iError)
|
|
{
|
|
if (iError == WCHNET_ERR_SUCCESS) return;
|
|
printf("Error: %02X\r\n", (u16)iError);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn TIM2_Init
|
|
*
|
|
* @brief Initializes TIM2.
|
|
*
|
|
* @return none
|
|
*/
|
|
void TIM2_Init( void )
|
|
{
|
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure={0};
|
|
|
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
|
|
|
|
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
|
|
TIM_TimeBaseStructure.TIM_Prescaler = WCHNETTIMERPERIOD * 1000 - 1;
|
|
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
|
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
|
|
TIM_ITConfig(TIM2, TIM_IT_Update ,ENABLE);
|
|
|
|
TIM_Cmd(TIM2, ENABLE);
|
|
TIM_ClearITPendingBit(TIM2, TIM_IT_Update );
|
|
NVIC_EnableIRQ(TIM2_IRQn);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn Transport_Open
|
|
*
|
|
* @brief open the TCP connection.
|
|
*
|
|
* @return socket id
|
|
*/
|
|
u8 Transport_Open(void)
|
|
{
|
|
u8 i;
|
|
SOCK_INF TmpSocketInf;
|
|
|
|
memset((void *)&TmpSocketInf,0,sizeof(SOCK_INF));
|
|
memcpy((void *)TmpSocketInf.IPAddr,DESIP,4);
|
|
TmpSocketInf.DesPort = desport;
|
|
TmpSocketInf.SourPort = srcport;
|
|
TmpSocketInf.ProtoType = PROTO_TYPE_TCP;
|
|
TmpSocketInf.RecvBufLen = RECE_BUF_LEN;
|
|
i = WCHNET_SocketCreat(&SocketId,&TmpSocketInf);
|
|
mStopIfError(i);
|
|
|
|
i = WCHNET_SocketConnect(SocketId);
|
|
mStopIfError(i);
|
|
return SocketId;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn Transport_Close
|
|
*
|
|
* @brief close the TCP connection.
|
|
*
|
|
* @return @ERR_T
|
|
*/
|
|
u8 Transport_Close(void)
|
|
{
|
|
u8 i;
|
|
i = WCHNET_SocketClose(SocketId,TCP_CLOSE_NORMAL);
|
|
mStopIfError(i);
|
|
return i;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn Transport_SendPacket
|
|
*
|
|
* @brief send data.
|
|
*
|
|
* @param buf - data buff.
|
|
* len - data length
|
|
*
|
|
* @return none
|
|
*/
|
|
void Transport_SendPacket(u8 *buf, u32 len)
|
|
{
|
|
WCHNET_SocketSend(SocketId, buf, &len);
|
|
printf("%d bytes uploaded!\r\n",len);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn MQTT_Connect
|
|
*
|
|
* @brief Establish MQTT connection.
|
|
*
|
|
* @param username - user name.
|
|
* password - password
|
|
*
|
|
* @return none
|
|
*/
|
|
void MQTT_Connect(char *username, char *password)
|
|
{
|
|
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
|
|
u32 len;
|
|
u8 buf[200];
|
|
|
|
data.clientID.cstring = "admin1";
|
|
data.keepAliveInterval = 2000;
|
|
data.cleansession = 1;
|
|
data.username.cstring = username;
|
|
data.password.cstring = password;
|
|
|
|
len = MQTTSerialize_connect(buf,sizeof(buf),&data);
|
|
Transport_SendPacket(buf,len);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn MQTT_Subscribe
|
|
*
|
|
* @brief MQTT subscribes to a topic.
|
|
*
|
|
* @param topic - Topic name to subscribe to.
|
|
* req_qos - quality of service
|
|
*
|
|
* @return none
|
|
*/
|
|
void MQTT_Subscribe( char *topic,int req_qos)
|
|
{
|
|
MQTTString topicString = MQTTString_initializer;
|
|
u32 len;
|
|
u32 msgid = 1;
|
|
u8 buf[200];
|
|
|
|
topicString.cstring = topic;
|
|
len = MQTTSerialize_subscribe(buf,sizeof(buf),0,msgid,1,&topicString,&req_qos);
|
|
Transport_SendPacket(buf,len);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn MQTT_Unsubscribe
|
|
*
|
|
* @brief MQTT unsubscribe from a topic.
|
|
*
|
|
* @param topic - Topic name to unsubscribe to.
|
|
*
|
|
* @return none
|
|
*/
|
|
void MQTT_Unsubscribe(char *topic)
|
|
{
|
|
MQTTString topicString = MQTTString_initializer;
|
|
u32 len;
|
|
u32 msgid = 1;
|
|
u8 buf[200];
|
|
|
|
topicString.cstring = topic;
|
|
len = MQTTSerialize_unsubscribe(buf,sizeof(buf),0,msgid,1,&topicString);
|
|
Transport_SendPacket(buf,len);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn MQTT_Publish
|
|
*
|
|
* @brief MQTT publishes a topic.
|
|
*
|
|
* @param topic - Published topic name.
|
|
* qos - quality of service
|
|
* payload - data buff
|
|
*
|
|
* @return none
|
|
*/
|
|
void MQTT_Publish(char *topic, int qos, char *payload)
|
|
{
|
|
MQTTString topicString = MQTTString_initializer;
|
|
u32 payloadlen;
|
|
u32 len;
|
|
u8 buf[1024];
|
|
|
|
topicString.cstring = topic;
|
|
payloadlen = strlen(payload);
|
|
len = MQTTSerialize_publish(buf,sizeof(buf),0,qos,0,packetid++,topicString,payload,payloadlen);
|
|
Transport_SendPacket(buf,len);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn MQTT_Pingreq
|
|
*
|
|
* @brief MQTT sends heartbeat packet
|
|
*
|
|
* @return none
|
|
*/
|
|
void MQTT_Pingreq(void)
|
|
{
|
|
u32 len;
|
|
u8 buf[200];
|
|
|
|
len = MQTTSerialize_pingreq(buf,sizeof(buf));
|
|
Transport_SendPacket(buf,len);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn MQTT_Disconnect
|
|
*
|
|
* @brief Disconnect the MQTT connection
|
|
*
|
|
* @return none
|
|
*/
|
|
void MQTT_Disconnect(void)
|
|
{
|
|
u32 len;
|
|
u8 buf[50];
|
|
len = MQTTSerialize_disconnect(buf,sizeof(buf));
|
|
Transport_SendPacket(buf,len);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn msgDeal
|
|
*
|
|
* @brief Dealing with subscription information.
|
|
*
|
|
* @param msg - data buff
|
|
* len - data length
|
|
*
|
|
* @return none
|
|
*/
|
|
void msgDeal(unsigned char *msg, int len)
|
|
{
|
|
unsigned char *ptr = msg;
|
|
printf("payload len = %d\r\n",len);
|
|
printf("payload: ");
|
|
for(int i = 0; i < len; i++)
|
|
{
|
|
printf("%c ",(u16)*ptr);
|
|
ptr++;
|
|
}
|
|
printf("\r\n");
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn WCHNET_HandleSockInt
|
|
*
|
|
* @brief Socket Interrupt Handle
|
|
*
|
|
* @param socketid - socket id.
|
|
* intstat - interrupt status
|
|
*
|
|
* @return none
|
|
*/
|
|
void WCHNET_HandleSockInt(u8 socketid, u8 intstat)
|
|
{
|
|
u32 len;
|
|
int qos, payloadlen;
|
|
MQTTString topicName;
|
|
unsigned short packetid;
|
|
unsigned char retained, dup;
|
|
unsigned char *payload;
|
|
|
|
if(intstat & SINT_STAT_RECV) //receive data
|
|
{
|
|
len = WCHNET_SocketRecvLen(socketid,NULL);
|
|
WCHNET_SocketRecv(socketid,MyBuf,&len);
|
|
switch(MyBuf[0]>>4)
|
|
{
|
|
case CONNACK:
|
|
printf("CONNACK\r\n");
|
|
con_flag = 1;
|
|
MQTT_Subscribe(sub_topic, sub_qos);
|
|
break;
|
|
|
|
case PUBLISH:
|
|
MQTTDeserialize_publish(&dup,&qos,&retained,&packetid,&topicName,
|
|
&payload,&payloadlen,MyBuf,len);
|
|
msgDeal(payload, payloadlen);
|
|
break;
|
|
|
|
case SUBACK:
|
|
sub_flag = 1;
|
|
printf("SUBACK\r\n");
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
memset(MyBuf, 0 ,sizeof(MyBuf));
|
|
}
|
|
if(intstat & SINT_STAT_CONNECT) //connect successfully
|
|
{
|
|
WCHNET_ModifyRecvBuf(socketid, (u32)SocketRecvBuf, RECE_BUF_LEN);
|
|
MQTT_Connect(username, password);
|
|
printf("TCP Connect Success\r\n");
|
|
}
|
|
if(intstat & SINT_STAT_DISCONNECT) //disconnect
|
|
{
|
|
con_flag = 0;
|
|
printf("TCP Disconnect\r\n");
|
|
}
|
|
if(intstat & SINT_STAT_TIM_OUT) //timeout disconnect
|
|
{
|
|
con_flag = 0;
|
|
printf("TCP Timeout\r\n");
|
|
Transport_Open();
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn WCHNET_HandleGlobalInt
|
|
*
|
|
* @brief Global Interrupt Handle
|
|
*
|
|
* @return none
|
|
*/
|
|
void WCHNET_HandleGlobalInt(void)
|
|
{
|
|
u8 intstat;
|
|
u16 i;
|
|
u8 socketint;
|
|
|
|
intstat = WCHNET_GetGlobalInt(); //get global interrupt flag
|
|
if(intstat & GINT_STAT_UNREACH) //Unreachable interrupt
|
|
{
|
|
printf("GINT_STAT_UNREACH\r\n");
|
|
}
|
|
if(intstat & GINT_STAT_IP_CONFLI) //IP conflict
|
|
{
|
|
printf("GINT_STAT_IP_CONFLI\r\n");
|
|
}
|
|
if(intstat & GINT_STAT_PHY_CHANGE) //PHY status change
|
|
{
|
|
i = WCHNET_GetPHYStatus();
|
|
if(i&PHY_Linked_Status)
|
|
printf("PHY Link Success\r\n");
|
|
}
|
|
if(intstat & GINT_STAT_SOCKET) //socket related interrupt
|
|
{
|
|
for(i = 0; i < WCHNET_MAX_SOCKET_NUM; i++)
|
|
{
|
|
socketint = WCHNET_GetSocketInt(i);
|
|
if(socketint) WCHNET_HandleSockInt(i, socketint);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn main
|
|
*
|
|
* @brief Main program
|
|
*
|
|
* @return none
|
|
*/
|
|
int main(void)
|
|
{
|
|
u8 i;
|
|
Delay_Init();
|
|
USART_Printf_Init(115200); //USART initialize
|
|
printf("MQTT Test\r\n");
|
|
if((SystemCoreClock == 60000000) || (SystemCoreClock == 120000000))
|
|
printf("SystemClk:%d\r\n", SystemCoreClock);
|
|
else
|
|
printf("Error: Please choose 60MHz and 120MHz clock when using Ethernet!\r\n");
|
|
printf("net version:%x\n",WCHNET_GetVer());
|
|
if(WCHNET_LIB_VER != WCHNET_GetVer()){
|
|
printf("version error.\n");
|
|
}
|
|
WCHNET_GetMacAddr(MACAddr); //get the chip MAC address
|
|
printf("mac addr:");
|
|
for(i = 0; i < 6; i++)
|
|
printf("%x ",MACAddr[i]);
|
|
printf("\n");
|
|
TIM2_Init();
|
|
i = ETH_LibInit(IPAddr,GWIPAddr,IPMask,MACAddr); //Ethernet library initialize
|
|
mStopIfError(i);
|
|
if(i == WCHNET_ERR_SUCCESS) printf("WCHNET_LibInit Success\r\n");
|
|
Transport_Open(); //open the TCP connection.
|
|
|
|
while(1)
|
|
{
|
|
/*Ethernet library main task function,
|
|
* which needs to be called cyclically*/
|
|
WCHNET_MainTask();
|
|
/*Query the Ethernet global interrupt,
|
|
* if there is an interrupt, call the global interrupt handler*/
|
|
if(WCHNET_QueryGlobalInt())
|
|
{
|
|
WCHNET_HandleGlobalInt();
|
|
}
|
|
if (publishValid == 1) {
|
|
publishValid = 0;
|
|
if(con_flag) MQTT_Publish(pub_topic, pub_qos, payload);
|
|
// if(con_flag) MQTT_Pingreq(); //heartbeat packet
|
|
}
|
|
}
|
|
}
|