initial commit

This commit is contained in:
2024-12-15 00:34:01 +06:00
commit 31efbc726f
1576 changed files with 657692 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
#ifndef _GOOGLENEST_H_
#define _GOOGLENEST_H_
#include "platform_opts.h"
#define GOOGLENEST_TLS_POLARSSL 0 /*!< Use PolarSSL for TLS when GOOGLENEST */
#define GOOGLENEST_TLS_MBEDTLS 1 /*!< Use mbedTLS for TLS when GOOGLENEST */
#if CONFIG_USE_POLARSSL
#define GOOGLENEST_USE_TLS GOOGLENEST_TLS_POLARSSL
#elif CONFIG_USE_MBEDTLS
#define GOOGLENEST_USE_TLS GOOGLENEST_TLS_MBEDTLS
#endif
#define BUFFER_SIZE 512
typedef struct {
int socket;
void *tls;
char *host;
} googlenest_context;
int gn_connect(googlenest_context *googlenest, char *host, int port);
void gn_close(googlenest_context *googlenest);
int gn_put(googlenest_context *googlenest, char *uri, char *content);
int gn_patch(googlenest_context *googlenest, char *uri, char *content);
int gn_post(googlenest_context *googlenest, char *uri, char *content, unsigned char *out_buffer, unsigned int out_len);
int gn_get(googlenest_context *googlenest, char *uri, unsigned char *out_buffer, unsigned int out_len);
int gn_delete(googlenest_context *googlenest, char *uri);
int gn_stream(googlenest_context *googlenest, char *uri);
void google_retrieve_data_hook_callback(void (*callback)(char *));
void *gn_tls_connect(int *sock , char *host, int port);
void gn_tls_close(void *tls_in,int *sock);
int gn_tls_write(void *tls_in, char *request, int request_len);
int gn_tls_read(void *tls_in, char *buffer, int buf_len);
#endif

View File

@@ -0,0 +1,217 @@
#include "FreeRTOS.h"
#include "task.h"
#include "platform_stdlib.h"
#include "google_nest.h"
#if (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_POLARSSL)
#include <polarssl/net.h>
#include <polarssl/ssl.h>
#include <polarssl/error.h>
#include <polarssl/memory.h>
struct gn_tls{
ssl_context ctx;
};
#elif (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_MBEDTLS)
#include "mbedtls/net.h"
#include "mbedtls/ssl.h"
#include "mbedtls/error.h"
struct gn_tls{
mbedtls_ssl_context ctx;
mbedtls_ssl_config conf;
mbedtls_net_context socket;
};
static void* _calloc_func(size_t nmemb, size_t size) {
size_t mem_size;
void *ptr = NULL;
mem_size = nmemb * size;
ptr = pvPortMalloc(mem_size);
if(ptr)
memset(ptr, 0, mem_size);
return ptr;
}
static char *gn_itoa(int value){
char *val_str;
int tmp = value, len = 1;
while((tmp /= 10) > 0)
len ++;
val_str = (char *) pvPortMalloc(len + 1);
sprintf(val_str, "%d", value);
return val_str;
}
#endif /* GOOGLENEST_USE_TLS */
static int _random_func(void *p_rng, unsigned char *output, unsigned int output_len) {
rtw_get_random_bytes(output, output_len);
return 0;
}
void *gn_tls_connect(int *sock , char *host, int port){
#if (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_POLARSSL)
int ret;
struct gn_tls *tls =NULL;
memory_set_own(pvPortMalloc, vPortFree);
tls = (struct gn_tls *) malloc(sizeof(struct gn_tls));
if(tls){
ssl_context *ssl = &tls->ctx;
memset(tls, 0, sizeof(struct gn_tls));
if((ret = net_connect(sock, host, port)) != 0) {
printf("\n[GOOGLENEST] ERROR: net_connect %d\n", ret);
goto exit;
}
if((ret = ssl_init(ssl)) != 0) {
printf("\n[GOOGLENEST] ERROR: ssl_init %d\n", ret);
goto exit;
}
ssl_set_endpoint(ssl, SSL_IS_CLIENT);
ssl_set_authmode(ssl, SSL_VERIFY_NONE);
ssl_set_rng(ssl, _random_func, NULL);
ssl_set_bio(ssl, net_recv, sock, net_send, sock);
if((ret = ssl_handshake(ssl)) != 0) {
printf("\n[GOOGLENEST] ERROR: ssl_handshake -0x%x\n", -ret);
goto exit;
}
}
else{
printf("\n[GOOGLENEST] ERROR: malloc\n");
ret = -1;
goto exit;
}
exit:
if(ret && tls) {
net_close(*sock);
ssl_free(&tls->ctx);
free(tls);
tls = NULL;
}
return (void *) tls;
#elif (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_MBEDTLS)
int ret;
struct gn_tls *tls =NULL;
mbedtls_platform_set_calloc_free(_calloc_func, vPortFree);
tls = (struct gn_tls *) malloc(sizeof(struct gn_tls));
if(tls){
mbedtls_ssl_context *ssl = &tls->ctx;
mbedtls_ssl_config *conf = &tls->conf;
mbedtls_net_context *server_fd = &tls->socket;
memset(tls, 0, sizeof(struct gn_tls));
server_fd->fd = *sock;
char *port_str = gn_itoa(port);
if((ret = mbedtls_net_connect(server_fd, host, port_str, MBEDTLS_NET_PROTO_TCP)) != 0) {
printf("\n[GOOGLENEST] ERROR: net_connect %d\n", ret);
goto exit;
}
free(port_str);
*sock = server_fd->fd;
mbedtls_ssl_init(ssl);
mbedtls_ssl_config_init(conf);
mbedtls_ssl_set_bio(ssl, server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
if((ret = mbedtls_ssl_config_defaults(conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
printf("\n[GOOGLENEST] ERROR: ssl_config %d\n", ret);
goto exit;
}
mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
mbedtls_ssl_conf_rng(conf, _random_func, NULL);
if((ret = mbedtls_ssl_setup(ssl, conf)) != 0) {
printf("\n[GOOGLENEST] ERROR: ssl_setup %d\n", ret);
goto exit;
}
if((ret = mbedtls_ssl_handshake(ssl)) != 0) {
printf("\n[GOOGLENEST] ERROR: ssl_handshake -0x%x\n", -ret);
goto exit;
}
}
else {
printf("\n[GOOGLENEST] ERROR: malloc\n");
ret = -1;
goto exit;
}
exit:
if(ret && tls){
mbedtls_net_free(&tls->socket);
mbedtls_ssl_free(&tls->ctx);
mbedtls_ssl_config_free(&tls->conf);
free(tls);
tls = NULL;
}
return (void *) tls;
#endif /* GOOGLENEST_USE_TLS */
}
void gn_tls_close(void *tls_in,int *sock){
struct gn_tls *tls = (struct gn_tls *)tls_in;
#if (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_POLARSSL)
if(tls)
ssl_close_notify(&tls->ctx);
if(*sock != -1){
net_close(*sock);
*sock = -1;
}
ssl_free(&tls->ctx);
free(tls);
tls = NULL;
#elif (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_MBEDTLS)
if(tls)
mbedtls_ssl_close_notify(&tls->ctx);
if(*sock != -1){
mbedtls_net_free(&tls->socket);
*sock = -1;
}
mbedtls_ssl_free(&tls->ctx);
mbedtls_ssl_config_free(&tls->conf);
free(tls);
tls = NULL;
#endif /* GOOGLENEST_USE_TLS */
}
int gn_tls_write(void *tls_in, char *request, int request_len){
struct gn_tls *tls = (struct gn_tls *)tls_in;
#if (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_POLARSSL)
return ssl_write(&tls->ctx, request, request_len);
#elif (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_MBEDTLS)
return mbedtls_ssl_write(&tls->ctx, request, request_len);
#endif /* GOOGLENEST_USE_TLS */
}
int gn_tls_read(void *tls_in, char *buffer, int buf_len){
struct gn_tls *tls = (struct gn_tls *)tls_in;
#if (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_POLARSSL)
return ssl_read(&tls->ctx, buffer, buf_len);
#elif (GOOGLENEST_USE_TLS == GOOGLENEST_TLS_MBEDTLS)
return mbedtls_ssl_read(&tls->ctx, buffer, buf_len);
#endif /* GOOGLENEST_USE_TLS */
}

View File

@@ -0,0 +1,873 @@
/*******************************************************************************
* Copyright (c) 2014, 2015 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTClient.h"
const char * const msg_types_str[]=
{
"Reserved",
"CONNECT",
"CONNACK",
"PUBLISH",
"PUBACK",
"PUBREC",
"PUBREL",
"PUBCOMP",
"SUBSCRIBE",
"SUBACK",
"UNSUBSCRIBE",
"UNSUBACK",
"PINGREQ",
"PINGRESP",
"DISCONNECT",
"Reserved"
};
const char * const mqtt_status_str[]=
{
"MQTT_START",
"MQTT_CONNECT",
"MQTT_SUBTOPIC",
"MQTT_RUNNING"
};
static void NewMessageData(MessageData* md, MQTTString* aTopicName, MQTTMessage* aMessage) {
md->topicName = aTopicName;
md->message = aMessage;
}
static int getNextPacketId(MQTTClient *c) {
return c->next_packetid = (c->next_packetid == MAX_PACKET_ID) ? 1 : c->next_packetid + 1;
}
static int sendPacket(MQTTClient* c, int length, Timer* timer)
{
int rc = FAILURE,
sent = 0;
while (sent < length && !TimerIsExpired(timer))
{
rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length, TimerLeftMS(timer));
if (rc < 0) // there was an error writing the data
break;
sent += rc;
}
if (sent == length)
{
TimerCountdown(&c->ping_timer, c->keepAliveInterval); // record the fact that we have successfully sent the packet
rc = SUCCESS;
}
else{
rc = FAILURE;
mqtt_printf(MQTT_DEBUG, "Send packet failed");
}
if (c->ipstack->my_socket < 0) {
c->isconnected = 0;
}
return rc;
}
void MQTTClientInit(MQTTClient* c, Network* network, unsigned int command_timeout_ms,
unsigned char* sendbuf, size_t sendbuf_size, unsigned char* readbuf, size_t readbuf_size)
{
int i;
c->ipstack = network;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
c->messageHandlers[i].topicFilter = 0;
c->command_timeout_ms = command_timeout_ms;
c->buf = sendbuf;
c->buf_size = sendbuf_size;
c->readbuf = readbuf;
c->readbuf_size = readbuf_size;
c->isconnected = 0;
c->ping_outstanding = 0;
c->defaultMessageHandler = NULL;
c->next_packetid = 1;
c->ipstack->m2m_rxevent = 0;
c->mqttstatus = MQTT_START;
TimerInit(&c->cmd_timer);
TimerInit(&c->ping_timer);
}
static int decodePacket(MQTTClient* c, int* value, int timeout)
{
unsigned char i;
int multiplier = 1;
int len = 0;
const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
*value = 0;
do
{
int rc = MQTTPACKET_READ_ERROR;
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
{
rc = MQTTPACKET_READ_ERROR; /* bad data */
goto exit;
}
rc = c->ipstack->mqttread(c->ipstack, &i, 1, timeout);
if (rc != 1)
goto exit;
*value += (i & 127) * multiplier;
multiplier *= 128;
} while ((i & 128) != 0);
exit:
return len;
}
static int readPacket(MQTTClient* c, Timer* timer)
{
int rc = FAILURE;
MQTTHeader header = {0};
int len = 0;
int rem_len = 0;
/* 1. read the header byte. This has the packet type in it */
if (c->ipstack->mqttread(c->ipstack, c->readbuf, 1, TimerLeftMS(timer)) != 1){
mqtt_printf(MQTT_MSGDUMP, "read packet header failed");
goto exit;
}
len = 1;
/* 2. read the remaining length. This is variable in itself */
decodePacket(c, &rem_len, TimerLeftMS(timer));
len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
if(len + rem_len > c->readbuf_size){
mqtt_printf(MQTT_WARNING, "rem_len = %d, read buffer will overflow", rem_len);
rc = BUFFER_OVERFLOW;
goto exit;
}
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
if (rem_len > 0 && (c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, TimerLeftMS(timer)) != rem_len)){
mqtt_printf(MQTT_MSGDUMP, "read the rest of the data failed");
goto exit;
}
header.byte = c->readbuf[0];
rc = header.bits.type;
exit:
if (c->ipstack->my_socket < 0) {
c->isconnected = 0;
}
return rc;
}
// assume topic filter and name is in correct format
// # can only be at end
// + and # can only be next to separator
static char isTopicMatched(char* topicFilter, MQTTString* topicName)
{
char* curf = topicFilter;
char* curn = topicName->lenstring.data;
char* curn_end = curn + topicName->lenstring.len;
while (*curf && curn < curn_end)
{
if (*curn == '/' && *curf != '/')
break;
if (*curf != '+' && *curf != '#' && *curf != *curn)
break;
if (*curf == '+')
{ // skip until we meet the next separator, or end of string
char* nextpos = curn + 1;
while (nextpos < curn_end && *nextpos != '/')
nextpos = ++curn + 1;
}
else if (*curf == '#')
curn = curn_end - 1; // skip until end of string
curf++;
curn++;
};
return (curn == curn_end) && (*curf == '\0');
}
int deliverMessage(MQTTClient* c, MQTTString* topicName, MQTTMessage* message)
{
int i;
int rc = FAILURE;
// we have to find the right message handler - indexed by topic
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
{
if (c->messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(topicName, (char*)c->messageHandlers[i].topicFilter) ||
isTopicMatched((char*)c->messageHandlers[i].topicFilter, topicName)))
{
if (c->messageHandlers[i].fp != NULL)
{
MessageData md;
NewMessageData(&md, topicName, message);
c->messageHandlers[i].fp(&md);
rc = SUCCESS;
}
}
}
if (rc == FAILURE && c->defaultMessageHandler != NULL)
{
MessageData md;
NewMessageData(&md, topicName, message);
c->defaultMessageHandler(&md);
rc = SUCCESS;
}
return rc;
}
int keepalive(MQTTClient* c)
{
int rc = FAILURE;
if (c->keepAliveInterval == 0)
{
rc = SUCCESS;
goto exit;
}
if (TimerIsExpired(&c->ping_timer))
{
if (!c->ping_outstanding)
{
Timer timer;
TimerInit(&timer);
TimerCountdownMS(&timer, 1000);
int len = MQTTSerialize_pingreq(c->buf, c->buf_size);
if (len > 0 && (rc = sendPacket(c, len, &timer)) == SUCCESS) // send the ping packet
c->ping_outstanding = 1;
}
}
exit:
return rc;
}
void MQTTCloseSession(MQTTClient* c)
{
c->ping_outstanding = 0;
c->isconnected = 0;
}
int cycle(MQTTClient* c, Timer* timer)
{
// read the socket, see what work is due
unsigned short packet_type = readPacket(c, timer);
int len = 0, rc = SUCCESS;
if (packet_type == (unsigned short)BUFFER_OVERFLOW || packet_type == (unsigned short)FAILURE) {
rc = FAILURE;
goto exit;
}
mqtt_printf(MQTT_DEBUG, "Read packet type: %d", packet_type);
switch (packet_type)
{
case CONNACK:
case PUBACK:
case SUBACK:
break;
case PUBLISH:
{
MQTTString topicName;
MQTTMessage msg;
int intQoS;
if (MQTTDeserialize_publish(&msg.dup, &intQoS, &msg.retained, &msg.id, &topicName,
(unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
goto exit;
msg.qos = (enum QoS)intQoS;
deliverMessage(c, &topicName, &msg);
if (msg.qos != QOS0)
{
if (msg.qos == QOS1)
len = MQTTSerialize_ack(c->buf, c->buf_size, PUBACK, 0, msg.id);
else if (msg.qos == QOS2)
len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREC, 0, msg.id);
if (len <= 0)
rc = FAILURE;
else {
#if 1
sendPacket(c, len, timer);
#else
// it's odd that ACK PUB also need success
rc = sendPacket(c, len, timer);
#endif
}
if (rc == FAILURE)
goto exit; // there was a problem
}
break;
}
case PUBREC:
{
unsigned short mypacketid;
unsigned char dup, type;
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
rc = FAILURE;
else if ((len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREL, 0, mypacketid)) <= 0)
rc = FAILURE;
else if ((rc = sendPacket(c, len, timer)) != SUCCESS) // send the PUBREL packet
rc = FAILURE; // there was a problem
if (rc == FAILURE)
goto exit; // there was a problem
break;
}
case PUBREL:
{
unsigned short mypacketid;
unsigned char dup, type;
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
rc = FAILURE;
else if ((len = MQTTSerialize_ack(c->buf, c->buf_size, PUBCOMP, 0, mypacketid)) <= 0)
rc = FAILURE;
else if ((rc = sendPacket(c, len, timer)) != SUCCESS) // send the PUBREL packet
rc = FAILURE; // there was a problem
if (rc == FAILURE)
goto exit; // there was a problem
break;
}
case PUBCOMP:
break;
case PINGRESP:
c->ping_outstanding = 0;
break;
}
if (keepalive(c) != SUCCESS) {
//check only keepalive FAILURE status so that previous FAILURE status can be considered as FAULT
rc = FAILURE;
}
exit:
if (rc == SUCCESS)
rc = packet_type;
return rc;
}
int MQTTYield(MQTTClient* c, int timeout_ms)
{
int rc = SUCCESS;
Timer timer;
TimerInit(&timer);
TimerCountdownMS(&timer, timeout_ms);
do
{
if (cycle(c, &timer) == FAILURE)
{
rc = FAILURE;
break;
}
} while (!TimerIsExpired(&timer));
return rc;
}
int waitfor(MQTTClient* c, int packet_type, Timer* timer)
{
int rc = FAILURE;
do
{
if (TimerIsExpired(timer))
break; // we timed out
}
while ((rc = cycle(c, timer)) != packet_type);
return rc;
}
int MQTTConnect(MQTTClient* c, MQTTPacket_connectData* options)
{
Timer connect_timer;
int rc = FAILURE;
MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
int len = 0;
if (c->isconnected) /* don't send connect packet again if we are already connected */
goto exit;
TimerInit(&connect_timer);
TimerCountdownMS(&connect_timer, c->command_timeout_ms);
if (options == 0)
options = &default_options; /* set default options if none were supplied */
c->keepAliveInterval = options->keepAliveInterval;
TimerCountdown(&c->ping_timer, c->keepAliveInterval);
if ((len = MQTTSerialize_connect(c->buf, c->buf_size, options)) <= 0)
goto exit;
if ((rc = sendPacket(c, len, &connect_timer)) != SUCCESS) // send the connect packet
goto exit; // there was a problem
#if defined(WAIT_FOR_ACK)
// this will be a blocking call, wait for the connack
if (waitfor(c, CONNACK, &connect_timer) == CONNACK)
{
unsigned char connack_rc = 255;
unsigned char sessionPresent = 0;
if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, c->readbuf, c->readbuf_size) == 1)
rc = connack_rc;
else
rc = FAILURE;
}
else{
mqtt_printf(MQTT_DEBUG, "Not received CONNACK");
rc = FAILURE;
}
#endif
exit:
if (rc == SUCCESS)
{
c->isconnected = 1;
c->ping_outstanding = 0;
}
return rc;
}
int MQTTSubscribe(MQTTClient* c, const char* topicFilter, enum QoS qos, messageHandler messageHandler)
{
int rc = FAILURE;
Timer timer;
int len = 0;
MQTTString topic = MQTTString_initializer;
topic.cstring = (char *)topicFilter;
if (!c->isconnected)
goto exit;
TimerInit(&timer);
TimerCountdownMS(&timer, c->command_timeout_ms);
len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int*)&qos);
if (len <= 0)
goto exit;
if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
goto exit; // there was a problem
#if defined(WAIT_FOR_ACK)
if (waitfor(c, SUBACK, &timer) == SUBACK) // wait for suback
{
int count = 0, grantedQoS = -1;
unsigned short mypacketid;
if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, c->readbuf, c->readbuf_size) == 1)
rc = grantedQoS; // 0, 1, 2 or 0x80
if (rc != 0x80)
{
int i;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
{
if (c->messageHandlers[i].topicFilter == topicFilter)
{
rc = 0;
goto exit; //already subscribed
}
}
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
{
if (c->messageHandlers[i].topicFilter == 0)
{
c->messageHandlers[i].topicFilter = topicFilter;
c->messageHandlers[i].fp = messageHandler;
rc = 0;
break;
}
}
}
}
else
rc = FAILURE;
#endif
exit:
if (rc == FAILURE)
MQTTCloseSession(c);
return rc;
}
int MQTTUnsubscribe(MQTTClient* c, const char* topicFilter)
{
int rc = FAILURE;
Timer timer;
MQTTString topic = MQTTString_initializer;
topic.cstring = (char *)topicFilter;
int len = 0;
if (!c->isconnected)
goto exit;
TimerInit(&timer);
TimerCountdownMS(&timer, c->command_timeout_ms);
if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0)
goto exit;
if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
goto exit; // there was a problem
#if defined(WAIT_FOR_ACK)
if (waitfor(c, UNSUBACK, &timer) == UNSUBACK)
{
unsigned short mypacketid; // should be the same as the packetid above
if (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1)
rc = 0;
int i;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
{
if (c->messageHandlers[i].topicFilter == topicFilter)
{
c->messageHandlers[i].topicFilter = 0;
c->messageHandlers[i].fp = NULL;
}
}
}
else
rc = FAILURE;
#endif
exit:
if (rc == FAILURE)
MQTTCloseSession(c);
return rc;
}
int MQTTPublish(MQTTClient* c, const char* topicName, MQTTMessage* message)
{
int rc = FAILURE;
Timer timer;
MQTTString topic = MQTTString_initializer;
topic.cstring = (char *)topicName;
int len = 0;
if (!c->isconnected)
goto exit;
TimerInit(&timer);
TimerCountdownMS(&timer, c->command_timeout_ms);
if (message->qos == QOS1 || message->qos == QOS2)
message->id = getNextPacketId(c);
len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id,
topic, (unsigned char*)message->payload, message->payloadlen);
if (len <= 0)
goto exit;
if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
goto exit; // there was a problem
#if defined(WAIT_FOR_ACK)
if (message->qos == QOS1)
{
if (waitfor(c, PUBACK, &timer) == PUBACK)
{
unsigned short mypacketid;
unsigned char dup, type;
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
rc = FAILURE;
}
else{
rc = FAILURE;
mqtt_printf(MQTT_DEBUG, "Not received PUBACK");
}
}
else if (message->qos == QOS2)
{
if (waitfor(c, PUBCOMP, &timer) == PUBCOMP)
{
unsigned short mypacketid;
unsigned char dup, type;
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
rc = FAILURE;
}
else{
rc = FAILURE;
mqtt_printf(MQTT_DEBUG, "Not received PUBCOMP");
}
}
#endif
exit:
if (rc == FAILURE)
MQTTCloseSession(c);
return rc;
}
int MQTTDisconnect(MQTTClient* c)
{
int rc = FAILURE;
Timer timer; // we might wait for incomplete incoming publishes to complete
int len = 0;
TimerInit(&timer);
TimerCountdownMS(&timer, c->command_timeout_ms);
len = MQTTSerialize_disconnect(c->buf, c->buf_size);
if (len > 0)
rc = sendPacket(c, len, &timer); // send the disconnect packet
MQTTCloseSession(c);
return rc;
}
#if defined(MQTT_TASK)
void MQTTSetStatus(MQTTClient* c, int mqttstatus)
{
c->mqttstatus = mqttstatus;
mqtt_printf(MQTT_INFO, "Set mqtt status to %s", mqtt_status_str[mqttstatus]);
}
int MQTTDataHandle(MQTTClient* c, fd_set *readfd, MQTTPacket_connectData *connectData, messageHandler messageHandler, char* address, int port, char* topic)
{
short packet_type = 0;
int rc = 0;
int mqttstatus = c->mqttstatus;
int mqtt_rxevent = 0;
int mqtt_fd = c->ipstack->my_socket;
mqtt_rxevent = (mqtt_fd >= 0) ? FD_ISSET( mqtt_fd, readfd) : 0;
if(mqttstatus == MQTT_START) {
mqtt_printf(MQTT_INFO, "MQTT start");
if(c->isconnected){
c->isconnected = 0;
}
mqtt_printf(MQTT_INFO, "Connect Network \"%s\"", address);
if((rc = NetworkConnect(c->ipstack, address, port)) != 0){
mqtt_printf(MQTT_INFO, "Return code from network connect is %d\n", rc);
goto exit;
}
mqtt_printf(MQTT_INFO, "\"%s\" Connected", address);
mqtt_printf(MQTT_INFO, "Start MQTT connection");
TimerInit(&c->cmd_timer);
TimerCountdownMS(&c->cmd_timer, c->command_timeout_ms);
if ((rc = MQTTConnect(c, connectData)) != 0){
mqtt_printf(MQTT_INFO, "Return code from MQTT connect is %d\n", rc);
goto exit;
}
MQTTSetStatus(c, MQTT_CONNECT);
goto exit;
}
if(mqtt_rxevent){
c->ipstack->m2m_rxevent = 0;
Timer timer;
TimerInit(&timer);
TimerCountdownMS(&timer, 1000);
packet_type = readPacket(c, &timer);
if(packet_type > 0 && packet_type < 15)
mqtt_printf(MQTT_DEBUG, "Read packet type is %s", msg_types_str[packet_type]);
else{
mqtt_printf(MQTT_DEBUG, "Read packet type is %d", packet_type);
MQTTSetStatus(c, MQTT_START);
c->ipstack->disconnect(c->ipstack);
rc = FAILURE;
goto exit;
}
}
switch(mqttstatus){
case MQTT_CONNECT:
if (packet_type == CONNACK)
{
unsigned char connack_rc = 255;
unsigned char sessionPresent = 0;
if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, c->readbuf, c->readbuf_size) == 1){
rc = connack_rc;
mqtt_printf(MQTT_INFO, "MQTT Connected");
TimerInit(&c->cmd_timer);
TimerCountdownMS(&c->cmd_timer, c->command_timeout_ms);
if ((rc = MQTTSubscribe(c, topic, QOS2, messageHandler)) != 0){
mqtt_printf(MQTT_INFO, "Return code from MQTT subscribe is %d\n", rc);
}else{
mqtt_printf(MQTT_INFO, "Subscribe to Topic: %s", topic);
MQTTSetStatus(c, MQTT_SUBTOPIC);
}
}else{
mqtt_printf(MQTT_DEBUG, "Deserialize CONNACK failed");
rc = FAILURE;
}
}else if(TimerIsExpired(&c->cmd_timer)){
mqtt_printf(MQTT_DEBUG, "Not received CONNACK");
rc = FAILURE;
}
if(rc == FAILURE){
MQTTSetStatus(c, MQTT_START);
}
break;
case MQTT_SUBTOPIC:
if(packet_type == SUBACK){
int count = 0, grantedQoS = -1;
unsigned short mypacketid;
int isSubscribed = 0;
if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, c->readbuf, c->readbuf_size) == 1){
rc = grantedQoS; // 0, 1, 2 or 0x80
mqtt_printf(MQTT_DEBUG, "grantedQoS: %d", grantedQoS);
}
if (rc != 0x80)
{
int i;
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
{
if (c->messageHandlers[i].topicFilter == topic)
{
isSubscribed = 1;
break;
}
}
if(!isSubscribed)
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
{
if (c->messageHandlers[i].topicFilter == 0)
{
c->messageHandlers[i].topicFilter = topic;
c->messageHandlers[i].fp = messageHandler;
break;
}
}
rc = 0;
MQTTSetStatus(c, MQTT_RUNNING);
}
}else if(TimerIsExpired(&c->cmd_timer)){
mqtt_printf(MQTT_DEBUG, "Not received SUBACK");
rc = FAILURE;
}
if(rc == FAILURE){
MQTTSetStatus(c, MQTT_START);
}
break;
case MQTT_RUNNING:
if(packet_type>0){
int len = 0;
Timer timer;
TimerInit(&timer);
TimerCountdownMS(&timer, 10000);
switch(packet_type){
case CONNACK:
break;
case PUBACK:
{
unsigned short mypacketid;
unsigned char dup, type;
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
rc = FAILURE;
break;
}
case SUBACK:
break;
case UNSUBACK:
break;
case PUBLISH:
{
MQTTString topicName;
MQTTMessage msg;
int intQoS;
if (MQTTDeserialize_publish(&msg.dup, &intQoS, &msg.retained, &msg.id, &topicName,
(unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
{
rc = FAILURE;
mqtt_printf(MQTT_DEBUG, "Deserialize PUBLISH failed");
goto exit;
}
msg.qos = (enum QoS)intQoS;
deliverMessage(c, &topicName, &msg);
if (msg.qos != QOS0)
{
if (msg.qos == QOS1){
len = MQTTSerialize_ack(c->buf, c->buf_size, PUBACK, 0, msg.id);
mqtt_printf(MQTT_DEBUG, "send PUBACK");
}else if (msg.qos == QOS2){
len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREC, 0, msg.id);
mqtt_printf(MQTT_DEBUG, "send PUBREC");
}else{
mqtt_printf(MQTT_DEBUG, "invalid QoS: %d", msg.qos);
}
if (len <= 0){
rc = FAILURE;
mqtt_printf(MQTT_DEBUG, "Serialize_ack failed");
goto exit;
}else{
if((rc = sendPacket(c, len, &timer)) == FAILURE){
MQTTSetStatus(c, MQTT_START);
goto exit; // there was a problem
}
}
}
break;
}
case PUBREC:
{
unsigned short mypacketid;
unsigned char dup, type;
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1){
mqtt_printf(MQTT_DEBUG, "Deserialize PUBREC failed");
rc = FAILURE;
}else if ((len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREL, 0, mypacketid)) <= 0){
mqtt_printf(MQTT_DEBUG, "Serialize PUBREL failed");
rc = FAILURE;
}else if ((rc = sendPacket(c, len, &timer)) != SUCCESS){ // send the PUBREL packet
rc = FAILURE; // there was a problem
MQTTSetStatus(c, MQTT_START);
}
break;
}
case PUBREL:
{
unsigned short mypacketid;
unsigned char dup, type;
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1){
mqtt_printf(MQTT_DEBUG, "Deserialize PUBREL failed");
rc = FAILURE;
}else if ((len = MQTTSerialize_ack(c->buf, c->buf_size, PUBCOMP, 0, mypacketid)) <= 0){
mqtt_printf(MQTT_DEBUG, "Serialize PUBCOMP failed");
rc = FAILURE;
}else if ((rc = sendPacket(c, len, &timer)) != SUCCESS){ // send the PUBCOMP packet
rc = FAILURE; // there was a problem
MQTTSetStatus(c, MQTT_START);
}
break;
}
case PUBCOMP:
break;
case PINGRESP:
c->ping_outstanding = 0;
break;
}
}
if (keepalive(c) != SUCCESS) {
//check only keepalive FAILURE status so that previous FAILURE status can be considered as FAULT
rc = FAILURE;
}
break;
default:
break;
}
exit:
return rc;
}
#endif

View File

@@ -0,0 +1,225 @@
/**
******************************************************************************
* @file MQTTClient.h
* @author
* @version
* @brief This file provides user interface for MQTT client.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#if !defined(__MQTT_CLIENT_C_)
#define __MQTT_CLIENT_C_
/** @addtogroup mqtt MQTT
* @ingroup network
* @brief MQTT client functions
* @{
*/
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(WIN32_DLL) || defined(WIN64_DLL)
#define DLLImport __declspec(dllimport)
#define DLLExport __declspec(dllexport)
#elif defined(LINUX_SO)
#define DLLImport extern
#define DLLExport __attribute__ ((visibility ("default")))
#else
#define DLLImport
#define DLLExport
#endif
#include "../MQTTPacket/MQTTPacket.h"
#include "stdio.h"
#include "MQTTFreertos.h"
#define MQTT_TASK
#if !defined(MQTT_TASK)
#define WAIT_FOR_ACK
#endif
#define MQTT_SENDBUF_LEN 1024
#define MQTT_READBUF_LEN 1024
enum mqtt_status{
MQTT_START = 0,
MQTT_CONNECT = 1,
MQTT_SUBTOPIC = 2,
MQTT_RUNNING = 3
};
#if defined(MQTTCLIENT_PLATFORM_HEADER)
/* The following sequence of macros converts the MQTTCLIENT_PLATFORM_HEADER value
* into a string constant suitable for use with include.
*/
#define xstr(s) str(s)
#define str(s) #s
#include xstr(MQTTCLIENT_PLATFORM_HEADER)
#endif
#define MAX_PACKET_ID 65535 /* according to the MQTT specification - do not change! */
#if !defined(MAX_MESSAGE_HANDLERS)
#define MAX_MESSAGE_HANDLERS 5 /* redefinable - how many subscriptions do you want? */
#endif
enum QoS { QOS0, QOS1, QOS2 };
/* all failure return codes must be negative */
enum returnCode { BUFFER_OVERFLOW = -2, FAILURE = -1 };//, SUCCESS = 0
/* The Platform specific header must define the Network and Timer structures and functions
* which operate on them.
*
typedef struct Network
{
int (*mqttread)(Network*, unsigned char* read_buffer, int, int);
int (*mqttwrite)(Network*, unsigned char* send_buffer, int, int);
} Network;*/
/* The Timer structure must be defined in the platform specific header,
* and have the following functions to operate on it. */
extern void TimerInit(Timer*);
extern char TimerIsExpired(Timer*);
extern void TimerCountdownMS(Timer*, unsigned int);
extern void TimerCountdown(Timer*, unsigned int);
extern int TimerLeftMS(Timer*);
typedef struct MQTTMessage
{
enum QoS qos;
unsigned char retained;
unsigned char dup;
unsigned short id;
void *payload;
size_t payloadlen;
} MQTTMessage;
typedef struct MessageData
{
MQTTMessage* message;
MQTTString* topicName;
} MessageData;
typedef void (*messageHandler)(MessageData*);
typedef struct MQTTClient
{
unsigned int next_packetid,
command_timeout_ms;
size_t buf_size,
readbuf_size;
unsigned char *buf,
*readbuf;
unsigned int keepAliveInterval;
char ping_outstanding;
int isconnected;
struct MessageHandlers
{
const char* topicFilter;
void (*fp) (MessageData*);
} messageHandlers[MAX_MESSAGE_HANDLERS]; /* Message handlers are indexed by subscription topic */
void (*defaultMessageHandler) (MessageData*);
Network* ipstack;
Timer ping_timer;
Timer cmd_timer;
int mqttstatus;
} MQTTClient;
#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}
/**
* @brief Create an MQTT client object
* @param client : The context of MQTT client
* @param network : The Network context
* @param command_timeout_ms : The command timeout of MQTT
* @param sendbuf : The array of MQTT send buffer
* @param sendbuf_size : The size of send buffer
* @param readbuf : The array of MQTT receive buffer
* @param readbuf_size : The size of receive buffer
* @return none
*/
DLLExport void MQTTClientInit(MQTTClient* client, Network* network, unsigned int command_timeout_ms,
unsigned char* sendbuf, size_t sendbuf_size, unsigned char* readbuf, size_t readbuf_size);
/**
* @brief Send an MQTT connect packet down the network and wait for a Connack
* The nework object must be connected to the network endpoint before calling this function
* @param client c
* @param options : The connect options of MQTT
* @return 0 : success
* -1 : failed
*/
DLLExport int MQTTConnect(MQTTClient* client, MQTTPacket_connectData* options);
/**
* @brief Send an MQTT publish packet and wait for all acks to complete for all QoSs
* @param client : The context of MQTT client
* @param topic : The MQTT topic to publish
* @param message : The message to send
* @return 0 : success
* -1 : failed
*/
DLLExport int MQTTPublish(MQTTClient* client, const char*, MQTTMessage*);
/**
* @brief Send an MQTT subscribe packet and wait for suback before returning.
* @param client : The context of MQTT client
* @param topicFilter : The topic filter to subscribe
* @param QoS : The MQTT QOS value
* @param messageHandler : The MQTT message handler
* @return 0 : success
* -1 : failed
*/
DLLExport int MQTTSubscribe(MQTTClient* client, const char* topicFilter, enum QoS, messageHandler);
/**
* @brief Send an MQTT unsubscribe packet and wait for unsuback before returning.
* @param client : The context of MQTT client
* @param topicFilter : The topic filter to unsubscribe
* @return 0 : success
* -1 : failed
*/
DLLExport int MQTTUnsubscribe(MQTTClient* client, const char* topicFilter);
/**
* @brief Send an MQTT disconnect packet and close the connection
* @param client : The context of MQTT client
* @return 0 : success
* -1 : failed
*/
DLLExport int MQTTDisconnect(MQTTClient* client);
/**
* @brief MQTT receive packet background function
* @param client : The context of MQTT client
* @param time : The timeout of receive MQTT packets, in milliseconds
* @return 0 : success
* -1 : failed
*/
DLLExport int MQTTYield(MQTTClient* client, int time);
#if defined(MQTT_TASK)
void MQTTSetStatus(MQTTClient* c, int mqttstatus);
int MQTTDataHandle(MQTTClient* c, fd_set *readfd, MQTTPacket_connectData *connectData, messageHandler messageHandler, char* address, int port, char* topic);
#endif
#if defined(__cplusplus)
}
#endif
/*\@}*/
#endif

View File

@@ -0,0 +1,906 @@
/*******************************************************************************
* Copyright (c) 2014, 2015 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Allan Stockdill-Mander - initial API and implementation and/or initial documentation
* Ian Craggs - convert to FreeRTOS
*******************************************************************************/
#include "MQTTFreertos.h"
#include "netdb.h"
#ifdef LWIP_IPV6
#undef LWIP_IPV6
#endif
#ifdef inet_ntop
#undef inet_ntop
#endif
#ifdef inet_pton
#undef inet_pton
#endif
#define LWIP_IPV6 0
#if LWIP_IPV6
#define inet_ntop(af,src,dst,size) \
(((af) == AF_INET6) ? ip6addr_ntoa_r((src),(dst),(size)) \
: (((af) == AF_INET) ? ipaddr_ntoa_r((src),(dst),(size)) : NULL))
#define inet_pton(af,src,dst) \
(((af) == AF_INET6) ? inet6_aton((src),(dst)) \
: (((af) == AF_INET) ? inet_aton((src),(dst)) : 0))
#else /* LWIP_IPV6 */
#define inet_ntop(af,src,dst,size) \
(((af) == AF_INET) ? ipaddr_ntoa_r((src),(dst),(size)) : NULL)
#define inet_pton(af,src,dst) \
(((af) == AF_INET) ? inet_aton((src),(dst)) : 0)
#endif /* LWIP_IPV6 */
int ThreadStart(Thread* thread, void (*fn)(void*), void* arg)
{
int rc = 0;
uint16_t usTaskStackSize = (configMINIMAL_STACK_SIZE * 5);
UBaseType_t uxTaskPriority = uxTaskPriorityGet(NULL); /* set the priority as the same as the calling task*/
rc = xTaskCreate(fn, /* The function that implements the task. */
"MQTTTask", /* Just a text name for the task to aid debugging. */
usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */
arg, /* The task parameter, not used in this case. */
uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
&thread->task); /* The task handle is not used. */
return rc;
}
void MutexInit(Mutex* mutex)
{
mutex->sem = xSemaphoreCreateMutex();
}
int MutexLock(Mutex* mutex)
{
return xSemaphoreTake(mutex->sem, portMAX_DELAY);
}
int MutexUnlock(Mutex* mutex)
{
return xSemaphoreGive(mutex->sem);
}
void TimerCountdownMS(Timer* timer, unsigned int timeout_ms)
{
timer->xTicksToWait = timeout_ms / portTICK_PERIOD_MS; /* convert milliseconds to ticks */
vTaskSetTimeOutState(&timer->xTimeOut); /* Record the time at which this function was entered. */
}
void TimerCountdown(Timer* timer, unsigned int timeout)
{
TimerCountdownMS(timer, timeout * 1000);
}
int TimerLeftMS(Timer* timer)
{
xTaskCheckForTimeOut(&timer->xTimeOut, &timer->xTicksToWait); /* updates xTicksToWait to the number left */
return (timer->xTicksToWait * portTICK_PERIOD_MS);
}
char TimerIsExpired(Timer* timer)
{
return xTaskCheckForTimeOut(&timer->xTimeOut, &timer->xTicksToWait) == pdTRUE;
}
void TimerInit(Timer* timer)
{
timer->xTicksToWait = 0;
memset(&timer->xTimeOut, '\0', sizeof(timer->xTimeOut));
}
#if CONFIG_USE_POLARSSL
int FreeRTOS_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;
int so_error = 0;
socklen_t errlen = sizeof(so_error);
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
do
{
int rc = 0;
#if defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD) && (LWIP_SO_SNDRCVTIMEO_NONSTANDARD == 0)
// timeout format is changed in lwip 1.5.0
struct timeval timeout;
timeout.tv_sec = xTicksToWait / 1000;
timeout.tv_usec = ( xTicksToWait % 1000 ) * 1000;
setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
#else
setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, &xTicksToWait, sizeof(xTicksToWait));
#endif
#if (MQTT_OVER_SSL)
if (n->use_ssl)
rc = ssl_read(n->ssl, buffer + recvLen, len - recvLen);
else
#endif
rc = recv(n->my_socket, buffer + recvLen, len - recvLen, 0);
if (rc > 0)
recvLen += rc;
else if (rc < 0)
{
getsockopt(n->my_socket, SOL_SOCKET, SO_ERROR, &so_error, &errlen);
if (so_error && (so_error != EAGAIN)) {
n->disconnect(n);
}
recvLen = rc;
break;
}
} while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
return recvLen;
}
int FreeRTOS_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;
int so_error = 0;
socklen_t errlen = sizeof(so_error);
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
do
{
int rc = 0;
#if defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD) && (LWIP_SO_SNDRCVTIMEO_NONSTANDARD == 0)
// timeout format is changed in lwip 1.5.0
struct timeval timeout;
timeout.tv_sec = xTicksToWait / 1000;
timeout.tv_usec = ( xTicksToWait % 1000 ) * 1000;
setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval));
#else
setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, &xTicksToWait, sizeof(xTicksToWait));
#endif
#if (MQTT_OVER_SSL)
if (n->use_ssl)
rc = ssl_write(n->ssl, buffer + sentLen, len - sentLen);
else
#endif
rc = send(n->my_socket, buffer + sentLen, len - sentLen, 0);
if (rc > 0)
sentLen += rc;
else if (rc < 0)
{
getsockopt(n->my_socket, SOL_SOCKET, SO_ERROR, &so_error, &errlen);
if (so_error && (so_error != EAGAIN)) {
n->disconnect(n);
}
sentLen = rc;
break;
}
} while (sentLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
return sentLen;
}
void FreeRTOS_disconnect(Network* n)
{
if (n->my_socket >= 0) {
shutdown(n->my_socket, SHUT_RDWR);
close(n->my_socket);
n->my_socket = -1;
#if (MQTT_OVER_SSL)
if (n->use_ssl) {
ssl_free(n->ssl);
free(n->ssl);
n->ssl = NULL;
}
#endif
}
}
void NetworkInit(Network* n)
{
n->my_socket = -1;
n->mqttread = FreeRTOS_read;
n->mqttwrite = FreeRTOS_write;
n->disconnect = FreeRTOS_disconnect;
#if (MQTT_OVER_SSL)
n->use_ssl = 0;
n->ssl = NULL;
n->rootCA = NULL;
n->clientCA = NULL;
n->private_key = NULL;
#endif
}
#if (MQTT_OVER_SSL)
static int mqtt_tls_verify( void *data, x509_crt *crt, int depth, int *flags )
{
char buf[1024];
mqtt_printf(MQTT_DEBUG, "\nVerify requested for (Depth %d):\n", depth );
x509_crt_info( buf, sizeof( buf ) - 1, "", crt );
mqtt_printf(MQTT_DEBUG, "%s", buf );
if( ( (*flags) & BADCERT_EXPIRED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! server certificate has expired\n" );
if( ( (*flags) & BADCERT_REVOKED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! server certificate has been revoked\n" );
if( ( (*flags) & BADCERT_CN_MISMATCH ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! CN mismatch\n" );
if( ( (*flags) & BADCERT_NOT_TRUSTED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! self-signed or not signed by a trusted CA\n" );
if( ( (*flags) & BADCRL_NOT_TRUSTED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! CRL not trusted\n" );
if( ( (*flags) & BADCRL_EXPIRED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! CRL expired\n" );
if( ( (*flags) & BADCERT_OTHER ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! other (unknown) flag\n" );
if ( ( *flags ) == 0 )
mqtt_printf(MQTT_DEBUG, " This certificate has no flags\n" );
return( 0 );
}
static int my_random(void *p_rng, unsigned char *output, size_t output_len)
{
rtw_get_random_bytes(output, output_len);
return 0;
}
#endif // #if (MQTT_OVER_SSL)
int NetworkConnect(Network* n, char* addr, int port)
{
struct sockaddr_in sAddr;
int retVal = -1;
struct hostent *hptr;
char **pptr;
char str[32];
int keepalive_enable = 1;
int keep_idle = 30;
if(n->my_socket >= 0){
n->disconnect(n);
}
if ((hptr = gethostbyname(addr)) == 0)
{
mqtt_printf(MQTT_DEBUG, "gethostbyname failed!");
goto exit;
}
pptr = hptr->h_addr_list;
for(; *pptr!=NULL; pptr++)
{
inet_ntop(hptr->h_addrtype, (const ip_addr_t *)*pptr, str, sizeof(str));
}
inet_ntop(hptr->h_addrtype, (const ip_addr_t *)hptr->h_addr, str, sizeof(str));
sAddr.sin_family = AF_INET;
sAddr.sin_port = htons(port);
sAddr.sin_addr.s_addr = inet_addr(str);
mqtt_printf(MQTT_DEBUG, "addr = %s", str);
if ((n->my_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
goto exit;
}
setsockopt( n->my_socket, SOL_SOCKET, SO_KEEPALIVE,
(const char *) &keepalive_enable, sizeof( keepalive_enable ) );
setsockopt( n->my_socket, IPPROTO_TCP, TCP_KEEPIDLE,
(const char *) &keep_idle, sizeof( keep_idle ) );
if ((retVal = connect(n->my_socket, (struct sockaddr*)&sAddr, sizeof(sAddr))) < 0)
{
close(n->my_socket);
n->my_socket = -1;
mqtt_printf(MQTT_DEBUG, "Connect failed!!");
goto exit;
}
#if (MQTT_OVER_SSL)
x509_crt *root_crt;
x509_crt *client_crt;
pk_context *client_rsa;
root_crt = NULL;
client_crt = NULL;
client_rsa = NULL;
if ( n->use_ssl != 0 ) {
memory_set_own(pvPortMalloc, vPortFree);
n->ssl = (ssl_context *) malloc( sizeof(ssl_context) );
if ( n->ssl == NULL ) {
mqtt_printf(MQTT_DEBUG, "malloc ssl failed!");
goto err;
}
memset(n->ssl, 0, sizeof(ssl_context));
if ( ssl_init(n->ssl) != 0 ) {
mqtt_printf(MQTT_DEBUG, "init ssl failed!");
goto err;
}
ssl_set_endpoint(n->ssl, SSL_IS_CLIENT);
if (n->rootCA != NULL) {
root_crt = (x509_crt *) polarssl_malloc( sizeof(x509_crt) );
if ( root_crt == NULL ) {
mqtt_printf(MQTT_DEBUG, "malloc root_crt failed!");
goto err;
}
memset(root_crt, 0, sizeof(x509_crt));
ssl_set_authmode( n->ssl, SSL_VERIFY_REQUIRED );
if (x509_crt_parse( root_crt, n->rootCA, strlen(n->rootCA) ) != 0) {
mqtt_printf(MQTT_DEBUG, "parse root_crt failed!");
goto err;
}
ssl_set_ca_chain( n->ssl, root_crt, NULL, NULL );
ssl_set_verify( n->ssl, mqtt_tls_verify, NULL );
mqtt_printf(MQTT_DEBUG, "root_crt parse done");
} else {
ssl_set_authmode(n->ssl, SSL_VERIFY_NONE);
}
if (n->clientCA != NULL && n->private_key != NULL) {
client_crt = (x509_crt *) polarssl_malloc( sizeof(x509_crt) );
if ( client_crt == NULL ) {
mqtt_printf(MQTT_DEBUG, "malloc client_crt failed!");
goto err;
}
memset(client_crt, 0, sizeof(x509_crt));
x509_crt_init(client_crt);
client_rsa = (pk_context *) polarssl_malloc( sizeof(pk_context) );
if ( client_rsa == NULL ) {
mqtt_printf(MQTT_DEBUG, "malloc client_rsa failed!");
goto err;
}
memset(client_rsa, 0, sizeof(pk_context));
pk_init(client_rsa);
if ( x509_crt_parse(client_crt, n->clientCA, strlen(n->clientCA)) != 0 ) {
mqtt_printf(MQTT_DEBUG, "parse client_crt failed!");
goto err;
}
if ( pk_parse_key(client_rsa, n->private_key, strlen(n->private_key), NULL, 0) != 0 ) {
mqtt_printf(MQTT_DEBUG, "parse client_rsa failed!");
goto err;
}
ssl_set_own_cert(n->ssl, client_crt, client_rsa);
mqtt_printf(MQTT_DEBUG, "client_crt parse done");
}
ssl_set_rng(n->ssl, my_random, NULL);
ssl_set_bio(n->ssl, net_recv, &n->my_socket, net_send, &n->my_socket);
retVal = ssl_handshake(n->ssl);
if (retVal < 0) {
mqtt_printf(MQTT_DEBUG, "ssl handshake failed err:-0x%04X", -retVal);
goto err;
} else {
mqtt_printf(MQTT_DEBUG, "ssl handshake success");
}
}
if (client_rsa) {
pk_free(client_rsa);
polarssl_free(client_rsa);
}
if (client_crt) {
x509_crt_free(client_crt);
polarssl_free(client_crt);
}
if (root_crt) {
x509_crt_free(root_crt);
polarssl_free(root_crt);
}
goto exit;
err:
if (client_rsa) {
pk_free(client_rsa);
polarssl_free(client_rsa);
}
if (client_crt) {
x509_crt_free(client_crt);
polarssl_free(client_crt);
}
if (root_crt) {
x509_crt_free(root_crt);
polarssl_free(root_crt);
}
net_close(n->my_socket);
ssl_free(n->ssl);
free(n->ssl);
retVal = -1;
#endif // #if (MQTT_OVER_SSL)
exit:
return retVal;
}
#elif CONFIG_USE_MBEDTLS /* CONFIG_USE_POLARSSL */
int FreeRTOS_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;
int so_error = 0;
socklen_t errlen = sizeof(so_error);
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
do
{
int rc = 0;
#if defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD) && (LWIP_SO_SNDRCVTIMEO_NONSTANDARD == 0)
// timeout format is changed in lwip 1.5.0
struct timeval timeout;
timeout.tv_sec = xTicksToWait / 1000;
timeout.tv_usec = ( xTicksToWait % 1000 ) * 1000;
setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
#else
setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, &xTicksToWait, sizeof(xTicksToWait));
#endif
#if (MQTT_OVER_SSL)
if (n->use_ssl)
rc = mbedtls_ssl_read(n->ssl, buffer + recvLen, len - recvLen);
else
#endif
rc = recv(n->my_socket, buffer + recvLen, len - recvLen, 0);
if (rc > 0)
recvLen += rc;
else if (rc < 0)
{
getsockopt(n->my_socket, SOL_SOCKET, SO_ERROR, &so_error, &errlen);
if (so_error && (so_error != EAGAIN)) {
n->disconnect(n);
}
recvLen = rc;
break;
}
} while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
return recvLen;
}
int FreeRTOS_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;
int so_error = 0;
socklen_t errlen = sizeof(so_error);
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
do
{
int rc = 0;
#if defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD) && (LWIP_SO_SNDRCVTIMEO_NONSTANDARD == 0)
// timeout format is changed in lwip 1.5.0
struct timeval timeout;
timeout.tv_sec = xTicksToWait / 1000;
timeout.tv_usec = ( xTicksToWait % 1000 ) * 1000;
setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval));
#else
setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, &xTicksToWait, sizeof(xTicksToWait));
#endif
#if (MQTT_OVER_SSL)
if (n->use_ssl)
rc = mbedtls_ssl_write(n->ssl, buffer + sentLen, len - sentLen);
else
#endif
rc = send(n->my_socket, buffer + sentLen, len - sentLen, 0);
if (rc > 0)
sentLen += rc;
else if (rc < 0)
{
getsockopt(n->my_socket, SOL_SOCKET, SO_ERROR, &so_error, &errlen);
if (so_error && (so_error != EAGAIN)) {
n->disconnect(n);
}
sentLen = rc;
break;
}
} while (sentLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
return sentLen;
}
void FreeRTOS_disconnect(Network* n)
{
if (n->my_socket >= 0){
shutdown(n->my_socket, SHUT_RDWR);
close(n->my_socket);
n->my_socket = -1;
#if (MQTT_OVER_SSL)
if (n->use_ssl) {
mbedtls_ssl_free(n->ssl);
mbedtls_ssl_config_free(n->conf);
free(n->ssl);
free(n->conf);
n->ssl = NULL;
n->conf = NULL;
}
#endif
}
}
void NetworkInit(Network* n)
{
n->my_socket = -1;
n->mqttread = FreeRTOS_read;
n->mqttwrite = FreeRTOS_write;
n->disconnect = FreeRTOS_disconnect;
#if (MQTT_OVER_SSL)
n->use_ssl = 0;
n->ssl = NULL;
n->conf = NULL;
n->rootCA = NULL;
n->clientCA = NULL;
n->private_key = NULL;
#endif
}
#if (MQTT_OVER_SSL)
static int mqtt_tls_verify( void *data, mbedtls_x509_crt *crt, int depth, int *flags )
{
char buf[1024];
mqtt_printf(MQTT_DEBUG, "\nVerify requested for (Depth %d):\n", depth );
mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt );
mqtt_printf(MQTT_DEBUG, "%s", buf );
if( ( (*flags) & MBEDTLS_X509_BADCERT_EXPIRED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! server certificate has expired\n" );
if( ( (*flags) & MBEDTLS_X509_BADCERT_REVOKED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! server certificate has been revoked\n" );
if( ( (*flags) & MBEDTLS_X509_BADCERT_CN_MISMATCH ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! CN mismatch\n" );
if( ( (*flags) & MBEDTLS_X509_BADCERT_NOT_TRUSTED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! self-signed or not signed by a trusted CA\n" );
if( ( (*flags) & MBEDTLS_X509_BADCRL_NOT_TRUSTED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! CRL not trusted\n" );
if( ( (*flags) & MBEDTLS_X509_BADCRL_EXPIRED ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! CRL expired\n" );
if( ( (*flags) & MBEDTLS_X509_BADCERT_OTHER ) != 0 )
mqtt_printf(MQTT_DEBUG, " ! other (unknown) flag\n" );
if ( ( *flags ) == 0 )
mqtt_printf(MQTT_DEBUG, " This certificate has no flags\n" );
return( 0 );
}
static void* my_calloc(size_t nelements, size_t elementSize)
{
size_t size;
void *ptr = NULL;
size = nelements * elementSize;
ptr = pvPortMalloc(size);
if(ptr)
memset(ptr, 0, size);
return ptr;
}
static int my_random(void *p_rng, unsigned char *output, size_t output_len)
{
rtw_get_random_bytes(output, output_len);
return 0;
}
#endif // #if (MQTT_OVER_SSL)
int NetworkConnect(Network* n, char* addr, int port)
{
struct sockaddr_in sAddr;
int retVal = -1;
struct hostent *hptr;
char **pptr;
char str[32];
int keepalive_enable = 1;
int keep_idle = 30;
if(n->my_socket >= 0){
n->disconnect(n);
}
if ((hptr = gethostbyname(addr)) == 0)
{
mqtt_printf(MQTT_DEBUG, "gethostbyname failed!");
goto exit;
}
pptr = hptr->h_addr_list;
for(; *pptr!=NULL; pptr++)
{
inet_ntop(hptr->h_addrtype, (const ip_addr_t *)*pptr, str, sizeof(str));
}
inet_ntop(hptr->h_addrtype, (const ip_addr_t *)hptr->h_addr, str, sizeof(str));
sAddr.sin_family = AF_INET;
sAddr.sin_port = htons(port);
sAddr.sin_addr.s_addr = inet_addr(str);
mqtt_printf(MQTT_DEBUG, "addr = %s", str);
if ((n->my_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
goto exit;
}
setsockopt( n->my_socket, SOL_SOCKET, SO_KEEPALIVE,
(const char *) &keepalive_enable, sizeof( keepalive_enable ) );
setsockopt( n->my_socket, IPPROTO_TCP, TCP_KEEPIDLE,
(const char *) &keep_idle, sizeof( keep_idle ) );
if ((retVal = connect(n->my_socket, (struct sockaddr*)&sAddr, sizeof(sAddr))) < 0)
{
close(n->my_socket);
n->my_socket = -1;
mqtt_printf(MQTT_DEBUG, "Connect failed!!");
goto exit;
}
#if (MQTT_OVER_SSL)
mbedtls_x509_crt *root_crt;
mbedtls_x509_crt *client_crt;
mbedtls_pk_context *client_rsa;
root_crt = NULL;
client_crt = NULL;
client_rsa = NULL;
if ( n->use_ssl != 0 ) {
mbedtls_platform_set_calloc_free(my_calloc, vPortFree);
n->ssl = (mbedtls_ssl_context *) malloc( sizeof(mbedtls_ssl_context) );
n->conf = (mbedtls_ssl_config *) malloc( sizeof(mbedtls_ssl_config) );
if (( n->ssl == NULL )||( n->conf == NULL )) {
mqtt_printf(MQTT_DEBUG, "malloc ssl failed!");
goto err;
}
mbedtls_ssl_init(n->ssl);
mbedtls_ssl_config_init(n->conf);
if((mbedtls_ssl_config_defaults(n->conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
mqtt_printf(MQTT_DEBUG, "ssl config defaults failed!");
goto err;
}
mbedtls_ssl_set_bio(n->ssl, &n->my_socket, mbedtls_net_send, mbedtls_net_recv, NULL);
mbedtls_ssl_conf_rng(n->conf, my_random, NULL);
#if MBEDTLS_SSL_MAX_CONTENT_LEN == 512
if(mbedtls_ssl_conf_max_frag_len(n->conf, MBEDTLS_SSL_MAX_FRAG_LEN_512) < 0) {
printf("ssl conf max frag len failed!");
goto err;
}
#elif MBEDTLS_SSL_MAX_CONTENT_LEN == 1024
if(mbedtls_ssl_conf_max_frag_len(n->conf, MBEDTLS_SSL_MAX_FRAG_LEN_1024) < 0) {
printf("ssl conf max frag len failed!");
goto err;
}
#elif MBEDTLS_SSL_MAX_CONTENT_LEN == 2048
if(mbedtls_ssl_conf_max_frag_len(n->conf, MBEDTLS_SSL_MAX_FRAG_LEN_2048) < 0) {
printf("ssl conf max frag len failed!");
goto err;
}
#elif MBEDTLS_SSL_MAX_CONTENT_LEN == 4096
if(mbedtls_ssl_conf_max_frag_len(n->conf, MBEDTLS_SSL_MAX_FRAG_LEN_4096) < 0) {
printf("ssl conf max frag len failed!");
goto err;
}
#endif
if((mbedtls_ssl_setup(n->ssl, n->conf)) != 0) {
mqtt_printf(MQTT_DEBUG,"mbedtls_ssl_setup failed!");
goto err;
}
if (n->rootCA != NULL) {
root_crt = (mbedtls_x509_crt *) mbedtls_calloc( sizeof(mbedtls_x509_crt), 1);
if ( root_crt == NULL ) {
mqtt_printf(MQTT_DEBUG, "malloc root_crt failed!");
goto err;
}
mbedtls_x509_crt_init(root_crt);
if (mbedtls_x509_crt_parse( root_crt, (const unsigned char *)n->rootCA, strlen(n->rootCA)+1 ) != 0) {
mqtt_printf(MQTT_DEBUG, "parse root_crt failed!");
goto err;
}
mbedtls_ssl_conf_ca_chain( n->conf, root_crt, NULL);
mbedtls_ssl_conf_authmode(n->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
mbedtls_ssl_conf_verify( n->conf, (int (*)(void *, mbedtls_x509_crt *, int, uint32_t *))mqtt_tls_verify, NULL );
mqtt_printf(MQTT_DEBUG, "root_crt parse done");
} else {
mbedtls_ssl_conf_authmode(n->conf, MBEDTLS_SSL_VERIFY_NONE);
}
if (n->clientCA != NULL && n->private_key != NULL) {
client_crt = (mbedtls_x509_crt *) mbedtls_calloc( sizeof(mbedtls_x509_crt), 1);
if ( client_crt == NULL ) {
mqtt_printf(MQTT_DEBUG, "malloc client_crt failed!");
goto err;
}
mbedtls_x509_crt_init(client_crt);
client_rsa = (mbedtls_pk_context *) mbedtls_calloc( sizeof(mbedtls_pk_context), 1);
if ( client_rsa == NULL ) {
mqtt_printf(MQTT_DEBUG, "malloc client_rsa failed!");
goto err;
}
mbedtls_pk_init(client_rsa);
if ( mbedtls_x509_crt_parse(client_crt, (const unsigned char *)n->clientCA, strlen(n->clientCA)+1) != 0 ) {
mqtt_printf(MQTT_DEBUG, "parse client_crt failed!");
goto err;
}
if ( mbedtls_pk_parse_key(client_rsa, (const unsigned char *)n->private_key, strlen(n->private_key)+1, NULL, 0) != 0 ) {
mqtt_printf(MQTT_DEBUG, "parse client_rsa failed!");
goto err;
}
mbedtls_ssl_conf_own_cert(n->conf, client_crt, client_rsa);
}
retVal = mbedtls_ssl_handshake(n->ssl);
if (retVal < 0) {
mqtt_printf(MQTT_DEBUG, "ssl handshake failed err:-0x%04X", -retVal);
goto err;
} else {
mqtt_printf(MQTT_DEBUG, "ssl handshake success");
}
}
if (client_rsa) {
mbedtls_pk_free(client_rsa);
mbedtls_free(client_rsa);
}
if (client_crt) {
mbedtls_x509_crt_free(client_crt);
mbedtls_free(client_crt);
}
if (root_crt) {
mbedtls_x509_crt_free(root_crt);
mbedtls_free(root_crt);
}
goto exit;
err:
if (client_rsa) {
mbedtls_pk_free(client_rsa);
mbedtls_free(client_rsa);
}
if (client_crt) {
mbedtls_x509_crt_free(client_crt);
mbedtls_free(client_crt);
}
if (root_crt) {
mbedtls_x509_crt_free(root_crt);
mbedtls_free(root_crt);
}
mbedtls_net_free((mbedtls_net_context *)&n->my_socket);
mbedtls_ssl_free(n->ssl);
mbedtls_ssl_config_free(n->conf);
free(n->ssl);
free(n->conf);
retVal = -1;
#endif // #if (MQTT_OVER_SSL)
exit:
return retVal;
}
#endif /* CONFIG_USE_POLARSSL */
#if 0
int NetworkConnectTLS(Network *n, char* addr, int port, SlSockSecureFiles_t* certificates, unsigned char sec_method, unsigned int cipher, char server_verify)
{
SlSockAddrIn_t sAddr;
int addrSize;
int retVal;
unsigned long ipAddress;
retVal = sl_NetAppDnsGetHostByName(addr, strlen(addr), &ipAddress, AF_INET);
if (retVal < 0) {
return -1;
}
sAddr.sin_family = AF_INET;
sAddr.sin_port = sl_Htons((unsigned short)port);
sAddr.sin_addr.s_addr = sl_Htonl(ipAddress);
addrSize = sizeof(SlSockAddrIn_t);
n->my_socket = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, SL_SEC_SOCKET);
if (n->my_socket < 0) {
return -1;
}
SlSockSecureMethod method;
method.secureMethod = sec_method;
retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method));
if (retVal < 0) {
return retVal;
}
SlSockSecureMask mask;
mask.secureMask = cipher;
retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_MASK, &mask, sizeof(mask));
if (retVal < 0) {
return retVal;
}
if (certificates != NULL) {
retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_FILES, certificates->secureFiles, sizeof(SlSockSecureFiles_t));
if (retVal < 0)
{
return retVal;
}
}
retVal = sl_Connect(n->my_socket, (SlSockAddr_t *)&sAddr, addrSize);
if (retVal < 0) {
if (server_verify || retVal != -453) {
sl_Close(n->my_socket);
return retVal;
}
}
SysTickIntRegister(SysTickIntHandler);
SysTickPeriodSet(80000);
SysTickEnable();
return retVal;
}
#endif

View File

@@ -0,0 +1,122 @@
/*******************************************************************************
* Copyright (c) 2014, 2015 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Allan Stockdill-Mander - initial API and implementation and/or initial documentation
*******************************************************************************/
#if !defined(MQTTFreeRTOS_H)
#define MQTTFreeRTOS_H
#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
#include "lwip/sockets.h"
#include "osdep_service.h"
#define MQTT_OVER_SSL (1)
#if (MQTT_OVER_SSL)
#if CONFIG_USE_POLARSSL
#include "polarssl/config.h"
#include "polarssl/net.h"
#include "polarssl/ssl.h"
#include "polarssl/error.h"
#include "polarssl/memory.h"
#elif CONFIG_USE_MBEDTLS
#include "mbedtls/config.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#endif
#endif
enum {
MQTT_EXCESSIVE, MQTT_MSGDUMP, MQTT_DEBUG, MQTT_INFO, MQTT_ALWAYS, MQTT_WARNING, MQTT_ERROR
};
#define FreeRTOS_Select select
#define mqtt_printf(level, fmt, arg...) \
do {\
if (level >= MQTT_DEBUG) {\
{\
printf("\r\n[%d]mqtt:", rtw_get_current_time());\
printf(fmt, ##arg);\
printf("\n\r");\
} \
}\
}while(0)
typedef struct Timer
{
TickType_t xTicksToWait;
TimeOut_t xTimeOut;
} Timer;
typedef struct Network Network;
struct Network
{
int my_socket;
int (*mqttread) (Network*, unsigned char*, int, int);
int (*mqttwrite) (Network*, unsigned char*, int, int);
void (*disconnect) (Network*);
int m2m_rxevent;
#if (MQTT_OVER_SSL)
unsigned char use_ssl;
#if CONFIG_USE_POLARSSL
ssl_context *ssl;
#elif CONFIG_USE_MBEDTLS
mbedtls_ssl_context *ssl;
mbedtls_ssl_config *conf;
#endif
char *rootCA;
char *clientCA;
char *private_key;
#endif
};
void TimerInit(Timer*);
char TimerIsExpired(Timer*);
void TimerCountdownMS(Timer*, unsigned int);
void TimerCountdown(Timer*, unsigned int);
int TimerLeftMS(Timer*);
typedef struct Mutex
{
SemaphoreHandle_t sem;
} Mutex;
void MutexInit(Mutex*);
int MutexLock(Mutex*);
int MutexUnlock(Mutex*);
typedef struct Thread
{
TaskHandle_t task;
} Thread;
int ThreadStart(Thread*, void (*fn)(void*), void* arg);
int FreeRTOS_read(Network*, unsigned char*, int, int);
int FreeRTOS_write(Network*, unsigned char*, int, int);
void FreeRTOS_disconnect(Network*);
void NetworkInit(Network*);
int NetworkConnect(Network*, char*, int);
/*int NetworkConnectTLS(Network*, char*, int, SlSockSecureFiles_t*, unsigned char, unsigned int, char);*/
#endif

View File

@@ -0,0 +1,139 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTCONNECT_H_
#define MQTTCONNECT_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
typedef union
{
unsigned char all; /**< all connect flags */
#if defined(REVERSED)
struct
{
unsigned int username : 1; /**< 3.1 user name */
unsigned int password : 1; /**< 3.1 password */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int will : 1; /**< will flag */
unsigned int cleansession : 1; /**< clean session flag */
unsigned int : 1; /**< unused */
} bits;
#else
struct
{
unsigned int : 1; /**< unused */
unsigned int cleansession : 1; /**< cleansession flag */
unsigned int will : 1; /**< will flag */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int password : 1; /**< 3.1 password */
unsigned int username : 1; /**< 3.1 user name */
} bits;
#endif
} MQTTConnectFlags; /**< connect flags byte */
/**
* Defines the MQTT "Last Will and Testament" (LWT) settings for
* the connect packet.
*/
typedef struct
{
/** The eyecatcher for this structure. must be MQTW. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
int struct_version;
/** The LWT topic to which the LWT message will be published. */
MQTTString topicName;
/** The LWT payload. */
MQTTString message;
/**
* The retained flag for the LWT message (see MQTTAsync_message.retained).
*/
unsigned char retained;
/**
* The quality of service setting for the LWT message (see
* MQTTAsync_message.qos and @ref qos).
*/
char qos;
} MQTTPacket_willOptions;
#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
typedef struct
{
/** The eyecatcher for this structure. must be MQTC. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
int struct_version;
/** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
*/
unsigned char MQTTVersion;
MQTTString clientID;
unsigned short keepAliveInterval;
unsigned char cleansession;
unsigned char willFlag;
MQTTPacket_willOptions will;
MQTTString username;
MQTTString password;
} MQTTPacket_connectData;
typedef union
{
unsigned char all; /**< all connack flags */
#if defined(REVERSED)
struct
{
unsigned int sessionpresent : 1; /**< session present flag */
unsigned int : 7; /**< unused */
} bits;
#else
struct
{
unsigned int : 7; /**< unused */
unsigned int sessionpresent : 1; /**< session present flag */
} bits;
#endif
} MQTTConnackFlags; /**< connack flags byte */
#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
#endif /* MQTTCONNECT_H_ */

View File

@@ -0,0 +1,214 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
* @param options the options to be used to build the connect packet
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
{
int len = 0;
FUNC_ENTRY;
if (options->MQTTVersion == 3)
len = 12; /* variable depending on MQTT or MQIsdp */
else if (options->MQTTVersion == 4)
len = 10;
len += MQTTstrlen(options->clientID)+2;
if (options->willFlag)
len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
if (options->username.cstring || options->username.lenstring.data)
len += MQTTstrlen(options->username)+2;
if (options->password.cstring || options->password.lenstring.data)
len += MQTTstrlen(options->password)+2;
FUNC_EXIT_RC(len);
return len;
}
/**
* Serializes the connect options into the buffer.
* @param buf the buffer into which the packet will be serialized
* @param len the length in bytes of the supplied buffer
* @param options the options to be used to build the connect packet
* @return serialized length, or error if 0
*/
int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
MQTTConnectFlags flags = {0};
int len = 0;
int rc = -1;
FUNC_ENTRY;
if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = CONNECT;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
if (options->MQTTVersion == 4)
{
writeCString(&ptr, "MQTT");
writeChar(&ptr, (char) 4);
}
else
{
writeCString(&ptr, "MQIsdp");
writeChar(&ptr, (char) 3);
}
flags.all = 0;
flags.bits.cleansession = options->cleansession;
flags.bits.will = (options->willFlag) ? 1 : 0;
if (flags.bits.will)
{
flags.bits.willQoS = options->will.qos;
flags.bits.willRetain = options->will.retained;
}
if (options->username.cstring || options->username.lenstring.data)
flags.bits.username = 1;
if (options->password.cstring || options->password.lenstring.data)
flags.bits.password = 1;
writeChar(&ptr, flags.all);
writeInt(&ptr, options->keepAliveInterval);
writeMQTTString(&ptr, options->clientID);
if (options->willFlag)
{
writeMQTTString(&ptr, options->will.topicName);
writeMQTTString(&ptr, options->will.message);
}
if (flags.bits.username)
writeMQTTString(&ptr, options->username);
if (flags.bits.password)
writeMQTTString(&ptr, options->password);
rc = ptr - buf;
exit: FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into connack data - return code
* @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
* @param connack_rc returned integer value of the connack return code
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param len the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
MQTTConnackFlags flags = {0};
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != CONNACK)
goto exit;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
flags.all = readChar(&curdata);
*sessionPresent = flags.bits.sessionpresent;
*connack_rc = readChar(&curdata);
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @param packettype the message type
* @return serialized length, or error if 0
*/
int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
{
MQTTHeader header = {0};
int rc = -1;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = packettype;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @return serialized length, or error if 0
*/
int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
{
return MQTTSerialize_zero(buf, buflen, DISCONNECT);
}
/**
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @return serialized length, or error if 0
*/
int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
{
return MQTTSerialize_zero(buf, buflen, PINGREQ);
}

View File

@@ -0,0 +1,147 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
#define min(a, b) ((a < b) ? a : b)
/**
* Validates MQTT protocol name and version combinations
* @param protocol the MQTT protocol name as an MQTTString
* @param version the MQTT protocol version number, as in the connect packet
* @return correct MQTT combination? 1 is true, 0 is false
*/
int MQTTPacket_checkVersion(MQTTString* protocol, int version)
{
int rc = 0;
if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
min(6, protocol->lenstring.len)) == 0)
rc = 1;
else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
min(4, protocol->lenstring.len)) == 0)
rc = 1;
return rc;
}
/**
* Deserializes the supplied (wire) buffer into connect data structure
* @param data the connect data structure to be filled out
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param len the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
{
MQTTHeader header = {0};
MQTTConnectFlags flags = {0};
unsigned char* curdata = buf;
unsigned char* enddata = &buf[len];
int rc = 0;
MQTTString Protocol;
int version;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != CONNECT)
goto exit;
curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
goto exit;
version = (int)readChar(&curdata); /* Protocol version */
/* If we don't recognize the protocol version, we don't parse the connect packet on the
* basis that we don't know what the format will be.
*/
if (MQTTPacket_checkVersion(&Protocol, version))
{
flags.all = readChar(&curdata);
data->cleansession = flags.bits.cleansession;
data->keepAliveInterval = readInt(&curdata);
if (!readMQTTLenString(&data->clientID, &curdata, enddata))
goto exit;
data->willFlag = flags.bits.will;
if (flags.bits.will)
{
data->will.qos = flags.bits.willQoS;
data->will.retained = flags.bits.willRetain;
if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
!readMQTTLenString(&data->will.message, &curdata, enddata))
goto exit;
}
if (flags.bits.username)
{
if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
goto exit; /* username flag set, but no username supplied - invalid */
if (flags.bits.password &&
(enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
goto exit; /* password flag set, but no password supplied - invalid */
}
else if (flags.bits.password)
goto exit; /* password flag set without username - invalid */
rc = 1;
}
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the connack packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param connack_rc the integer connack return code to be used
* @param sessionPresent the MQTT 3.1.1 sessionPresent flag
* @return serialized length, or error if 0
*/
int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
MQTTConnackFlags flags = {0};
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = CONNACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
flags.all = 0;
flags.bits.sessionpresent = sessionPresent;
writeChar(&ptr, flags.all);
writeChar(&ptr, connack_rc);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@@ -0,0 +1,105 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
#define min(a, b) ((a < b) ? 1 : 0)
/**
* Deserializes the supplied (wire) buffer into publish data
* @param dup returned integer - the MQTT dup flag
* @param qos returned integer - the MQTT QoS value
* @param retained returned integer - the MQTT retained flag
* @param packetid returned integer - the MQTT packet identifier
* @param topicName returned MQTTString - the MQTT topic in the publish
* @param payload returned byte buffer - the MQTT publish payload
* @param payloadlen returned integer - the length of the MQTT payload
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success
*/
int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != PUBLISH)
goto exit;
*dup = header.bits.dup;
*qos = header.bits.qos;
*retained = header.bits.retain;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (!readMQTTLenString(topicName, &curdata, enddata) ||
enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
goto exit;
if (*qos > 0)
*packetid = readInt(&curdata);
*payloadlen = enddata - curdata;
*payload = curdata;
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into an ack
* @param packettype returned integer - the MQTT packet type
* @param dup returned integer - the MQTT dup flag
* @param packetid returned integer - the MQTT packet identifier
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
FUNC_ENTRY;
header.byte = readChar(&curdata);
*dup = header.bits.dup;
*packettype = header.bits.type;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
*packetid = readInt(&curdata);
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@@ -0,0 +1,255 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
const char* MQTTPacket_names[] =
{
"RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",
"PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",
"PINGREQ", "PINGRESP", "DISCONNECT"
};
const char* MQTTPacket_getName(unsigned short packetid)
{
return MQTTPacket_names[packetid];
}
int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)
{
int strindex = 0;
strindex = snprintf(strbuf, strbuflen,
"CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",
(int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,
(int)data->cleansession, data->keepAliveInterval);
if (data->willFlag)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", will QoS %d, will retain %d, will topic %.*s, will message %.*s",
data->will.qos, data->will.retained,
data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,
data->will.message.lenstring.len, data->will.message.lenstring.data);
if (data->username.lenstring.data && data->username.lenstring.len > 0)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);
if (data->password.lenstring.data && data->password.lenstring.len > 0)
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
", password %.*s", data->password.lenstring.len, data->password.lenstring.data);
return strindex;
}
int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)
{
int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);
return strindex;
}
int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)
{
int strindex = snprintf(strbuf, strbuflen,
"PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",
dup, qos, retained, packetid,
(topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,
payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);
return strindex;
}
int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
{
int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);
if (dup)
strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);
return strindex;
}
int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[])
{
return snprintf(strbuf, strbuflen,
"SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",
dup, packetid, count,
topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,
requestedQoSs[0]);
}
int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)
{
return snprintf(strbuf, strbuflen,
"SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);
}
int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[])
{
return snprintf(strbuf, strbuflen,
"UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",
dup, packetid, count,
topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);
}
char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
{
int index = 0;
int rem_length = 0;
MQTTHeader header = {0};
header.byte = buf[index++];
index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
switch (header.bits.type)
{
case CONNACK:
{
unsigned char sessionPresent, connack_rc;
if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)
MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);
}
break;
case PUBLISH:
{
unsigned char dup, retained, *payload;
unsigned short packetid;
int qos, payloadlen;
MQTTString topicName = MQTTString_initializer;
if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
&payload, &payloadlen, buf, buflen) == 1)
MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
topicName, payload, payloadlen);
}
break;
case PUBACK:
case PUBREC:
case PUBREL:
case PUBCOMP:
{
unsigned char packettype, dup;
unsigned short packetid;
if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
}
break;
case SUBACK:
{
unsigned short packetid;
int maxcount = 1, count = 0;
int grantedQoSs[1];
if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)
MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);
}
break;
case UNSUBACK:
{
unsigned short packetid;
if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)
MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);
}
break;
case PINGREQ:
case PINGRESP:
case DISCONNECT:
snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
break;
}
return strbuf;
}
char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
{
int index = 0;
int rem_length = 0;
MQTTHeader header = {0};
header.byte = buf[index++];
index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
switch (header.bits.type)
{
case CONNECT:
{
MQTTPacket_connectData data;
if ((MQTTDeserialize_connect(&data, buf, buflen)) == 1)
MQTTStringFormat_connect(strbuf, strbuflen, &data);
}
break;
case PUBLISH:
{
unsigned char dup, retained, *payload;
unsigned short packetid;
int qos, payloadlen;
MQTTString topicName = MQTTString_initializer;
if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
&payload, &payloadlen, buf, buflen) == 1)
MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
topicName, payload, payloadlen);
}
break;
case PUBACK:
case PUBREC:
case PUBREL:
case PUBCOMP:
{
unsigned char packettype, dup;
unsigned short packetid;
if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
}
break;
case SUBSCRIBE:
{
unsigned char dup;
unsigned short packetid;
int maxcount = 1, count = 0;
MQTTString topicFilters[1];
int requestedQoSs[1];
if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,
topicFilters, requestedQoSs, buf, buflen) == 1)
MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;
}
break;
case UNSUBSCRIBE:
{
unsigned char dup;
unsigned short packetid;
int maxcount = 1, count = 0;
MQTTString topicFilters[1];
if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)
MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);
}
break;
case PINGREQ:
case PINGRESP:
case DISCONNECT:
snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
break;
}
strbuf[strbuflen] = '\0';
return strbuf;
}

View File

@@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#if !defined(MQTTFORMAT_H)
#define MQTTFORMAT_H
#include "StackTrace.h"
#include "MQTTPacket.h"
const char* MQTTPacket_getName(unsigned short packetid);
int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[]);
int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[]);
char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
#endif

View File

@@ -0,0 +1,410 @@
/****************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Sergio R. Caprile - non-blocking packet read functions for stream transport
*******************************************************************************/
#include "StackTrace.h"
#include "MQTTPacket.h"
#include <string.h>
/**
* Encodes the message length according to the MQTT algorithm
* @param buf the buffer into which the encoded data is written
* @param length the length to be encoded
* @return the number of bytes written to buffer
*/
int MQTTPacket_encode(unsigned char* buf, int length)
{
int rc = 0;
FUNC_ENTRY;
do
{
char d = length % 128;
length /= 128;
/* if there are more digits to encode, set the top bit of this digit */
if (length > 0)
d |= 0x80;
buf[rc++] = d;
} while (length > 0);
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Decodes the message length according to the MQTT algorithm
* @param getcharfn pointer to function to read the next character from the data source
* @param value the decoded length returned
* @return the number of bytes read from the socket
*/
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
{
unsigned char c;
int multiplier = 1;
int len = 0;
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
FUNC_ENTRY;
*value = 0;
do
{
int rc = MQTTPACKET_READ_ERROR;
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
{
rc = MQTTPACKET_READ_ERROR; /* bad data */
goto exit;
}
rc = (*getcharfn)(&c, 1);
if (rc != 1)
goto exit;
*value += (c & 127) * multiplier;
multiplier *= 128;
} while ((c & 128) != 0);
exit:
FUNC_EXIT_RC(len);
return len;
}
int MQTTPacket_len(int rem_len)
{
rem_len += 1; /* header byte */
/* now remaining_length field */
if (rem_len < 128)
rem_len += 1;
else if (rem_len < 16384)
rem_len += 2;
else if (rem_len < 2097151)
rem_len += 3;
else
rem_len += 4;
return rem_len;
}
static unsigned char* bufptr;
int bufchar(unsigned char* c, int count)
{
int i;
for (i = 0; i < count; ++i)
*c = *bufptr++;
return count;
}
int MQTTPacket_decodeBuf(unsigned char* buf, int* value)
{
bufptr = buf;
return MQTTPacket_decode(bufchar, value);
}
/**
* Calculates an integer from two bytes read from the input buffer
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the integer value calculated
*/
int readInt(unsigned char** pptr)
{
unsigned char* ptr = *pptr;
int len = 256*(*ptr) + (*(ptr+1));
*pptr += 2;
return len;
}
/**
* Reads one character from the input buffer.
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the character read
*/
char readChar(unsigned char** pptr)
{
char c = **pptr;
(*pptr)++;
return c;
}
/**
* Writes one character to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param c the character to write
*/
void writeChar(unsigned char** pptr, char c)
{
**pptr = c;
(*pptr)++;
}
/**
* Writes an integer as 2 bytes to an output buffer.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param anInt the integer to write
*/
void writeInt(unsigned char** pptr, int anInt)
{
**pptr = (unsigned char)(anInt / 256);
(*pptr)++;
**pptr = (unsigned char)(anInt % 256);
(*pptr)++;
}
/**
* Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param string the C string to write
*/
void writeCString(unsigned char** pptr, const char* string)
{
int len = strlen(string);
writeInt(pptr, len);
memcpy(*pptr, string, len);
*pptr += len;
}
int getLenStringLen(char* ptr)
{
int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
return len;
}
void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
{
if (mqttstring.lenstring.len > 0)
{
writeInt(pptr, mqttstring.lenstring.len);
memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
*pptr += mqttstring.lenstring.len;
}
else if (mqttstring.cstring)
writeCString(pptr, mqttstring.cstring);
else
writeInt(pptr, 0);
}
/**
* @param mqttstring the MQTTString structure into which the data is to be read
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param enddata pointer to the end of the data: do not read beyond
* @return 1 if successful, 0 if not
*/
int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
{
int rc = 0;
FUNC_ENTRY;
/* the first two bytes are the length of the string */
if (enddata - (*pptr) > 1) /* enough length to read the integer? */
{
mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
{
mqttstring->lenstring.data = (char*)*pptr;
*pptr += mqttstring->lenstring.len;
rc = 1;
}
}
mqttstring->cstring = NULL;
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
* @param mqttstring the string to return the length of
* @return the length of the string
*/
int MQTTstrlen(MQTTString mqttstring)
{
int rc = 0;
if (mqttstring.cstring)
rc = strlen(mqttstring.cstring);
else
rc = mqttstring.lenstring.len;
return rc;
}
/**
* Compares an MQTTString to a C string
* @param a the MQTTString to compare
* @param bptr the C string to compare
* @return boolean - equal or not
*/
int MQTTPacket_equals(MQTTString* a, char* bptr)
{
int alen = 0,
blen = 0;
char *aptr;
if (a->cstring)
{
aptr = a->cstring;
alen = strlen(a->cstring);
}
else
{
aptr = a->lenstring.data;
alen = a->lenstring.len;
}
blen = strlen(bptr);
return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
}
/**
* Helper function to read packet data from some source into a buffer
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param getfn pointer to a function which will read any number of bytes from the needed source
* @return integer MQTT packet type, or -1 on error
* @note the whole message must fit into the caller's buffer
*/
int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
{
int rc = -1;
MQTTHeader header = {0};
int len = 0;
int rem_len = 0;
/* 1. read the header byte. This has the packet type in it */
if ((*getfn)(buf, 1) != 1)
goto exit;
len = 1;
/* 2. read the remaining length. This is variable in itself */
MQTTPacket_decode(getfn, &rem_len);
len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
if((rem_len + len) > buflen)
goto exit;
if ((*getfn)(buf + len, rem_len) != rem_len)
goto exit;
header.byte = buf[0];
rc = header.bits.type;
exit:
return rc;
}
/**
* Decodes the message length according to the MQTT algorithm, non-blocking
* @param trp pointer to a transport structure holding what is needed to solve getting data from it
* @param value the decoded length returned
* @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
*/
static int MQTTPacket_decodenb(MQTTTransport *trp)
{
unsigned char c;
int rc = MQTTPACKET_READ_ERROR;
FUNC_ENTRY;
if(trp->len == 0){ /* initialize on first call */
trp->multiplier = 1;
trp->rem_len = 0;
}
do {
int frc;
if (++(trp->len) > MAX_NO_OF_REMAINING_LENGTH_BYTES)
goto exit;
if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
goto exit;
if (frc == 0){
rc = 0;
goto exit;
}
trp->rem_len += (c & 127) * trp->multiplier;
trp->multiplier *= 128;
} while ((c & 128) != 0);
rc = trp->len;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Helper function to read packet data from some source into a buffer, non-blocking
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param trp pointer to a transport structure holding what is needed to solve getting data from it
* @return integer MQTT packet type, 0 for call again, or -1 on error
* @note the whole message must fit into the caller's buffer
*/
int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
{
int rc = -1, frc;
MQTTHeader header = {0};
switch(trp->state){
default:
trp->state = 0;
/*FALLTHROUGH*/
case 0:
/* read the header byte. This has the packet type in it */
if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
goto exit;
if (frc == 0)
return 0;
trp->len = 0;
++trp->state;
/*FALLTHROUGH*/
/* read the remaining length. This is variable in itself */
case 1:
if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
goto exit;
if(frc == 0)
return 0;
trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
if((trp->rem_len + trp->len) > buflen)
goto exit;
++trp->state;
/*FALLTHROUGH*/
case 2:
/* read the rest of the buffer using a callback to supply the rest of the data */
if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
goto exit;
if (frc == 0)
return 0;
trp->rem_len -= frc;
trp->len += frc;
if(trp->rem_len)
return 0;
header.byte = buf[0];
rc = header.bits.type;
break;
}
exit:
trp->state = 0;
return rc;
}

View File

@@ -0,0 +1,133 @@
/*******************************************************************************
/ * Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTPACKET_H_
#define MQTTPACKET_H_
#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
#if defined(WIN32_DLL) || defined(WIN64_DLL)
#define DLLImport __declspec(dllimport)
#define DLLExport __declspec(dllexport)
#elif defined(LINUX_SO)
#define DLLImport extern
#define DLLExport __attribute__ ((visibility ("default")))
#else
#define DLLImport
#define DLLExport
#endif
enum errors
{
MQTTPACKET_BUFFER_TOO_SHORT = -2,
MQTTPACKET_READ_ERROR = -1,
MQTTPACKET_READ_COMPLETE
};
enum msgTypes
{
CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
PINGREQ, PINGRESP, DISCONNECT
};
/**
* Bitfields for the MQTT header byte.
*/
typedef union
{
unsigned char byte; /**< the whole byte */
#if defined(REVERSED)
struct
{
unsigned int type : 4; /**< message type nibble */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int retain : 1; /**< retained flag bit */
} bits;
#else
struct
{
unsigned int retain : 1; /**< retained flag bit */
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
unsigned int dup : 1; /**< DUP flag bit */
unsigned int type : 4; /**< message type nibble */
} bits;
#endif
} MQTTHeader;
typedef struct
{
int len;
char* data;
} MQTTLenString;
typedef struct
{
char* cstring;
MQTTLenString lenstring;
} MQTTString;
#define MQTTString_initializer {NULL, {0, NULL}}
int MQTTstrlen(MQTTString mqttstring);
#include "MQTTConnect.h"
#include "MQTTPublish.h"
#include "MQTTSubscribe.h"
#include "MQTTUnsubscribe.h"
#include "MQTTFormat.h"
int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
int MQTTPacket_len(int rem_len);
int MQTTPacket_equals(MQTTString* a, char* b);
int MQTTPacket_encode(unsigned char* buf, int length);
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
int readInt(unsigned char** pptr);
char readChar(unsigned char** pptr);
void writeChar(unsigned char** pptr, char c);
void writeInt(unsigned char** pptr, int anInt);
int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
void writeCString(unsigned char** pptr, const char* string);
void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
typedef struct {
int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
void *sck; /* pointer to whatever the system may use to identify the transport */
int multiplier;
int rem_len;
int len;
char state;
}MQTTTransport;
int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
}
#endif
#endif /* MQTTPACKET_H_ */

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTPUBLISH_H_
#define MQTTPUBLISH_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
MQTTString topicName, unsigned char* payload, int payloadlen);
DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
#endif /* MQTTPUBLISH_H_ */

View File

@@ -0,0 +1,169 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT publish packet that would be produced using the supplied parameters
* @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
* @param topicName the topic name to be used in the publish
* @param payloadlen the length of the payload to be sent
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
{
int len = 0;
len += 2 + MQTTstrlen(topicName) + payloadlen;
if (qos > 0)
len += 2; /* packetid */
return len;
}
/**
* Serializes the supplied publish data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param qos integer - the MQTT QoS value
* @param retained integer - the MQTT retained flag
* @param packetid integer - the MQTT packet identifier
* @param topicName MQTTString - the MQTT topic in the publish
* @param payload byte buffer - the MQTT publish payload
* @param payloadlen integer - the length of the MQTT payload
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
MQTTString topicName, unsigned char* payload, int payloadlen)
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.bits.type = PUBLISH;
header.bits.dup = dup;
header.bits.qos = qos;
header.bits.retain = retained;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeMQTTString(&ptr, topicName);
if (qos > 0)
writeInt(&ptr, packetid);
memcpy(ptr, payload, payloadlen);
ptr += payloadlen;
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the ack packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param type the MQTT packet type
* @param dup the MQTT dup flag
* @param packetid the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 4)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.bits.type = packettype;
header.bits.dup = dup;
header.bits.qos = (packettype == PUBREL) ? 1 : 0;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
writeInt(&ptr, packetid);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes a puback packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
}
/**
* Serializes a pubrel packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
}
/**
* Serializes a pubrel packet into the supplied buffer.
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return serialized length, or error if 0
*/
int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
{
return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
}

View File

@@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTSUBSCRIBE_H_
#define MQTTSUBSCRIBE_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[], int requestedQoSs[]);
DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);
#endif /* MQTTSUBSCRIBE_H_ */

View File

@@ -0,0 +1,135 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
{
int i;
int len = 2; /* packetid */
for (i = 0; i < count; ++i)
len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
return len;
}
/**
* Serializes the supplied subscribe data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied bufferr
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the topicFilters and reqQos arrays
* @param topicFilters - array of topic filter names
* @param requestedQoSs - array of requested QoS
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
MQTTString topicFilters[], int requestedQoSs[])
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = 0;
int i = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = SUBSCRIBE;
header.bits.dup = dup;
header.bits.qos = 1;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
{
writeMQTTString(&ptr, topicFilters[i]);
writeChar(&ptr, requestedQoSs[i]);
}
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into suback data
* @param packetid returned integer - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the grantedQoSs array
* @param count returned integer - number of members in the grantedQoSs array
* @param grantedQoSs returned array of integers - the granted qualities of service
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != SUBACK)
goto exit;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
if (enddata - curdata < 2)
goto exit;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (*count > maxcount)
{
rc = -1;
goto exit;
}
grantedQoSs[(*count)++] = readChar(&curdata);
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@@ -0,0 +1,110 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Deserializes the supplied (wire) buffer into subscribe data
* @param dup integer returned - the MQTT dup flag
* @param packetid integer returned - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
* @param count - number of members in the topicFilters and requestedQoSs arrays
* @param topicFilters - array of topic filter names
* @param requestedQoSs - array of requested QoS
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
int requestedQoSs[], unsigned char* buf, int buflen)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = -1;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != SUBSCRIBE)
goto exit;
*dup = header.bits.dup;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
goto exit;
if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
goto exit;
requestedQoSs[*count] = readChar(&curdata);
(*count)++;
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the supplied suback data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the grantedQoSs array
* @param grantedQoSs - array of granted QoS
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)
{
MQTTHeader header = {0};
int rc = -1;
unsigned char *ptr = buf;
int i;
FUNC_ENTRY;
if (buflen < 2 + count)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = SUBACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
writeChar(&ptr, grantedQoSs[i]);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Xiang Rong - 442039 Add makefile to Embedded C client
*******************************************************************************/
#ifndef MQTTUNSUBSCRIBE_H_
#define MQTTUNSUBSCRIBE_H_
#if !defined(DLLImport)
#define DLLImport
#endif
#if !defined(DLLExport)
#define DLLExport
#endif
DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[]);
DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
unsigned char* buf, int len);
DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
#endif /* MQTTUNSUBSCRIBE_H_ */

View File

@@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
* @param count the number of topic filter strings in topicFilters
* @param topicFilters the array of topic filter strings to be used in the publish
* @return the length of buffer needed to contain the serialized version of the packet
*/
int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
{
int i;
int len = 2; /* packetid */
for (i = 0; i < count; ++i)
len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
return len;
}
/**
* Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @param dup integer - the MQTT dup flag
* @param packetid integer - the MQTT packet identifier
* @param count - number of members in the topicFilters array
* @param topicFilters - array of topic filter names
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
int count, MQTTString topicFilters[])
{
unsigned char *ptr = buf;
MQTTHeader header = {0};
int rem_len = 0;
int rc = -1;
int i = 0;
FUNC_ENTRY;
if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = UNSUBSCRIBE;
header.bits.dup = dup;
header.bits.qos = 1;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
writeInt(&ptr, packetid);
for (i = 0; i < count; ++i)
writeMQTTString(&ptr, topicFilters[i]);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Deserializes the supplied (wire) buffer into unsuback data
* @param packetid returned integer - the MQTT packet identifier
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return error code. 1 is success, 0 is failure
*/
int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
{
unsigned char type = 0;
unsigned char dup = 0;
int rc = 0;
FUNC_ENTRY;
rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
if (type == UNSUBACK)
rc = 1;
FUNC_EXIT_RC(rc);
return rc;
}

View File

@@ -0,0 +1,100 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
*******************************************************************************/
#include "MQTTPacket.h"
#include "StackTrace.h"
#include <string.h>
/**
* Deserializes the supplied (wire) buffer into unsubscribe data
* @param dup integer returned - the MQTT dup flag
* @param packetid integer returned - the MQTT packet identifier
* @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
* @param count - number of members in the topicFilters and requestedQoSs arrays
* @param topicFilters - array of topic filter names
* @param buf the raw buffer data, of the correct length determined by the remaining length field
* @param buflen the length in bytes of the data in the supplied buffer
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
unsigned char* buf, int len)
{
MQTTHeader header = {0};
unsigned char* curdata = buf;
unsigned char* enddata = NULL;
int rc = 0;
int mylen = 0;
FUNC_ENTRY;
header.byte = readChar(&curdata);
if (header.bits.type != UNSUBSCRIBE)
goto exit;
*dup = header.bits.dup;
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
enddata = curdata + mylen;
*packetid = readInt(&curdata);
*count = 0;
while (curdata < enddata)
{
if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
goto exit;
(*count)++;
}
rc = 1;
exit:
FUNC_EXIT_RC(rc);
return rc;
}
/**
* Serializes the supplied unsuback data into the supplied buffer, ready for sending
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer
* @param packetid integer - the MQTT packet identifier
* @return the length of the serialized data. <= 0 indicates error
*/
int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
{
MQTTHeader header = {0};
int rc = 0;
unsigned char *ptr = buf;
FUNC_ENTRY;
if (buflen < 2)
{
rc = MQTTPACKET_BUFFER_TOO_SHORT;
goto exit;
}
header.byte = 0;
header.bits.type = UNSUBACK;
writeChar(&ptr, header.byte); /* write header */
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
writeInt(&ptr, packetid);
rc = ptr - buf;
exit:
FUNC_EXIT_RC(rc);
return rc;
}

View File

@@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright (c) 2014 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial API and implementation and/or initial documentation
* Ian Craggs - fix for bug #434081
*******************************************************************************/
#ifndef STACKTRACE_H_
#define STACKTRACE_H_
#include <stdio.h>
#define NOSTACKTRACE 1
#if defined(NOSTACKTRACE)
#define FUNC_ENTRY
#define FUNC_ENTRY_NOLOG
#define FUNC_ENTRY_MED
#define FUNC_ENTRY_MAX
#define FUNC_EXIT
#define FUNC_EXIT_NOLOG
#define FUNC_EXIT_MED
#define FUNC_EXIT_MAX
#define FUNC_EXIT_RC(x)
#define FUNC_EXIT_MED_RC(x)
#define FUNC_EXIT_MAX_RC(x)
#else
#if defined(WIN32)
#define inline __inline
#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
#else
#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
void StackTrace_entry(const char* name, int line, int trace);
void StackTrace_exit(const char* name, int line, void* return_value, int trace);
void StackTrace_printStack(FILE* dest);
char* StackTrace_get(unsigned long);
#endif
#endif
#endif /* STACKTRACE_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,271 @@
#include "osdep_service.h"
#include "serial_api.h"
#include <timer_api.h>
#include "freertos_pmu.h"
#include <mDNS/mDNS.h>
#include "gpio_api.h"
#include "gpio_irq_api.h"
#include "PinNames.h"
/******************************************************
* Macros
******************************************************/
#define UA_ERROR 0
#define UA_WARNING 1
#define UA_INFO 2
#define UA_DEBUG 3
#define UA_NONE 0xFF
#define UA_DEBUG_LEVEL UA_INFO
#define UA_UART_THREAD_PRIORITY 5
#define UA_UART_THREAD_STACKSIZE 512
#define UA_TCP_SERVER_FD_NUM 1
#define UA_TCP_CLIENT_FD_NUM 1
#define UA_UART_RECV_BUFFER_LEN 8196
#define UA_UART_FRAME_LEN 1400
#define UA_UART_MAX_DELAY_TIME 100
#define UA_CHAT_SOCKET_PORT 5001
#define UA_CONTROL_SOCKET_PORT 6001
#define UA_SC_SOFTAP_EN 1
#ifdef CONFIG_PLATFORM_8195A
#define UA_UART_TX_PIN PA_7
#define UA_UART_RX_PIN PA_6
#define UA_GPIO_LED_PIN PC_5
#define UA_GPIO_IRQ_PIN PC_4
#define UA_GPIO_TIMER TIMER0
#define UA_GPIO_WAKEUP_PIN PC_3
#endif
#ifdef CONFIG_PLATFORM_8711B
#define UA_UART_TX_PIN PA_23
#define UA_UART_RX_PIN PA_18
#define UA_GPIO_LED_PIN PA_5
#define UA_GPIO_IRQ_PIN PA_12
#define UA_GPIO_TIMER TIMER2
#define UA_GPIO_WAKEUP_PIN PA_0
#endif
#define UA_CONTROL_PREFIX "AMEBA_UART"
#define UA_PS_ENABLE 0
#define UA_WAKELOCK PMU_DEV_USER_BASE
#define UA_FAST_RECONNECT_TCP_DATA (0xF5000 + 0x1000)
#if (UA_DEBUG_LEVEL== UA_NONE)
#define ua_printf(level, fmt, arg...)
#else
#define ua_printf(level, fmt, arg...) \
do {\
if (level <= UA_DEBUG_LEVEL) {\
if (level <= UA_ERROR) {\
rtw_down_sema(&ua_print_sema);\
printf("\r\nERROR: " fmt, ##arg);\
rtw_up_sema(&ua_print_sema);\
} \
else {\
rtw_down_sema(&ua_print_sema);\
printf("\r\n"fmt, ##arg);\
rtw_up_sema(&ua_print_sema);\
} \
}\
}while(0)
#endif
#define UA_PRINT_DATA(_HexData, _HexDataLen) \
if(UA_DEBUG_LEVEL == UA_DEBUG) \
{ \
int __i; \
u8 *ptr = (u8 *)_HexData; \
printf("--------Len=%d\n\r", _HexDataLen); \
for( __i=0; __i<(int)_HexDataLen; __i++ ) \
{ \
printf("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" "); \
if (((__i + 1) % 16) == 0) printf("\n\r"); \
} \
printf("\n\r"); \
}
#define UA_SOCKET_CHECK(_ua_socket) \
if(_ua_socket == NULL) \
{ \
printf("ERROR: ua_socket = NULL\n\r"); \
return; \
}
#define UA_SOCKET_CHECK_2(_ua_socket) \
if(_ua_socket == NULL) \
{ \
printf("ERROR: ua_socket = NULL\n\r"); \
return -1; \
}
/******************************************************
* Constants
******************************************************/
typedef enum
{
UART_ADAPTER_LED_ON = 0,
UART_ADAPTER_LED_OFF = 1,
UART_ADAPTER_LED_FAST_TWINKLE = 2,
UART_ADAPTER_LED_SLOW_TWINKLE = 3,
}ua_led_mode_t;
typedef enum
{
UART_CTRL_MODE_SET_REQ = 0,
UART_CTRL_MODE_SET_RSP = 1,
UART_CTRL_MODE_GET_REQ = 2,
UART_CTRL_MODE_GET_RSP = 3,
}ua_ctrl_mode_t;
typedef enum
{
UART_CTRL_TYPE_BAUD_RATE = 0x01,
UART_CTRL_TYPE_WORD_LEN = 0x02,
UART_CTRL_TYPE_PARITY = 0x04,
UART_CTRL_TYPE_STOP_BIT = 0x08,
UART_CTRL_TYPE_TCP_SERVER_CREATE = 0x10,
UART_CTRL_TYPE_TCP_SERVER_DELETE = 0x20,
UART_CTRL_TYPE_TCP_CLIENT_CONNECT = 0x40,
UART_CTRL_TYPE_TCP_CLIENT_DISCONNECT = 0x80,
UART_CTRL_TYPE_TCP_GROUP_ID = 0x100,
}ua_ctrl_type_t;
/******************************************************
* Structures
******************************************************/
typedef struct _ua_uart_param_t
{
u8 WordLen;
u8 Parity;
u8 StopBit;
u8 FlowControl;
int BaudRate;
}ua_uart_param_t;
typedef struct _ua_uart_socket_t
{
int fd;
char rcv_ch;
volatile char overlap;
int recv_bytes;
volatile int pread;
volatile int pwrite;
volatile unsigned int tick_last_update;
unsigned int tick_current;
volatile int tx_busy;
volatile int uart_ps;
volatile int uart_ps_cnt;
char recv_buf[UA_UART_RECV_BUFFER_LEN];
long rx_cnt;
long miss_cnt;
serial_t uart_sobj;
ua_uart_param_t uart_param;
_sema action_sema;
_sema tcp_tx_rx_sema;
_sema dma_tx;
}ua_uart_socket_t;
typedef struct _ua_tcp_socket_t
{
int chat_socket;
int control_socket;
int chat_server_listen_socket;
int control_server_listen_socket;
int transmit_recv_socket;
int transmit_send_socket;
int transmit_server_listen_socket;
int group_id;
u32 server_port;
u32 client_port;
char client_ip[16];
int send_flag;
int recv_flag;
long rx_cnt;
long tx_cnt;
volatile int tcp_ps;
volatile int tcp_ps_cnt;
}ua_tcp_socket_t;
typedef struct _ua_gpio_t
{
gpio_t gpio_led;
gpio_t gpio_btn;
gpio_irq_t gpio_btn_irq;
gtimer_t gpio_timer;
}ua_gpio_t;
typedef struct _ua_socket_t
{
ua_uart_socket_t uart;
ua_tcp_socket_t tcp;
ua_gpio_t gpio;
ip_addr_t ip;
DNSServiceRef dnsServiceRef;
DNSServiceRef dnsServiceRef2;
}ua_socket_t;
typedef struct _ua_mbox_buffer
{
char data[UA_UART_FRAME_LEN];
int data_len;
}ua_mbox_buffer_t;
//Save Uart Settings when get uart information
typedef struct _ua_uart_get_str
{
int BaudRate; //The baud rate
char number; //The number of data bits
char parity; //The parity(0: none, 1:odd, 2:evn, default:0)
char StopBits; //The number of stop bits
char FlowControl; //support flow control is 1
}ua_uart_get_str;
//Uart Setting information
typedef struct _ua_uart_set_str
{
char UartName[8]; // the name of uart
int BaudRate; //The baud rate
char number; //The number of data bits
char parity; //The parity(default NONE)
char StopBits; //The number of stop bits
char FlowControl; //support flow control is 1
}ua_uart_set_str;
int uartadapter_init();
void uartadapter_tcp_send_data(ua_socket_t *ua_socket, char *buffer, int size);
void uartadapter_tcp_send_control(ua_socket_t *ua_socket, char *buffer, int size);
void uartadapter_tcp_transmit_server_thread(void *param);
void uartadapter_tcp_transmit_client_thread(void *param);
int uartadapter_tcpclient(ua_socket_t *ua_socket, const char *host_ip, unsigned short usPort);
void uartadapter_tcp_transmit_client_forever_thread(void *param);
void example_uart_adapter_init();
void cmd_uart_adapter(int argc, char **argv);
void uartadapter_tcp_transmit_socket_handler(ua_socket_t *ua_socket, char *tcp_rxbuf);

View File

@@ -0,0 +1,82 @@
#include "FreeRTOS.h"
#include "task.h"
#include "wifi_conf.h"
#include "wifi_ind.h"
#include "google/google_nest.h"
#include "flash_api.h"
#include "wigadget.h"
#include <lwip/netif.h>
#include "shtc1.h"
#define CLOUD_PORT 443
extern struct netif xnetif[NET_IF_NUM];
void cloud_link_task(void *param){
googlenest_context googlenest;
unsigned char URI[64];
unsigned char data[97] = {0};
unsigned char host_addr[64] = {0};
flash_t cloud_flash;
u8 *mac = (u8 *)LwIP_GetMAC(&xnetif[0]);
char i[16], j[16];
float temperature = 1.123f;
float humidity = 2.456f;
int ret = 0;
vTaskDelay(2000);
sprintf(URI, "ht_sensor/%02x%02x%02x%02x%02x%02x.json", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
memset(host_addr, 0, sizeof(host_addr));
if(flash_stream_read(&cloud_flash, FLASH_IOT_DATA, 97, (uint8_t *) data) == 1){
memset(host_addr, 0 , 64);
memcpy(host_addr, data+33, 64);
while(1) {
printf("\r\n\r\n\r\n\r\n\r\n\r\n=====>START CLOUD LINKING\r\n\r\n");
memset(i, 0, 16);
memset(j, 0, 16);
#if PSEUDO_DATA
sprintf(i,"%.2f", temperature++);
sprintf(j, "%.2f", humidity++);
if(temperature > 60)
temperature = 1.123f;
if(humidity > 98)
humidity = 2.456f;
#else
ret = SHTC_GetTempAndHumi(&temperature, &humidity);
sprintf(i, "%.2f", temperature);
sprintf(j, "%.2f", humidity);
#endif
if(ret < 0)
printf("\r\n\r\n<-----LOCAL LINK FAILED!!(get infor failed)\r\n\r\n");
else{
gen_json_data(i, j, data);
printf("\r\nCLOUD-LINK--Sending data : \r\n%s\r\n", data);
memset(&googlenest, 0, sizeof(googlenest_context));
if(gn_connect(&googlenest, host_addr, CLOUD_PORT) == 0) {
if(gn_put(&googlenest, URI, data) != 0)
printf("\r\n\r\nPUT data failed!\r\n\r\n");
gn_close(&googlenest);
printf("\r\n\r\n<=====CLOUD LINK OK!!\r\n\r\n");
}
else{
printf("\r\n\r\n<=====CLOUD LINK FAILED!!(google nest connecting)\r\n\r\n");
}
free(data);
vTaskDelay(10000);
}
}
}
else
printf("\r\n\r\n<=====CLOUD LINK FAILED!!(flash reading)\r\n\r\n");
}
void start_cloud_link(void)
{
if(xTaskCreate(cloud_link_task, ((const char*)"cloud_link_task"), 3584, NULL, tskIDLE_PRIORITY + 4, NULL) != pdPASS)
printf("\n\r%s xTaskCreate failed", __FUNCTION__);
}

View File

@@ -0,0 +1,11 @@
#ifndef CLOUD_LINK_H
#define CLOUD_LINK_THREAD_H
#include "wigadget.h"
void start_cloud_link(void);
void cloud_link_task(void *param);
#endif

View File

@@ -0,0 +1,25 @@
#ifndef _WI_ENCRYPT_H_
#define _WI_ENCRYPT_H_
#include "rom_aes.h"
typedef union
{ unsigned int l;
unsigned char b[4];
} aes_inf;
typedef struct
{
aes_context ctx;
aes_inf inf;
} aes_encrypt_ctx;
typedef struct
{
aes_context ctx;
aes_inf inf;
} aes_decrypt_ctx;
#endif

View File

@@ -0,0 +1,195 @@
#include "FreeRTOS.h"
#include "task.h"
#include "device.h"
#include "PinNames.h"
#include "basic_types.h"
#include "diag.h"
#include "osdep_service.h"
#include "i2c_api.h"
#include "pinmap.h"
#include "shtc1.h"
#ifdef CONFIG_PLATFORM_8195A
#define MBED_I2C_MTR_SDA PB_3
#define MBED_I2C_MTR_SCL PB_2
#endif
#ifdef CONFIG_PLATFORM_8711B
#define MBED_I2C_MTR_SDA PA_19
#define MBED_I2C_MTR_SCL PA_22
#endif
#define MBED_I2C_SLAVE_ADDR0 0x70
#define POLYNOMIAL 0x131 // P(x) = x^8 + x^5 + x^4 + 1 = 100110001
#define MBED_I2C_BUS_CLK 100000 //hz
#define I2C_DATA_MAX_LENGTH 16
static uint8_t i2cdata_write[I2C_DATA_MAX_LENGTH];
static uint8_t i2cdata_read[I2C_DATA_MAX_LENGTH];
static int i2cdata_read_pos;
static i2c_t i2cmaster;
// Sensor Commands
#define READ_ID 0xEFC8 // command: read ID register
#define SOFT_RESET 0x805D // soft resetSample Code for SHTC1
#define MEAS_T_RH_POLLING 0x7866 // meas. read T first, clock stretching disabled
#define MEAS_T_RH_CLOCKSTR 0x7CA2 // meas. read T first, clock stretching enabled
#define MEAS_RH_T_POLLING 0x58E0 // meas. read RH first, clock stretching disabled
#define MEAS_RH_T_CLOCKSTR 0x5C24 // meas. read RH first, clock stretching enabled
static int SHTC1_GetID(uint16_t *id);
static void SHTC1_WriteCommand(uint16_t cmd);
static int SHTC1_Read2BytesAndCrc(uint16_t *data);
static int SHTC1_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum);
static float SHTC1_CalcTemperature(uint16_t rawValue);
static float SHTC1_CalcHumidity(uint16_t rawValue);
int SHTC_Init(uint16_t *pID)
{
int error = NO_ERROR;
DiagPrintf("SHTC1_Init \r\n");
i2c_init((i2c_t*)&i2cmaster, MBED_I2C_MTR_SDA ,MBED_I2C_MTR_SCL);
i2c_frequency((i2c_t*)&i2cmaster,MBED_I2C_BUS_CLK);
if (pID == NULL )
return NULL_ERROR;
error = SHTC1_GetID(pID);
return error;
}
static int SHTC1_GetID(uint16_t *id)
{
int error = NO_ERROR;
uint8_t bytes[2];
uint8_t checksum;
SHTC1_WriteCommand(READ_ID);
i2c_read((i2c_t*)&i2cmaster, MBED_I2C_SLAVE_ADDR0, (char*)&i2cdata_read[0], 3, 1);
i2cdata_read_pos = 0;
error = SHTC1_Read2BytesAndCrc(id);
return error;
}
static int SHTC1_Read2BytesAndCrc(uint16_t *data)
{
int error;
int readed;
uint8_t bytes[2];
uint8_t checksum;
bytes[0] = i2cdata_read[i2cdata_read_pos++];
bytes[1] = i2cdata_read[i2cdata_read_pos++];
checksum = i2cdata_read[i2cdata_read_pos++];
error = SHTC1_CheckCrc(bytes, 2, checksum);
*data = (bytes[0] << 8) | bytes[1];
return error;
}
static int SHTC1_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)
{
uint8_t bit; // bit mask
uint8_t crc = 0xFF; // calculated checksum
uint8_t byteCtr; // byte counter
for(byteCtr = 0; byteCtr < nbrOfBytes; byteCtr++){
crc ^= (data[byteCtr]);
for(bit = 8; bit > 0; --bit){
if(crc & 0x80)
crc = (crc << 1) ^ POLYNOMIAL;
else
crc = (crc << 1);
}
}
if(crc != checksum)
return CHECKSUM_ERROR;
else
return NO_ERROR;
}
static void SHTC1_WriteCommand(uint16_t cmd)
{
int writebytes;
i2cdata_write[0] = (uint8_t)(cmd >>8);
i2cdata_write[1] = (uint8_t)(cmd&0xFF);
i2c_write((i2c_t*)&i2cmaster, MBED_I2C_SLAVE_ADDR0, &i2cdata_write[0], 2, 1);
}
static float SHTC1_CalcTemperature(uint16_t rawValue)
{
return 175.0 * (float)rawValue / 65536.0 - 45.0;
}
static float SHTC1_CalcHumidity(uint16_t rawValue)
{
return 100.0 * (float)rawValue / 65536.0;
}
int SHTC_GetTempAndHumi(float *temp, float *humi)
{
int error;
uint16_t rawValueTemp;
uint16_t rawValueHumi;
SHTC1_WriteCommand(MEAS_T_RH_CLOCKSTR);
i2c_read((i2c_t*)&i2cmaster, MBED_I2C_SLAVE_ADDR0, (char*)&i2cdata_read[0], 6, 1);
i2cdata_read_pos = 0;
error = NO_ERROR;
error |= SHTC1_Read2BytesAndCrc(&rawValueTemp);
error |= SHTC1_Read2BytesAndCrc(&rawValueHumi);
if ( error == NO_ERROR ) {
*temp = SHTC1_CalcTemperature(rawValueTemp);
*humi = SHTC1_CalcHumidity(rawValueHumi);
}
return error;
}
static void example_shtc1_thread(void *param)
{
int error;
uint16_t shtc1_id;
float temperature = 1.123f;
float humidity = 2.456f;
DBG_8195A("sleep 10 sec. to wait for UART console\n");
rtw_msleep_os(10000);
DBG_8195A("start i2c example - SHTC1\n");
error = SHTC_Init(&shtc1_id);
if ( error == NO_ERROR )
DiagPrintf("SHTC1 init ok, id=0x%x\r\n", shtc1_id);
else {
DiagPrintf("SHTC1 init FAILED! \r\n");
for(;;);
}
while(1){
error = SHTC_GetTempAndHumi(&temperature, &humidity);
rtl_printf("temp=%f, humidity=%f, error=%d\n", temperature, humidity, error);
rtw_msleep_os(1000);
}
}
void example_shtc1(void)
{
if(xTaskCreate(example_shtc1_thread, ((const char*)"example_shtc1_thread"), 512, NULL, tskIDLE_PRIORITY + 1, NULL) != pdPASS)
printf("\n\r%s xTaskCreate(init_thread) failed", __FUNCTION__);
}

View File

@@ -0,0 +1,13 @@
#ifndef SHTC1_H
#define SHTC1_H
#define NO_ERROR 0x00
#define ACK_ERROR 0x01
#define CHECKSUM_ERROR 0x02
#define NULL_ERROR 0x03
int SHTC_GetTempAndHumi(float *temp, float *humi);
int SHTC_Init(uint16_t *pID);
void example_shtc1(void);
#endif

View File

@@ -0,0 +1,732 @@
#include "FreeRTOS.h"
#include "task.h"
#include "wifi_conf.h"
#include "wifi_ind.h"
#include "sockets.h"
#include <mDNS/mDNS.h>
#include <lwip_netconf.h>
#include <lwip/netif.h>
#include "flash_api.h"
#include "encrypt.h"
#include "gpio_api.h"
#include "gpio_irq_api.h"
#include "cJSON.h"
#include "cloud_link.h"
#include "wigadget.h"
#include "shtc1.h"
#define PORT 6866
#define MAX_BUFFER_SIZE 256
#define ENC_SIZE 64
#define CONTROL_TYPE 1
#ifdef CONFIG_PLATFORM_8195A
#define GPIO_SOFTAP_RESET_PIN PC_4
#endif
#ifdef CONFIG_PLATFORM_8711B
#define GPIO_SOFTAP_RESET_PIN PA_0
#endif
flash_t iot_flash;
uint8_t aes_key[16];
static unsigned char tx_buffer[MAX_BUFFER_SIZE];
static unsigned char rx_buffer[MAX_BUFFER_SIZE];
extern struct netif xnetif[NET_IF_NUM];
#define DEBUG_IOT 1
#define IOT_LOG(level, fmt, ...) printf("\n\r[IOT %s] %s: " fmt "\n", level, __FUNCTION__, ##__VA_ARGS__)
#if DEBUG_IOT == 2
#define IOT_DEBUG(fmt, ...) IOT_LOG("DEBUG", fmt, ##__VA_ARGS__)
#else
#define IOT_DEBUG(fmt, ...)
#endif
#if DEBUG_IOT
#define IOT_ERROR(fmt, ...) IOT_LOG("ERROR", fmt, ##__VA_ARGS__)
#else
#define IOT_ERROR(fmt, ...)
#endif
void encrypt_data_aes(unsigned char *plaint_text, unsigned char *enc_data);
void decrypt_data_aes(unsigned char *enc_data, unsigned char *dec_data, int data_len);
static unsigned int arc4random(void)
{
unsigned int res = xTaskGetTickCount();
static unsigned int seed = 0xDEADB00B;
seed = ((seed & 0x007F00FF) << 7) ^
((seed & 0x0F80FF00) >> 8) ^ // be sure to stir those low bits
(res << 13) ^ (res >> 9); // using the clock too!
return seed;
}
static char *iot_itoa(int value)
{
char *val_str;
int tmp = value, len = 1;
while((tmp /= 10) > 0)
len ++;
val_str = (char *) malloc(len + 1);
sprintf(val_str, "%d", value);
return val_str;
}
void gen_json_data(char *i, char *j, unsigned char *json_data)
{
cJSON_Hooks memoryHook;
memoryHook.malloc_fn = malloc;
memoryHook.free_fn = free;
cJSON_InitHooks(&memoryHook);
memset(json_data, 0, ENC_SIZE);
cJSON *IOTJSObject = NULL;
char *data;
if((IOTJSObject = cJSON_CreateObject()) != NULL) {
cJSON_AddItemToObject(IOTJSObject, "TEM", cJSON_CreateString(i));
cJSON_AddItemToObject(IOTJSObject, "HUM", cJSON_CreateString(j));
data = cJSON_Print(IOTJSObject);
memcpy(json_data, data, strlen(data));
cJSON_Delete(IOTJSObject);
free(data);
}
}
void encrypt_data_aes(unsigned char *plaint_text, unsigned char *enc_data)
{
unsigned char iv[16] = {0};
unsigned char* iv_bak = "AAAAAAAAAAAAAAAA";
aes_encrypt_ctx enc_ctx;
memset(&enc_ctx, 0, sizeof(enc_ctx));
memset(iv, 0, sizeof(iv));
memcpy(iv, iv_bak, sizeof(iv));
memset(enc_data, 0, sizeof(enc_data));
aes_init();
aes_encrypt_key(aes_key, 16, &enc_ctx);
aes_cbc_encrypt(plaint_text, enc_data, ENC_SIZE, iv, &enc_ctx);
}
void decrypt_data_aes(unsigned char *enc_data, unsigned char *dec_data, int data_len)
{
unsigned char iv[16] = {0};
unsigned char* iv_bak = "AAAAAAAAAAAAAAAA";
aes_decrypt_ctx dec_ctx;
memset(&dec_ctx, 0, sizeof(dec_ctx));
memset(iv, 0, sizeof(iv));
memcpy(iv, iv_bak, sizeof(iv));
memset(dec_data, 0, sizeof(dec_data));
aes_init();
aes_decrypt_key(aes_key, 16, &dec_ctx);
aes_cbc_decrypt(enc_data, dec_data, data_len, iv, &dec_ctx);
IOT_DEBUG("Decrypt data: %s\r\n",dec_data);
}
void iotapp_platform_reset(void)
{
HAL_WRITE32(SYSTEM_CTRL_BASE, 0x14, 0x00000021);
osDelay(100);
HAL_WRITE32(0xE000ED00, 0x0C, (0x5FA << 16) |
(HAL_READ32(0xE000ED00, 0x0C) & (7 << 8)) |
(1 << 2));
while(1) osDelay(1000);
}
void iotapp_reset_irq_handler(uint32_t id, gpio_irq_event event)
{
printf("\n\r\n\r\n\r\n\r<<<<<<Reset the device>>>>>>>\n\r\n\r\n\r\n\r");
flash_erase_sector(&iot_flash, FLASH_IOT_DATA);
iotapp_platform_reset();
}
int local_link(unsigned char *tx_data)
{
int sockfd, newsockfd;
socklen_t client;
struct sockaddr_in serv_addr, cli_addr;
uint8_t rx_data[ENC_SIZE];
unsigned char enc_data[ENC_SIZE];
unsigned char dec_data[ENC_SIZE];
int ret = 0, opt = 1, k = 1, j;
char *result = NULL, *backup = NULL;
unsigned char *data = NULL;
char *delims = ", ";
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
IOT_ERROR("ERROR opening socket");
ret = -1;
goto exit2;
}
if((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt))) < 0){
IOT_ERROR("ERROR on setting socket option");
ret = -1;
goto exit2;
}
memset((char *)&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
if (bind(sockfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
IOT_ERROR("ERROR on binding");
ret = -1;
goto exit2;
}
if(listen(sockfd , 20) < 0){
IOT_ERROR("ERROR on listening");
ret = -1;
goto exit2;
}
client = sizeof(cli_addr);
if((newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&client)) < 0){
IOT_ERROR("ERROR on accept");
ret = -1;
goto exit;
}
if ((ret = read(newsockfd,rx_buffer,sizeof(rx_buffer))) < 0){
IOT_ERROR("ERROR reading from socket");
ret = -1;
goto exit;
}
IOT_DEBUG("cmd received: %s, length: %d\r\n",rx_buffer, ret);
//Changing received data to string
if (!strncmp(rx_buffer, "[", strlen("["))){
data = rx_buffer + strlen("[");
for(j = 1; j < 5; j++){
if (data[ret - j] == ']')
data[ret -j] = '\0';
}
}
else
strcpy(data, rx_buffer);
memset(rx_data, 0, sizeof(rx_data));
result = strtok_r(data, delims, &backup);
rx_data[0]=(uint8_t)atoi(result);
while((result = strtok_r(NULL, delims, &backup)) != NULL)
rx_data[k++]=(uint8_t)atoi(result);
memset(dec_data, 0, sizeof(dec_data));
//Decrpyt the received data
decrypt_data_aes(rx_data, dec_data, 16);
if(strncmp(dec_data, "request", strlen("request")) == 0){
//Encrypt the sending data
memset(enc_data, 0, strlen(enc_data));
encrypt_data_aes(tx_data, enc_data);
//Changing encrpyt data to JAVA type string
for (j = 0; j < ENC_SIZE; j++){
char *temp;
temp = iot_itoa(enc_data[j]);
if(j == 0)
strcpy(tx_buffer, "[");
strcat(tx_buffer,temp);
if (j == (ENC_SIZE - 1))
strcat(tx_buffer,"]");
else
strcat(tx_buffer,",");
free(temp);
temp = NULL;
}
IOT_DEBUG("Data reply to APP: %s\r\nLength of data: %d\r\n", tx_buffer, strlen(tx_buffer));
if ((ret = write(newsockfd,tx_buffer,strlen(tx_buffer))) < 0){
IOT_ERROR("ERROR writing to socket");
ret = -1;
goto exit;
}
else
IOT_DEBUG("Sending %d bytes data OK!\r\n", ret);
}
else if(strncmp(dec_data, "remove", strlen("remove")) == 0){
printf("\n\r\n\r\n\r\n\r<<<<<<Reset the device >>>>>>>\n\r\n\r\n\r\n\r");
flash_erase_sector(&iot_flash, FLASH_IOT_DATA);
write(newsockfd,"Remove OK",strlen("Remove OK"));
close(newsockfd);
close(sockfd);
iotapp_platform_reset();
}
else{
IOT_ERROR("ERROR wrong KEY or wrong request!");
write(newsockfd,"The KEY or the request is not correct!",strlen("The KEY or the request is not correct!"));
ret = -1;
goto exit;
}
exit:
if(close(newsockfd) != 0)
goto exit;
exit2:
if(close(sockfd) != 0)
goto exit2;
return ret;
}
static void local_link_task(void *param)
{
unsigned char data[ENC_SIZE] = {0};
vTaskDelay(1000);
char i[16], j[16];
float temperature = 1.123f;
float humidity = 2.456f;
int ret = 0;
while(1){
memset(i, 0, 16);
memset(j, 0, 16);
#if PSEUDO_DATA
sprintf(i,"%.2f", temperature++);
sprintf(j, "%.2f", humidity++);
if(temperature > 60)
temperature = 1.123f;
if(humidity > 98)
humidity = 2.456f;
#else
ret = SHTC_GetTempAndHumi(&temperature, &humidity);
sprintf(i,"%.2f", temperature);
sprintf(j, "%.2f", humidity);
#endif
if(ret < 0)
printf("\r\n\r\n<-----LOCAL LINK FAILED!!(get infor failed)\r\n\r\n");
else{
printf("\r\n\r\n----->START LOCAL LINKING\r\n\r\n");
gen_json_data(i, j, data);
printf("Sending data : %s\r\n", data);
if (local_link(data) < 0)
printf("\r\n\r\n<-----LOCAL LINK FAILED!!\r\n\r\n");
else
printf("\r\n\r\n<-----LOCAL LINK OK!!\r\n\r\n");
vTaskDelay(1000);
}
}
}
void start_local_link(void)
{
if(xTaskCreate(local_link_task, ((const char*)"local_link_task"), 5376, NULL, tskIDLE_PRIORITY + 4, NULL) != pdPASS)
printf("\n\r%s xTaskCreate failed", __FUNCTION__);
}
int pair_device(unsigned char *tx_buffer, unsigned char *rx_buffer, int handshake)
{
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int ret = 0;
int opt = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
IOT_ERROR("ERROR opening socket");
ret = -1;
goto exit;
}
if((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt))) < 0){
IOT_ERROR("ERROR on setting socket option");
ret = -1;
goto exit;
}
memset((char *)&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_len = sizeof(serv_addr);
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
if ((bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) < 0) {
IOT_ERROR("ERROR on binding");
ret = -1;
goto exit;
}
if ((listen(sockfd, 5)) < 0){
IOT_ERROR("ERROR on listening tcp server socket fd");
ret = -1;
goto exit;
}
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t*)&clilen);
if (newsockfd < 0) {
IOT_ERROR("ERROR on accept");
ret = -1;
goto exit2;
}
ret = read(newsockfd, rx_buffer, MAX_BUFFER_SIZE);
if (ret <= 0){
IOT_ERROR("ERROR reading from socket");
ret = -1;
goto exit2;
}
IOT_DEBUG("Request received: %s, byte: %d\r\n",rx_buffer, ret);
if(handshake == 1){
if(strncmp(rx_buffer,"PAIR", strlen("PAIR")) != 0){
write(newsockfd, "ERROR", strlen("ERROR"));
IOT_ERROR("ERROR on first handshake!");
ret = -1;
goto exit2;
}
}
else if(handshake == 2){
if((rx_buffer == NULL) ||(strlen(rx_buffer) < 32)){
write(newsockfd, "ERROR", strlen("ERROR"));
IOT_ERROR("ERROR on second handshake!");
ret = -1;
goto exit2;
}
}
else if(handshake == 3){
unsigned char account[64];
unsigned char enc_acc[64];
char *result = NULL, *backup = NULL;
unsigned char *data = NULL;
char *delims = ", ";
int j, k = 1;
if (!strncmp(rx_buffer, "[", strlen("["))){
data = rx_buffer + strlen("[");
for(j = 1; j < 5; j++){
if (data[ret - j] == ']')
data[ret -j] = '\0';
}
}
else
strcpy(data, rx_buffer);
memset(enc_acc, 0, sizeof(enc_acc));
result = strtok_r(data, delims, &backup);
enc_acc[0]=(uint8_t)atoi(result);
while((result = strtok_r(NULL, delims, &backup)) != NULL)
enc_acc[k++]=(uint8_t)atoi(result);
IOT_DEBUG("The value of k: %d", k);
memset(account, 0, sizeof(account));
decrypt_data_aes(enc_acc, account, k);
if((strncmp(account,"https://", strlen("https://"))) != 0){
write(newsockfd, "ERROR", strlen("ERROR"));
IOT_ERROR("ERROR on third handshake!");
ret = -1;
goto exit2;
}
else{
IOT_DEBUG("The received Firebase URL:%s", account);
memset(rx_buffer, 0, strlen(rx_buffer));
memcpy(rx_buffer, (account+strlen("https://")), (strlen(account) + strlen("https://")));
}
}
ret = write(newsockfd, tx_buffer, strlen(tx_buffer));
IOT_DEBUG("Data send: %s\r\n",tx_buffer);
if (ret < 0){
IOT_ERROR("ERROR writing to socket");
}
exit:
if(close(newsockfd) != 0)
goto exit;
exit2:
if(close(sockfd) != 0)
goto exit2;
return ret;
}
static void pair_device_task(void)
{
int i, j, k, HANDSHAKE;
uint8_t PAIR_STATE[1] = {0};
if(CONTROL_TYPE == 1){
printf("\r\n\r\n<<<<<<CONTROL_TYPE = 1 Need 3 times handshake>>>>>>\r\n\r\n");
HANDSHAKE = 3;
}
else{
printf("\r\n\r\n<<<<<<CONTROL_TYPE = 0 Need 2 times handshake>>>>>>\r\n\r\n");
HANDSHAKE = 2;
}
printf("\r\n\r\n=========>PAIR_STATE = 0 Start to pair\r\n\r\n");
for(i = 0; i < HANDSHAKE; i++){
static const uint8_t basepoint[32] = {9};
uint8_t mysecret[32];
uint8_t mypublic[32];
uint8_t theirpublic[32] = {0};
uint8_t shared_key[32];
//First handshake
if(i == 0){
printf("\r\n\r\n===>Start the first handshake\r\n\r\n");
memset(tx_buffer, 0, sizeof(tx_buffer));
memset(rx_buffer, 0, sizeof(rx_buffer));
for(j = 0; j < 32; j ++)
mysecret[j] = (uint8_t) arc4random();
mysecret[j] = '\0';
curve25519_donna(mypublic, mysecret, basepoint);
for (j = 0; j < 32; j++){
char *temp;
temp = iot_itoa(mypublic[j]);
if(j == 0)
strcpy(tx_buffer, "[");
strcat(tx_buffer,temp);
if (j == 31)
strcat(tx_buffer,"]");
else
strcat(tx_buffer,",");
free(temp);
temp = NULL;
}
if(pair_device(tx_buffer, rx_buffer, 1) >= 0)
printf("\r\n\r\n<===First handshake OK!!\r\n\r\n");
else{
i--;
printf("\r\n\r\n<===First handshake FAILED!!\r\n\r\n");
}
}
//Second handshake
if(i == 1){
printf("\r\n\r\n=====>Start the second handshake\r\n\r\n");
vTaskDelay(200);
memset(tx_buffer, 0, sizeof(tx_buffer));
if(CONTROL_TYPE == 1)
memcpy(tx_buffer, "FIREBASE URL", sizeof("FIREBASE URL"));
else
memcpy(tx_buffer, "PAIR OK", sizeof("PAIR OK"));
memset(rx_buffer, 0, sizeof(rx_buffer));
if(pair_device(tx_buffer, rx_buffer, 2) >= 0){
char *result = NULL, *backup = NULL;
unsigned char *data = NULL;
char *delims = ", ";
k = 1;
if (!strncmp(rx_buffer, "[", strlen("["))){
data = rx_buffer + strlen("[");
int len;
len = strlen(data);
for(j = 1; j < 5; j++){
if (data[len - j] == ']')
data[len -j] = '\0';
}
}
else
strcpy(data, rx_buffer);
memset(theirpublic, 0, sizeof(theirpublic));
result = strtok_r(data, delims, &backup);
theirpublic[0]=(uint8_t)atoi(result);
while((result = strtok_r(NULL, delims, &backup)) != NULL)
theirpublic[k++] = (uint8_t)atoi(result);
curve25519_donna(shared_key, mysecret, theirpublic);
for(j = 0; j < 16; j ++)
aes_key[j] = shared_key[j];
//Store the KEY in FLASH
if(CONTROL_TYPE == 0){
PAIR_STATE[0] = 1;
uint8_t data[33];
memset(data, 0, 33);
memcpy(data, PAIR_STATE, 1);
memcpy(data+1, shared_key, 32);
flash_erase_sector(&iot_flash, FLASH_IOT_DATA);
flash_stream_write(&iot_flash, FLASH_IOT_DATA, 33, (uint8_t *) data);
IOT_DEBUG("PAIR_STATE: %d\r\n", PAIR_STATE[0]);
}
printf("\r\n\r\n<=====Second handshake OK!!\r\n\r\n");
}
else{
i = i - 2;
printf("\r\n\r\n<=====Second handshake FAILED!!\r\n\r\n");
}
}
//Third handshake
if(i == 2){
printf("\r\n\r\n=======>Start the third handshake\r\n\r\n");
vTaskDelay(200);
memset(tx_buffer, 0, sizeof(tx_buffer));
memcpy(tx_buffer, "PAIR OK", sizeof("PAIR OK"));
memset(rx_buffer, 0, sizeof(rx_buffer));
if(pair_device(tx_buffer, rx_buffer, 3) >= 0){
IOT_DEBUG("rx_buffer: %s, sizeof rx_buffer:%d\r\n", rx_buffer, sizeof(rx_buffer));
PAIR_STATE[0] = 1;
uint8_t data[97];
memset(data, 0, 97);
memcpy(data, PAIR_STATE, 1);
memcpy(data+1, shared_key, 32);
memcpy(data+33, rx_buffer, 64);
flash_erase_sector(&iot_flash, FLASH_IOT_DATA);
flash_stream_write(&iot_flash, FLASH_IOT_DATA, 97, (uint8_t *) data);
IOT_DEBUG("PAIR_STATE: %d\r\n", PAIR_STATE[0]);
printf("\r\n\r\n<=======Third handshake OK!!\r\n\r\n");
}
else{
i = i - 3;
printf("\r\n\r\n<=======Third handshake FAILED!!\r\n\r\n");
}
}
}
printf("\r\n\r\n<=========Pairing OK!!\r\n\r\n");
}
static void mdns_task(void *param)
{
DNSServiceRef dnsServiceRef = NULL;
TXTRecordRef txtRecord;
unsigned char txt_buf[128];
uint8_t *mac, *ip;
int j, ret = 0;
uint8_t *flash_data;
uint8_t PAIR_STATE[1] = {0};
static unsigned char MAC_ADD[21];
static unsigned char IP[16];
static unsigned char port[6];
uint16_t shtc1_id;
// Delay to wait for IP by DHCP and get the information of IP and MAC
printf("\n\r\n\r\n\r\n\r<<<<<<Waiting for 20 seconds to connect Wi-Fi>>>>>>>\n\r\n\r\n\r\n\r");
vTaskDelay(20000);
ip = LwIP_GetIP(&xnetif[0]);
mac = LwIP_GetMAC(&xnetif[0]);
sprintf(MAC_ADD, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
sprintf(IP, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
sprintf(port, "%d", PORT);
IOT_DEBUG("MAC => %s\r\n", MAC_ADD) ;
IOT_DEBUG("IP => %s\r\n", IP);
IOT_DEBUG("PORT => %s\r\n", port);
//Get the value of PAIR_STATE and the AES key in flash
flash_data = (uint8_t *)malloc(33);
flash_stream_read(&iot_flash, FLASH_IOT_DATA, 33, (uint8_t *)flash_data);
memcpy(PAIR_STATE, flash_data, 1);
if(PAIR_STATE[0] != 0x1)
PAIR_STATE[0] = 0;
else{
for(j = 0;j < 16; j++){
aes_key[j] = flash_data[j+1];
}
}
free(flash_data);
IOT_DEBUG("PAIR_STATE now: %d\r\n", PAIR_STATE[0]);
IOT_DEBUG("=>mDNS Init\r\n");
if(mDNSResponderInit() == 0) {
printf("\r\n\r\n========>Start to register mDNS service\r\n\r\n");
//The device not paired before
if(PAIR_STATE[0] == 0){
TXTRecordCreate(&txtRecord, sizeof(txt_buf), txt_buf);
TXTRecordSetValue(&txtRecord, "IP", strlen(IP), IP);
TXTRecordSetValue(&txtRecord, "PORT", strlen(port), port);
TXTRecordSetValue(&txtRecord, "MAC_ADDR", strlen(MAC_ADD), MAC_ADD);
TXTRecordSetValue(&txtRecord, "PAIR_STATE", strlen("0"), "0");
TXTRecordSetValue(&txtRecord, "SERVICE_NAME", strlen("ht_sensor"), "ht_sensor");
if(CONTROL_TYPE == 1)
TXTRecordSetValue(&txtRecord, "CONTROL_TYPE", strlen("1"), "1");
else
TXTRecordSetValue(&txtRecord, "CONTROL_TYPE", strlen("0"), "0");
dnsServiceRef = mDNSRegisterService("ht_sensor", "_Ameba._tcp", "local", PORT, &txtRecord);
TXTRecordDeallocate(&txtRecord);
printf("\r\n\r\n<========Registering mDNS service OK!!\r\n\r\n");
pair_device_task();
}
//The device was paired
else if(PAIR_STATE[0] == 0x1){
TXTRecordCreate(&txtRecord, sizeof(txt_buf), txt_buf);
TXTRecordSetValue(&txtRecord, "IP", strlen(ip), ip);
TXTRecordSetValue(&txtRecord, "PORT", strlen(port), port);
TXTRecordSetValue(&txtRecord, "MAC_ADDR", strlen(MAC_ADD), MAC_ADD);
TXTRecordSetValue(&txtRecord, "PAIR_STATE", strlen("1"), "1");
TXTRecordSetValue(&txtRecord, "SERVICE_NAME", strlen("ht_sensor"), "ht_sensor");
if(CONTROL_TYPE == 1)
TXTRecordSetValue(&txtRecord, "CONTROL_TYPE", strlen("1"), "1");
else
TXTRecordSetValue(&txtRecord, "CONTROL_TYPE", strlen("0"), "0");
dnsServiceRef = mDNSRegisterService("ht_sensor", "_Ameba._tcp", "local", PORT, &txtRecord);
TXTRecordDeallocate(&txtRecord);
printf("\r\n\r\n<========Registering mDNS service OK!! PAIR_STATE = 1\r\n\r\n");
}
#if PSEUDO_DATA
printf("\r\n\r\n========>Using the speudo data\r\n\r\n");
if(CONTROL_TYPE == 1) start_cloud_link();
start_local_link();
#else
//Init the shtc1 sensor
printf("\r\n\r\n========>Init the temperature and humidity sensor\r\n\r\n");
ret = SHTC_Init(&shtc1_id);
if ( ret == NO_ERROR ){
printf("\r\n\r\n<========Senser init OK! ID = 0x%x \r\n\r\n", shtc1_id);
if(CONTROL_TYPE == 1) start_cloud_link();
start_local_link();
}
else {
printf("\r\n\r\n<========Senser init FAILED! ID = 0x%x \r\n\r\n", shtc1_id);
ret = -1;
}
#endif
}
else
ret = -1;
if(ret == 0){
while(1){
IOT_DEBUG("Update the mDNS textrecord!\r\n");
TXTRecordCreate(&txtRecord, sizeof(txt_buf), txt_buf);
TXTRecordSetValue(&txtRecord, "IP", strlen(IP), IP);
TXTRecordSetValue(&txtRecord, "PORT", strlen(port), port);
TXTRecordSetValue(&txtRecord, "MAC_ADDR", strlen(MAC_ADD), MAC_ADD);
TXTRecordSetValue(&txtRecord, "PAIR_STATE", strlen("1"), "1");
if(CONTROL_TYPE == 1)
TXTRecordSetValue(&txtRecord, "CONTROL_TYPE", strlen("1"), "1");
else
TXTRecordSetValue(&txtRecord, "CONTROL_TYPE", strlen("0"), "0");
TXTRecordSetValue(&txtRecord, "SERVICE_NAME", strlen("ht_sensor"), "ht_sensor");
mDNSUpdateService(dnsServiceRef, &txtRecord, 0);
TXTRecordDeallocate(&txtRecord);
vTaskDelay(2*60*1000);
}
}
else{
if(dnsServiceRef)
mDNSDeregisterService(dnsServiceRef);
IOT_DEBUG("<=mDNS Deinit\r\n\r\n");
mDNSResponderDeinit();
}
}
void example_wigadget(void)
{
if(xTaskCreate(mdns_task, ((const char*)"mdns_task"), 3072, NULL, tskIDLE_PRIORITY + 1, NULL) != pdPASS)
printf("\n\r%s xTaskCreate failed", __FUNCTION__);
gpio_t gpio_softap_reset_button;
gpio_irq_t gpioirq_softap_reset_button;
gpio_irq_init(&gpioirq_softap_reset_button, GPIO_SOFTAP_RESET_PIN, iotapp_reset_irq_handler, (uint32_t)(&gpio_softap_reset_button));
gpio_irq_set(&gpioirq_softap_reset_button, IRQ_FALL, 1);
gpio_irq_enable(&gpioirq_softap_reset_button);
}

View File

@@ -0,0 +1,11 @@
#ifndef WIGADGET_H
#define WIGADGET_H
#define FLASH_IOT_DATA (0x0007E000)
#define PSEUDO_DATA 1
void example_wigadget(void);
void gen_json_data(char *i, char *j, unsigned char *json_data);
#endif /* WIGADGET_H */

View File

@@ -0,0 +1,728 @@
/********************************************************************************
* Copyright (c) 2014, Realtek Semiconductor Corp.
* All rights reserved.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*******************************************************************************
*/
#if !defined(CONFIG_PLATFORM_8711B)
#include "xmport_uart.h"
#include "xmport_loguart.h"
#include "rtl8195a.h"
#include "xmodem.h"
#include "hal_spi_flash.h"
#include "rtl8195a_spi_flash.h"
#include <platform/platform_stdlib.h>
enum {
XMODEM_UART_0 = 0,
XMODEM_UART_1 = 1,
XMODEM_UART_2 = 2,
XMODEM_LOG_UART = 3
};
FWU_DATA_SECTION char xMFrameBuf[XM_BUFFER_SIZE];
FWU_DATA_SECTION XMODEM_CTRL xMCtrl;
FWU_DATA_SECTION static u32 fw_img1_size;
FWU_DATA_SECTION static u32 fw_img2_size;
FWU_DATA_SECTION static u32 fw_img2_addr;
FWU_DATA_SECTION static u32 fw_img3_size;
FWU_DATA_SECTION static u32 fw_img3_addr;
FWU_DATA_SECTION static u32 flash_wr_offset;
FWU_DATA_SECTION static u32 flash_erased_addr;
FWU_DATA_SECTION static u8 start_with_img1;
FWU_DATA_SECTION static u32 flash_wr_err_cnt;
FWU_DATA_SECTION HAL_RUART_ADAPTER xmodem_uart_adp; // we can dynamic allocate memory for this object to save memory
static union { uint32_t u; unsigned char c[4]; } file_checksum;
static u32 updated_img2_size = 0;
static u32 default_img2_addr = 0;
FWU_RODATA_SECTION const char Img2Signature[8]="81958711";
extern u32 SpicCalibrationPattern[4];
extern const u8 ROM_IMG1_VALID_PATTEN[];
extern HAL_RUART_ADAPTER *pxmodem_uart_adp;
#ifdef CONFIG_GPIO_EN
extern HAL_GPIO_ADAPTER gBoot_Gpio_Adapter;
extern PHAL_GPIO_ADAPTER _pHAL_Gpio_Adapter;
#endif
void xDelayUs(u32 us)
{
HalDelayUs(us);
}
extern BOOLEAN SpicFlashInitRtl8195A(u8 SpicBitMode);
_LONG_CALL_
extern VOID SpicWaitBusyDoneRtl8195A(VOID);
extern VOID SpicWaitWipDoneRefinedRtl8195A(SPIC_INIT_PARA SpicInitPara);
FWU_TEXT_SECTION void FWU_WriteWord(u32 Addr, u32 FData)
{
SPIC_INIT_PARA SpicInitPara = {0};
HAL_WRITE32(SPI_FLASH_BASE, Addr, FData);
// Wait spic busy done
SpicWaitBusyDoneRtl8195A();
// Wait flash busy done (wip=0)
SpicWaitWipDoneRefinedRtl8195A(SpicInitPara);
}
FWU_TEXT_SECTION u32 xModem_MemCmp(const u32 *av, const u32 *bv, u32 len)
{
const u32 *a = av;
const u32 *b = (u32*)((u8*)bv+SPI_FLASH_BASE);
u32 len4b = len >> 2;
u32 i;
for (i=0; i<len4b; i++) {
if (a[i] != b[i]) {
DBG_MISC_ERR("OTU: Flash write check error @ 0x%08x\r\n", (u32)(&b[i]));
return ((u32)(&b[i]));
}
}
return 0;
}
FWU_TEXT_SECTION
u32 xModem_Frame_Img2(char *ptr, uint32_t frame_num, uint32_t frame_size)
{
u32 address;
u32 ImageIndex=0;
u32 rx_len=0;
u32 *chk_sr;
u32 *chk_dr;
u32 err_addr;
if (frame_num == 1) {
// Parse Image2 header
memset(&file_checksum, 0, sizeof(file_checksum));
flash_wr_offset = fw_img2_addr;
fw_img2_size = rtk_le32_to_cpu(*((u32*)ptr)) + 0x14;
if ((fw_img2_size & 0x03) != 0) {
DBG_MISC_ERR("xModem_Frame_ImgAll Err#2: fw_img2_addr=0x%x fw_img2_size(%d) isn't 4-bytes aligned\r\n", fw_img2_addr, fw_img2_size);
fw_img1_size = 0;
fw_img2_size = 0;
return rx_len;
}
if (fw_img2_size > (2*1024*1024)) {
DBG_MISC_ERR("xModem_Frame_ImgAll Image2 to Big: fw_img2_addr=0x%x fw_img2_size(%d) \r\n", fw_img2_addr, fw_img2_size);
fw_img1_size = 0;
fw_img2_size = 0;
return rx_len;
}
fw_img3_addr = fw_img2_addr + fw_img2_size;
updated_img2_size = fw_img2_size;
// erase Flash first
address = fw_img2_addr & (~0xfff); // 4k aligned, 4k is the page size of flash memory
while ((address) < (fw_img2_addr+fw_img2_size)) {
SpicSectorEraseFlashRtl8195A(SPI_FLASH_BASE + address);
address += 0x1000;
}
flash_erased_addr = address;
}
if (fw_img2_size > 0) {
// writing image2
chk_sr = (u32*)((u8*)ptr+ImageIndex);
chk_dr = (u32*)flash_wr_offset;
while (ImageIndex < frame_size) {
FWU_WriteWord(flash_wr_offset, (*((u32*)(ptr+ImageIndex))));
ImageIndex += 4;
flash_wr_offset += 4;
rx_len += 4;
fw_img2_size -= 4;
if (fw_img2_size == 0) {
// Image2 write done,
break;
}
}
err_addr = xModem_MemCmp(chk_sr, chk_dr, (flash_wr_offset - (u32)chk_dr));
if (err_addr) {
flash_wr_err_cnt++;
}
}
// checksum attached at file end
file_checksum.c[0] = ptr[rx_len - 4];
file_checksum.c[1] = ptr[rx_len - 3];
file_checksum.c[2] = ptr[rx_len - 2];
file_checksum.c[3] = ptr[rx_len - 1];
return rx_len;
}
FWU_TEXT_SECTION
s32
xModem_Init_UART_Port(u8 uart_idx, u8 pin_mux, u32 baud_rate)
{
if (uart_idx <= XMODEM_UART_2) {
// update firmware via generic UART
pxmodem_uart_adp = &xmodem_uart_adp; // we can use dynamic allocate to save memory
xmodem_uart_init(uart_idx, pin_mux, baud_rate);
xmodem_uart_func_hook(&(xMCtrl.ComPort));
} else if(uart_idx == XMODEM_LOG_UART) {
// update firmware via Log UART
xmodem_loguart_init(baud_rate);
xmodem_loguart_func_hook(&(xMCtrl.ComPort));
} else {
// invalid UART port
DBG_MISC_ERR("xModem_Init_UART_Port: Invaild UART port(%d)\n", uart_idx);
return -1;
}
return 0;
}
FWU_TEXT_SECTION
VOID
xModem_DeInit_UART_Port(u8 uart_idx)
{
if (uart_idx <= XMODEM_UART_2) {
xmodem_uart_deinit();
} else if (uart_idx == XMODEM_LOG_UART) {
xmodem_loguart_deinit();
}
}
FWU_TEXT_SECTION
__weak s32
UpdatedImg2AddrValidate(
u32 Image2Addr,
u32 DefImage2Addr,
u32 DefImage2Size
)
{
if (Image2Addr == 0xffffffff) {
// Upgraded Image2 isn't exist
return 0; // invalid address
}
if ((Image2Addr & 0xfff) != 0) {
// Not 4K aligned
return 0; // invalid address
}
if (Image2Addr <= DefImage2Addr) {
// Updated image2 address must bigger than the addrss of default image2
return 0; // invalid address
}
if (Image2Addr < (DefImage2Addr+DefImage2Size)) {
// Updated image2 overlap with the default image2
return 0; // invalid address
}
return 1; // this address is valid
}
FWU_TEXT_SECTION
VOID
WriteImg2Sign(
u32 Image2Addr
)
{
u32 img2_sig[2];
_memcpy((void*)img2_sig, (void*)Img2Signature, 8);
FWU_WriteWord((Image2Addr + 8), img2_sig[0]);
FWU_WriteWord((Image2Addr + 12), img2_sig[1]);
// set the default imag2's signature to old
if(default_img2_addr != Image2Addr)
{
printf("set the signature of default img2 to old\n");
FWU_WriteWord((default_img2_addr + 8), 0x35393130);
FWU_WriteWord((default_img2_addr + 12), 0x31313738);
}
}
static void xmodem_write_ota_addr_to_system_data(u32 newImg2Addr)
{
FWU_WriteWord(FLASH_SYSTEM_DATA_ADDR, newImg2Addr);
return;
}
FWU_TEXT_SECTION
u32
SelectImg2ToUpdate(
u32 *OldImg2Addr
)
{
u32 DefImage2Addr=0xFFFFFFFF; // the default Image2 addr.
u32 SecImage2Addr=0xFFFFFFFF; // the 2nd image2 addr.
u32 ATSCAddr=0xFFFFFFFF;
u32 UpdImage2Addr; // the addr of the image2 to be updated
u32 DefImage2Len;
*OldImg2Addr = 0;
DefImage2Addr = (HAL_READ32(SPI_FLASH_BASE, 0x18)&0xFFFF) * 1024;
if ((DefImage2Addr != 0) && ((DefImage2Addr < (16*1024*1024)))) {
// Valid Default Image2 Addr: != 0 & located in 16M
DefImage2Len = HAL_READ32(SPI_FLASH_BASE, DefImage2Addr);
default_img2_addr = DefImage2Addr;
// Get the pointer of the upgraded Image2
SecImage2Addr = HAL_READ32(SPI_FLASH_BASE, FLASH_SYSTEM_DATA_ADDR);
if (UpdatedImg2AddrValidate(SecImage2Addr, DefImage2Addr, DefImage2Len)) {
UpdImage2Addr = SecImage2Addr; // Update the 2nd image2
} else {
// The upgraded image2 isn't exist or invalid so we can just update the default image2
//UpdImage2Addr = DefImage2Addr; // Update the default image2
UpdImage2Addr = 0x80000; // Update to a predefined address
}
} else {
UpdImage2Addr = 0;
}
xmodem_write_ota_addr_to_system_data(UpdImage2Addr);
return UpdImage2Addr;
}
static uint32_t xmodem_get_flash_checksum()
{
uint32_t flash_checksum = 0;
if(updated_img2_size == 0)
{
printf("img2 size is wrong\n");
return 0;
}
for(int i = 0; i < updated_img2_size - 4; i++)
flash_checksum += HAL_READ8(SPI_FLASH_BASE, fw_img2_addr + i);
return flash_checksum;
}
FWU_TEXT_SECTION
void OTU_FW_Update(u8 uart_idx, u8 pin_mux, u32 baud_rate)
{
u32 wr_len;
u32 OldImage2Addr=0; // the addr of the image2 will become old one
SPIC_INIT_PARA SpicInitPara = {0};
fw_img1_size = 0;
fw_img2_size = 0;
fw_img2_addr = 0;
fw_img3_size = 0;
fw_img3_addr = 0;
flash_wr_offset = 0;
flash_erased_addr = 0;
start_with_img1 = 0;;
flash_wr_err_cnt = 0;
u32 flash_checksum = 0;
// Get the address of the image2 to be updated
SPI_FLASH_PIN_FCTRL(ON);
if (!SpicFlashInitRtl8195A(SpicOneBitMode)){
SPI_FLASH_PIN_FCTRL(OFF);
DBG_MISC_ERR("OTU_FW_Update: SPI Init Fail!!!!!!\n");
return;
}
SpicWaitWipDoneRefinedRtl8195A(SpicInitPara);
printf("FW Update Over UART%d, PinMux=%d, Baud=%d\r\n", uart_idx, pin_mux, baud_rate);
fw_img2_addr = SelectImg2ToUpdate(&OldImage2Addr);
// Start to update the Image2 through xModem on peripheral device
printf("FW Update Image2 @ 0x%x\r\n", fw_img2_addr);
// We update the image via xModem on UART now, if we want to uase other peripheral device
// to update the image then we need to redefine the API
if (xModem_Init_UART_Port(uart_idx, pin_mux, baud_rate) < 0) {
return;
}
xModemStart(&xMCtrl, xMFrameBuf, xModem_Frame_Img2); // Support Image format: Image2 only
wr_len = xModemRxBuffer(&xMCtrl, (2*1024*1024));
xModemEnd(&xMCtrl);
xModem_DeInit_UART_Port(uart_idx);
// add checksum check
flash_checksum = xmodem_get_flash_checksum();
printf("flash_checksum: %x file_checksum: %x\n", flash_checksum, file_checksum.u);
if(flash_checksum != file_checksum.u)
printf("checksum error, please retry to update\n");
else
{
if ((wr_len > 0) && (flash_wr_err_cnt == 0)) {
// Firmware update OK, now write the signature to active this image
WriteImg2Sign(fw_img2_addr);
}
else
printf("error in writen to flash");
}
printf("OTU_FW_Update Done, Write Len=%d\n", wr_len);
SPI_FLASH_PIN_FCTRL(OFF);
}
#else
#include "xmodem.h"
#include "xmport_uart.h"
#include <platform/platform_stdlib.h>
#include "flash_api.h"
#include "device_lock.h"
char xMFrameBuf[XM_BUFFER_SIZE];
XMODEM_CTRL _xMCtrl;
extern const update_file_img_id OtaImgId[2];
static update_ota_target_hdr OtaTargetHdr;
static u32 fw_img2_addr;
static u32 flash_wr_err_cnt;
static int SigCnt;
static u8 signature[9];
static update_dw_info DownloadInfo[2];
static int ImageCnt;
static u32 OtaFg;
static s32 RemainBytes;
static u32 i;
static u32 TempLen;
static s32 OtaImgSize;
static int size;
void xDelayUs(u32 us)
{
DelayUs(us);
}
void xmodem_uart_func_hook(XMODEM_COM_PORT *pXComPort)
{
pXComPort->poll = (char(*)(void))xmodem_uart_readable;
pXComPort->put = xmodem_uart_putc;
pXComPort->get = (char(*)(void))xmodem_uart_getc;
}
s32
xModem_Init_UART_Port(u8 uart_idx, u8 pin_mux, u32 baud_rate)
{
xmodem_uart_init(uart_idx, pin_mux, baud_rate);
xmodem_uart_func_hook(&(_xMCtrl.ComPort));
return 0;
}
VOID
xModem_DeInit_UART_Port(u8 uart_idx)
{
xmodem_uart_deinit();
}
int GetDownloadInfo(u32 addr, update_ota_target_hdr * pOtaTgtHdr)
{
u32 ImageCnt;
/*init download information buffer*/
memset((u8 *)&DownloadInfo, 0, 2*sizeof(update_dw_info));
/*arrange OTA/RDP image download information*/
if(pOtaTgtHdr->RdpStatus == ENABLE) {
ImageCnt = 2;
if(pOtaTgtHdr->FileImgHdr.Offset < pOtaTgtHdr->FileRdpHdr.Offset) {
DownloadInfo[0].ImgId = OTA_IMAG;
/* get OTA image and Write New Image to flash, skip the signature,
not write signature first for power down protection*/
DownloadInfo[0].FlashAddr = addr -SPI_FLASH_BASE + 8;
DownloadInfo[0].ImageLen = pOtaTgtHdr->FileImgHdr.ImgLen - 8;/*skip the signature*/
DownloadInfo[0].ImgOffset = pOtaTgtHdr->FileImgHdr.Offset;
DownloadInfo[1].ImgId = RDP_IMAG;
DownloadInfo[1].FlashAddr = RDP_FLASH_ADDR - SPI_FLASH_BASE;
DownloadInfo[1].ImageLen = pOtaTgtHdr->FileRdpHdr.ImgLen;
DownloadInfo[1].ImgOffset = pOtaTgtHdr->FileRdpHdr.Offset;
} else {
DownloadInfo[0].ImgId = RDP_IMAG;
DownloadInfo[0].FlashAddr = RDP_FLASH_ADDR - SPI_FLASH_BASE;
DownloadInfo[0].ImageLen = pOtaTgtHdr->FileRdpHdr.ImgLen;
DownloadInfo[0].ImgOffset = pOtaTgtHdr->FileRdpHdr.Offset;
DownloadInfo[1].ImgId = OTA_IMAG;
/* get OTA image and Write New Image to flash, skip the signature,
not write signature first for power down protection*/
DownloadInfo[1].FlashAddr = addr -SPI_FLASH_BASE + 8;
DownloadInfo[1].ImageLen = pOtaTgtHdr->FileImgHdr.ImgLen - 8;/*skip the signature*/
DownloadInfo[1].ImgOffset = pOtaTgtHdr->FileImgHdr.Offset;
}
}else {
ImageCnt = 1;
DownloadInfo[0].ImgId = OTA_IMAG;
/* get OTA image and Write New Image to flash, skip the signature,
not write signature first for power down protection*/
DownloadInfo[0].FlashAddr = addr -SPI_FLASH_BASE + 8;
DownloadInfo[0].ImageLen = pOtaTgtHdr->FileImgHdr.ImgLen - 8;/*skip the signature*/
DownloadInfo[0].ImgOffset = pOtaTgtHdr->FileImgHdr.Offset;
}
printf("\n\r OTA Image Address = %x\n", addr);
if(pOtaTgtHdr->RdpStatus == ENABLE) {
printf("\n\r RDP Image Address = %x\n", RDP_FLASH_ADDR);
}
return ImageCnt;
}
u32 xModem_Frame_Img2(char *ptr, uint32_t frame_num, uint32_t frame_size)
{
uint32_t uart_ota_target_index = OTA_INDEX_2;
u32 fw_img2_size;
u8 *pImgId = NULL;
u32 IncFg = 0;
flash_t flash;
int read_bytes;
int read_bytes_buf;
u32 TempCnt = 0;
u32 TailCnt = 0;
u8 * buf = NULL;
printf("\rframe_num: %d frame_size: %d", frame_num, frame_size);
if (flash_wr_err_cnt)
return 0;
if (frame_num == 1) {
/* check OTA index we should update */
if (ota_get_cur_index() == OTA_INDEX_1) {
uart_ota_target_index = OTA_INDEX_2;
printf("\n\rOTA2 address space will be upgraded\n");
} else {
uart_ota_target_index = OTA_INDEX_1;
printf("\n\rOTA1 address space will be upgraded\n");
}
pImgId = (u8 *)&OtaImgId[uart_ota_target_index];
/* -----step3: parse firmware file header and get the target OTA image header-----*/
/* parse firmware file header and get the target OTA image header-----*/
if(!get_ota_tartget_header((u8*)ptr, frame_size, &OtaTargetHdr, pImgId)){
printf("\n\rget OTA header failed\n");
flash_wr_err_cnt++;
return 0;
}
/*get new image addr and check new address validity*/
if(!get_ota_address(uart_ota_target_index, &fw_img2_addr, &OtaTargetHdr)){
printf("\n\rget OTA address failed\n");
flash_wr_err_cnt++;
return 0;
}
/*get new image length from the firmware header*/
fw_img2_size = OtaTargetHdr.FileImgHdr.ImgLen;
/*-------------------step4: erase flash space for new firmware--------------*/
/*erase flash space new OTA image */
erase_ota_target_flash(fw_img2_addr, fw_img2_size);
/*erase flash space for new RDP image*/
if(OtaTargetHdr.RdpStatus == ENABLE) {
device_mutex_lock(RT_DEV_LOCK_FLASH);
flash_erase_sector(&flash, RDP_FLASH_ADDR - SPI_FLASH_BASE);
device_mutex_unlock(RT_DEV_LOCK_FLASH);
printf("\n\r RDP image size: %d", OtaTargetHdr.FileRdpHdr.ImgLen);
}
/*arrange OTA/RDP image download information*/
ImageCnt = GetDownloadInfo(fw_img2_addr, &OtaTargetHdr);
/*initialize the reveiving counter*/
RemainBytes = DownloadInfo[0].ImageLen;
}
/*downloading parse the OTA and RDP image from the data stream sent by server*/
while(i < ImageCnt){
/*download the new firmware from server*/
if(RemainBytes > 0){
buf = (u8*)ptr;
if(IncFg == 1) {
IncFg = 0;
read_bytes = read_bytes_buf;
} else {
read_bytes = frame_size;
if(read_bytes <= 0){
return 0; // it may not happen
}
read_bytes_buf = read_bytes;
TempLen += frame_size;
}
if(TempLen > DownloadInfo[i].ImgOffset) {
if(!OtaFg) { /*reach the desired image, the first packet process*/
OtaFg = 1;
TempCnt = TempLen -DownloadInfo[i].ImgOffset;
if(DownloadInfo[i].ImgId == OTA_IMAG) {
if(TempCnt < 8) {
SigCnt = TempCnt;
} else {
SigCnt = 8;
}
_memcpy(signature, buf + read_bytes -TempCnt, SigCnt);
if((SigCnt < 8) || (TempCnt -8 == 0)) {
return 0;
}
buf = buf + (read_bytes -TempCnt + 8);
read_bytes = TempCnt -8;
} else {
buf = buf + read_bytes -TempCnt;
read_bytes = TempCnt;
}
} else { /*normal packet process*/
if(DownloadInfo[i].ImgId == OTA_IMAG) {
if(SigCnt < 8) {
if(read_bytes < (8 -SigCnt)) {
_memcpy(signature + SigCnt, buf, read_bytes);
SigCnt += read_bytes;
return 0;
} else {
_memcpy(signature + SigCnt, buf, (8 -SigCnt));
buf = buf + (8 - SigCnt);
read_bytes -= (8 - SigCnt) ;
SigCnt = 8;
if(!read_bytes) {
return 0;
}
}
}
}
}
RemainBytes -= read_bytes;
if(RemainBytes < 0) {
read_bytes = read_bytes -(-RemainBytes);
}
device_mutex_lock(RT_DEV_LOCK_FLASH);
if(flash_stream_write(&flash, DownloadInfo[i].FlashAddr + size, read_bytes, buf) < 0){
printf("\n\r[%s] Write sector failed", __FUNCTION__);
device_mutex_unlock(RT_DEV_LOCK_FLASH);
flash_wr_err_cnt++;
return 0;
}
device_mutex_unlock(RT_DEV_LOCK_FLASH);
size += read_bytes;
}else{
return 0 + TailCnt; /* not reach desired image */
}
}else{
return 0; /* no desired image */
}
if(RemainBytes <= 0){
/*if complete downloading OTA image, acquire the image size*/
if(DownloadInfo[i].ImgId == OTA_IMAG) {
OtaImgSize = size;
}
TailCnt = read_bytes;
/*update flag status*/
size = 0;
OtaFg = 0;
IncFg = 1;
/*the next image length*/
if(++i < ImageCnt)
RemainBytes = DownloadInfo[i].ImageLen;
}else{
return read_bytes + TailCnt;
}
}
return 0 + TailCnt;/* no desired image */
}
int
WriteImg2Sign(
u32 wr_len
)
{
int ret = 1 ;
uint32_t uart_ota_target_index = OTA_INDEX_2;
flash_t flash;
if(fw_img2_addr == OTA1_ADDR)
uart_ota_target_index = OTA_INDEX_1;
else
uart_ota_target_index = OTA_INDEX_2;
if((OtaImgSize <= 0) || (OtaImgSize != (OtaTargetHdr.FileImgHdr.ImgLen - 8))) {
printf("\n\rdownload new firmware failed\n");
return 1;
}
printf("\n\rwrite size = %d", OtaImgSize);
printf("\n\rsignature = %s",signature);
/*-------------step6: verify checksum and update signature-----------------*/
if(verify_ota_checksum(fw_img2_addr, OtaImgSize, signature, &OtaTargetHdr)){
if(!change_ota_signature(fw_img2_addr, signature, uart_ota_target_index)) {
printf("\n%s: change signature failed\n", __FUNCTION__);
return 1;
}
ret = 0;
} else {
/*if checksum error, clear the signature zone which has been
written in flash in case of boot from the wrong firmware*/
#if 1
device_mutex_lock(RT_DEV_LOCK_FLASH);
flash_erase_sector(&flash, fw_img2_addr - SPI_FLASH_BASE);
device_mutex_unlock(RT_DEV_LOCK_FLASH);
#endif
}
return ret;
}
void OTU_FW_Update(u8 uart_idx, u8 pin_mux, u32 baud_rate)
{
u32 wr_len = 0;
int ret = 1;
memset(signature, 0, sizeof(signature));
memset(&OtaTargetHdr, 0, sizeof(OtaTargetHdr));
memset((u8 *)&DownloadInfo, 0, 2*sizeof(update_dw_info));
fw_img2_addr = 0;
flash_wr_err_cnt = 0;
SigCnt = 0;
ImageCnt = 0;
OtaFg = 0;
RemainBytes = 0;
i = 0;
TempLen = 0;
OtaImgSize = 0;
size = 0;
printf("FW Update Over UART%d, PinMux=%d, Baud=%d\r\n", uart_idx, pin_mux, baud_rate);
// Baud rate setting is used by UART_SetBaud,not serial_baud. Baud rate setting cannot be successful when LOW_POWER_RX_ENABLE
if(uart_config[0].LOW_POWER_RX_ENABLE){
UART_LPRxpathSet(UART0_DEV, DISABLE);
UART_LPRxIPClockSet(UART0_DEV, UART_RX_CLK_XTAL_40M);
}
// Start to update the Image2 through xModem on peripheral device
// We update the image via xModem on UART now, if we want to use other peripheral device
// to update the image then we need to redefine the API
if (xModem_Init_UART_Port(uart_idx, pin_mux, baud_rate) < 0) {
return;
}
xModemStart(&_xMCtrl, xMFrameBuf, xModem_Frame_Img2);
wr_len = _xModemRxBuffer(&_xMCtrl, (2*1024*1024));
xModemEnd(&_xMCtrl);
xModem_DeInit_UART_Port(uart_idx);
printf("FW Update Image2 @ 0x%x\r\n", fw_img2_addr);
if ((wr_len > 0) && (flash_wr_err_cnt == 0)){
ret = WriteImg2Sign(wr_len);
}
else
printf("\n\rerror in writen to flash");
if(!ret)
printf("\n\rOTU_FW_Update Success");
if(uart_config[0].LOW_POWER_RX_ENABLE){
UART_LPRxpathSet(UART0_DEV, ENABLE);
UART_LPRxIPClockSet(UART0_DEV, UART_RX_CLK_OSC_8M);
}
printf("\n\rOTU_FW_Update Done, Write Len=%d\n", wr_len);
}
#endif

View File

@@ -0,0 +1,129 @@
/**
******************************************************************************
* @file xmodem.h
* @author
* @version
* @brief This file provides user interface for xmodem, support Xmode Tx & Rx
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#ifndef _XMODE_H_
#define _XMODE_H_
/** @addtogroup xmodem XMODEM
* @ingroup hal
* @brief Xmodem TX & RX function
* @{
*/
#include <basic_types.h>
#if defined(CONFIG_PLATFORM_8711B)
#define xModemRxBuffer _xModemRxBuffer
#endif
/*****************
* X-Modem status
*****************/
#define XMODEM_OK 1
#define XMODEM_CANCEL 2
#define XMODEM_ACK 3
#define XMODEM_NAK 4
#define XMODEM_COMPLETE 5
#define XMODEM_NO_SESSION 6
#define XMODEM_ABORT 7
#define XMODEM_TIMEOUT 8
/****************************
* flow control character
****************************/
#define SOH 0x01 /* Start of header */
#define STX 0x02 /* Start of header XModem-1K */
#define EOT 0x04 /* End of transmission */
#define ACK 0x06 /* Acknowledge */
#define NAK 0x15 /* Not acknowledge */
#define CAN 0x18 /* Cancel */
#define ESC 0x1b /* User Break */
/****************************
* Xmode paramters
****************************/
#define FRAME_SIZE 132 /* X-modem structure */
#define FRAME_SIZE_1K 1028 /* X-modem structure */
#define XM_BUFFER_SIZE 1024 /* X-modem buffer */
#define TIMEOUT 180 /* max timeout */
#define RETRY_COUNT 20 /* Try times */
#define xWAITTIME 0x00400000 /* waitiing time */
#define WAIT_FRAME_TIME (10000*100) /* 10 sec, wait frame timeout */
#define WAIT_CHAR_TIME (1000*100) /* 1 sec, wait char timeout */
/***********************
* frame structure
***********************/
typedef struct
{
unsigned char soh;
unsigned char recordNo;
unsigned char recordNoInverted;
unsigned char buffer[XM_BUFFER_SIZE];
unsigned char CRC;
} XMODEM_FRAME;
typedef struct _XMODEM_COM_PORT_ {
char (*poll) (void);
char (*get)(void);
void (*put)(char c);
}XMODEM_COM_PORT, *PXMODEM_COM_PORT;
typedef struct _XMODEM_CTRL_ {
u16 xMUsing;
u16 currentFrame; /* current frame number */
u16 previousFrame; /* previous frame number */
u16 expected;
s16 rStatus;
s32 rFinish;
u32 total_frame;
u32 rx_len;
char *pXFrameBuf;
u32 (*RxFrameHandler)(char *ptr, u32 frame_num, u32 frame_size);
XMODEM_COM_PORT ComPort;
}XMODEM_CTRL, *PXMODEM_CTRL;
typedef u32 (*RxFrameHandler_t)(char *ptr, u32 frame_num, u32 frame_size);
/**
* @brief Initial comport, buffer, buffer handler
* @param pXMCtrl : xmodem comport
* @param FrameBuf : pointer of RX frame buffer
* @param RxFrameHdl : callback of receiving RX frame
* @return XMODEM_OK : initial OK
XMODEM_NO_SESSION : initial failed, xmodem is using
*/
extern s16 xModemStart(XMODEM_CTRL *pXMCtrl, char *FrameBuf, RxFrameHandler_t RxFrameHdl);
/**
* @brief Close xmodem comport
* @param pXMCtrl : xmodem comport
* @return XMODEM_OK : OK
* XMODEM_NO_SESSION : Close xmodem failed, xmodem has already closed
*/
extern s16 xModemEnd(XMODEM_CTRL *pXMCtrl);
/**
* @brief xmodem receive frame
* @param pXMCtrl : xmodem comport
* @param MaxSize : the maximum size of total RX frame
* @return successful : return total RX frame length
* failed : return MaxSize+1
*/
extern s32 xModemRxBuffer(XMODEM_CTRL *pXMCtrl, s32 MaxSize);
/*\@}*/
#endif /* _XMODE_H_ */

View File

@@ -0,0 +1,25 @@
/*
* Routines to access hardware
*
* Copyright (c) 2013 Realtek Semiconductor Corp.
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*/
#ifndef _XMPORT_LOGUART_H_
#define _XMPORT_LOGUART_H_
#include "xmodem.h"
//void xmodem_loguart_init(void);
void xmodem_loguart_init(u32 BaudRate);
void xmodem_loguart_func_hook(XMODEM_COM_PORT *pXComPort);
void xmodem_loguart_deinit(void);
char xmodem_loguart_readable(void);
char xmodem_loguart_writable(void);
char xmodem_loguart_getc(void);
void xmodem_loguart_putc(char c);
#endif // end of "#define _XMPORT_LOGUART_H_"

View File

@@ -0,0 +1,77 @@
/**
******************************************************************************
* @file xmodem_uart.h
* @author
* @version
* @brief This file provides user interface for xmodem uart
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#ifndef _XMPORT_UART_H_
#define _XMPORT_UART_H_
/** @addtogroup xmodem_uart XMODEM_UART
* @ingroup hal
* @brief Xmodem UART function
* @{
*/
#include "xmodem.h"
/**
* @brief Initial xmodem Uart
* @param uart_idx : Uart index
* @param pin_mux : Uart pin mux
* @param baud_rate : Uart baudrate
*/
void xmodem_uart_init(u8 uart_idx, u8 pin_mux, u32 baud_rate);
/**
* @brief Assign xmodem hook function with polling function, put char function, get char function
* @param pXComPort : pointer of xmodem comport to save hook function
*/
void xmodem_uart_func_hook(XMODEM_COM_PORT *pXComPort);
/**
* @brief Deinit xmodem Uart
*/
void xmodem_uart_deinit(void);
/**
* @Note This function is not used in xmodem
* @brief Check the readable status of UART
* @return 1 : UART is readable
* 0 : UART is not readable
*/
char xmodem_uart_readable(void);
/**
* @brief Check the writable status of UART
* @return 1 : UART is writable
* 0 : UART is not writable
*/
char xmodem_uart_writable(void);
/**
* @Note This function is not used in xmodem
* @brief Read character by UART
* @return The character read from UART
*/
char xmodem_uart_getc(void);
/**
* @brief Send character by UART
* @param c : The character to be sent
*/
void xmodem_uart_putc(char c);
/*\@}*/
#endif // end of "#define _XMPORT_UART_H_"