/********************************** (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 } } }