本文在前一篇的基础上进行MQTT的移植,并实现对步进电机驱动器的控制。
分两步完成:
1、移植MQTT协议栈,并进行验证;
2、对步进电机进行控制。
一,移植MQTT协议
参考实现:https://github.com/baoshi/ESP-RTOS-Paho/tree/63c2c74dfe978f215b3bb05f7e1258454908c4fb
以前一篇文章完成的代码为基础,在工程目录下的APP文件夹中新建一个文件夹命名为MQTTClient,
把paho.mqtt.embedded-c源码包中的
paho.mqtt.embedded-c\MQTTPacket\src下的:
MQTTConnect.h
MQTTConnectClient.c
MQTTDeserializePublish.c
MQTTFormat.h
MQTTPacket.c
MQTTPacket.h
MQTTPublish.h
MQTTSerializePublish.c
MQTTSubscribe.h
MQTTSubscribeClient.c
MQTTUnsubscribe.h
MQTTUnsubscribeClient.c
StackTrace.h
拷贝到MQTTClient文件夹中。
接下来,就是实现两个层面的连接处理:
1、tcp/ip建立连接,或由socket连接完成。
这部分放在
MQTTFreeRTOSImpl.c
MQTTFreeRTOSImpl.h
2、MQTT连接。
这部分放在:
MQTTClient.c
MQTTClient.h
MQTTFreeRTOSImpl.h的代码如下:
#ifndef MQTTFREERTOSIMPL_H
#define MQTTFREERTOSIMPL_H
#include "FreeRTOS.h"
#include "portmacro.h"
typedef struct Timer Timer;
struct Timer
{
portTickType end_time;
};
typedef struct Network Network;
struct Network
{
int my_socket;
int (*mqttread) (Network*, unsigned char*, int, int);
int (*mqttwrite) (Network*, unsigned char*, int, int);
};
char expired(Timer*);
void countdown_ms(Timer*, unsigned int);
void countdown(Timer*, unsigned int);
int left_ms(Timer*);
void InitTimer(Timer*);
int FreeRTOS_MQTT_read(Network*, unsigned char*, int, int);
int FreeRTOS_MQTT_write(Network*, unsigned char*, int, int);
void FreeRTOS_MQTT_disconnect(Network*);
void NewNetwork(Network* n);
int ConnectNetwork(Network* n, const char* host, int port);
int DisconnectNetwork(Network* n);
#endif /* MQTTFREERTOSIMPL_H */
MQTTFreeRTOSImpl.c的代码如下:
/*
²Î¿¼https://github.com/baoshi/ESP-RTOS-Paho/tree/63c2c74dfe978f215b3bb05f7e1258454908c4fb
*/
#include <string.h>
#include "FreeRTOS.h"
#include "portmacro.h"
#include "lwip/sockets.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
#include "MQTTFreeRTOSImpl.h"
#define _DEBUG
#include "dprintf.h"
char expired(Timer* timer)
{
portTickType now = xTaskGetTickCount();
int32_t left = timer->end_time - now;
return (left < 0);
}
void countdown_ms(Timer* timer, unsigned int timeout)
{
portTickType now = xTaskGetTickCount();
timer->end_time = now + timeout / portTICK_RATE_MS;
}
void countdown(Timer* timer, unsigned int timeout)
{
countdown_ms(timer, timeout);
}
int left_ms(Timer* timer)
{
portTickType now = xTaskGetTickCount();
int32_t left = timer->end_time - now;
return (left < 0) ? 0 : left / portTICK_RATE_MS;
}
void InitTimer(Timer* timer)
{
timer->end_time = 0;
}
#include "task.h"
#include "timers.h"
__asm void _nop(void)
{
nop
}
void delay(int i)
{
for(;i>0;i--)
_nop();
}
int FreeRTOS_MQTT_read(Network* n, unsigned char* buffer, int len, int timeout_ms)
{
TickType_t xTicksToWait = timeout_ms / portTICK_PERIOD_MS; /* convert milliseconds to ticks */
TimeOut_t xTimeOut;
int recvLen = 0;
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
do
{
int rc = 0;
lwip_setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, &xTicksToWait, sizeof(TickType_t));
rc = recv(n->my_socket, buffer + recvLen, len - recvLen, 0);
//dprintf("rc=%d\n",rc);
delay(50);//must delay enough,otherwise,it will be blocked
if (rc >= 0)
recvLen += rc;
else if (rc <0)
{
recvLen = rc;
break;
}
} while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
return recvLen;
}
int FreeRTOS_MQTT_write(Network* n, unsigned char* buffer, int len, int timeout_ms)
{
TickType_t xTicksToWait = timeout_ms / portTICK_PERIOD_MS; /* convert milliseconds to ticks */
TimeOut_t xTimeOut;
int sentLen = 0;
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
do
{
int rc = 0;
lwip_setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, &xTicksToWait, sizeof(xTicksToWait));
rc = send(n->my_socket, buffer + sentLen, len - sentLen, 0);
if (rc > 0)
sentLen += rc;
else if (rc < 0)
{
sentLen = rc;
break;
}
} while (sentLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
return sentLen;
}
void NewNetwork(Network* n)
{
n->my_socket = -1;
n->mqttread = FreeRTOS_MQTT_read;
n->mqttwrite = FreeRTOS_MQTT_write;
}
int host2addr(const char *hostname , struct in_addr *in)
{
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in *h;
int rv;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
rv = getaddrinfo(hostname, 0 , &hints , &servinfo);
if (rv != 0)
{
return rv;
}
// loop through all the results and get the first resolve
for (p = servinfo; p != 0; p = p->ai_next)
{
h = (struct sockaddr_in *)p->ai_addr;
in->s_addr = h->sin_addr.s_addr;
}
freeaddrinfo(servinfo); // all done with this structure
return 0;
}
int ConnectNetwork(Network* n, const char* host, int port)
{
struct sockaddr_in addr;
int ret;
if (host2addr(host, &(addr.sin_addr)) != 0)
{
return -1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
n->my_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if( n->my_socket < 0 )
{
// error
return -1;
}
ret = connect(n->my_socket, ( struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if( ret < 0 )
{
// error
lwip_close(n->my_socket);
return ret;
}
return ret;
}
int DisconnectNetwork(Network* n)
{
lwip_close(n->my_socket);
n->my_socket = -1;
return 0;
}
MQTTClient.h代码如下:
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and t