Add MQTT, network and debug functions

This commit is contained in:
Mats van Reenen 2020-10-15 10:58:51 +02:00
parent dea6cb3689
commit 7d5bd14503
12 changed files with 2574 additions and 12 deletions

2
.gitignore vendored
View File

@ -12,6 +12,7 @@
*.cmd
/*.c
/*.h
/.launches
# Node artifact files
node_modules/
@ -58,3 +59,4 @@ Thumbs.db
*.mov
*.wmv
/Debug/

11
src/debug/debug.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef DEBUG_H
#define DEBUG_H
#define IF_SEVERITY 0
#include "debug_if.h"
inline UART_Handle uartHandle;
// UART_control(uartHandle, UART_CMD_RXDISABLE, NULL);
#endif

89
src/debug/debug_if.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2016, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//*****************************************************************************
// Includes
//*****************************************************************************
// Standard includes
#ifndef DEBUG_IF_H
#define DEBUG_IF_H
/* Define Debug Method */
#define D_UART_PRINT 0
#define D_DISPLAY_PRINT 1
#define F_USER_DEFINED 2
#define D_DEBUG_METHOD D_UART_PRINT
/* Define Supported Modules */
#define D_GENERAL_IF (1)
#define D_MQTT_IF (1)
#define D_OTA_IF (1)
/* Define Severity Level */
enum
{
E_TRACE, E_DEBUG, E_INFO, E_WARNING, E_ERROR, E_FATAL, E_DISABLED
};
#define IF_NAME "GEN"
#ifndef IF_SEVERITY
#define IF_SEVERITY E_INFO
#endif
#if (D_DEBUG_METHOD == D_UART_PRINT)
#include "uart_term.h"
#define PRINTF(...) UART_PRINT(__VA_ARGS__);UART_PRINT("\n\r");
#elif (D_DEBUG_METHOD == D_DISPLAY_PRINT)
#include <ti/display/Display.h>
extern Display_Handle display;
#define PRINTF(_module_, _severity_, ...) Display_printf(display, 0, 0, __VA_ARGS__);
#else
/* USER DEFIND PRINT METHOD */
#ifndef PRINTF
#error "Missing definition of PRINTF method"
#endif
#endif
#define sl_printf(_severity_, ...) if(_severity_)>= D_SEVERITY) { PRINTF("[" IF_NAME "] "__VA_ARGS__); }
#define LOG_FATAL( ...) if(E_FATAL >= IF_SEVERITY) { PRINTF("[" IF_NAME "::FATAL] "__VA_ARGS__); }
#define LOG_ERROR( ...) if(E_ERROR >= IF_SEVERITY) { PRINTF("[" IF_NAME "::ERROR] "__VA_ARGS__); }
#define LOG_WARNING( ...) if(E_WARNING >= IF_SEVERITY) { PRINTF("[" IF_NAME "::WARN] "__VA_ARGS__); }
#define LOG_INFO( ...) if(E_INFO >= IF_SEVERITY) { PRINTF("[" IF_NAME "::INFO] "__VA_ARGS__); }
#define LOG_DEBUG( ...) if(E_DEBUG >= IF_SEVERITY) { PRINTF("[" IF_NAME "::DEBUG] "__VA_ARGS__); }
#define LOG_TRACE( ...) if(E_TRACE >= IF_SEVERITY) { PRINTF("[" IF_NAME "::TRACE] "__VA_ARGS__); }
#endif // DEBUG_IF_H

340
src/debug/uart_term.c Normal file
View File

@ -0,0 +1,340 @@
/*
* Copyright (c) 2016, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Terminal
*/
// Standard includes
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "uart_term.h"
extern int vsnprintf(char * s,
size_t n,
const char * format,
va_list arg);
//*****************************************************************************
// LOCAL DEFINES
//*****************************************************************************
#define IS_SPACE(x) (x == 32 ? 1 : 0)
//*****************************************************************************
// GLOBAL VARIABLES
//*****************************************************************************
static UART_Handle uartHandle;
//*****************************************************************************
//
//! Initialization
//!
//! This function
//! 1. Configures the UART to be used.
//!
//! \param none
//!
//! \return none
//
//*****************************************************************************
UART_Handle InitTerm(void)
{
UART_Params uartParams;
UART_init();
UART_Params_init(&uartParams);
uartParams.writeDataMode = UART_DATA_BINARY;
uartParams.readDataMode = UART_DATA_BINARY;
uartParams.readReturnMode = UART_RETURN_FULL;
uartParams.readEcho = UART_ECHO_OFF;
uartParams.baudRate = 115200;
uartHandle = UART_open(CONFIG_UART_0, &uartParams);
/* remove uart receive from LPDS dependency */
UART_control(uartHandle, UART_CMD_RXDISABLE, NULL);
return(uartHandle);
}
//*****************************************************************************
//
//! prints the formatted string on to the console
//!
//! \param[in] format - is a pointer to the character string specifying the
//! format in the following arguments need to be
//! interpreted.
//! \param[in] [variable number of] arguments according to the format in the
//! first parameters
//!
//! \return count of characters printed
//
//*****************************************************************************
int Report(const char *pcFormat,
...)
{
int iRet = 0;
char *pcBuff;
char *pcTemp;
int iSize = 256;
va_list list;
pcBuff = (char*)malloc(iSize);
if(pcBuff == NULL)
{
return(-1);
}
while(1)
{
va_start(list,pcFormat);
iRet = vsnprintf(pcBuff, iSize, pcFormat, list);
va_end(list);
if((iRet > -1) && (iRet < iSize))
{
break;
}
else
{
iSize *= 2;
if((pcTemp = realloc(pcBuff, iSize)) == NULL)
{
Message("Could not reallocate memory\n\r");
iRet = -1;
break;
}
else
{
pcBuff = pcTemp;
}
}
}
Message(pcBuff);
free(pcBuff);
return(iRet);
}
//*****************************************************************************
//
//! Trim the spaces from left and right end of given string
//!
//! \param pcInput - string on which trimming happens
//!
//! \return length of trimmed string
//
//*****************************************************************************
int TrimSpace(char * pcInput)
{
size_t size;
char *endStr;
char *strData = pcInput;
char index = 0;
size = strlen(strData);
if(!size)
{
return(0);
}
endStr = strData + size - 1;
while((endStr >= strData) && (IS_SPACE(*endStr)))
{
endStr--;
}
*(endStr + 1) = '\0';
while(*strData && IS_SPACE(*strData))
{
strData++;
index++;
}
memmove(pcInput, strData, strlen(strData) + 1);
return(strlen(pcInput));
}
//*****************************************************************************
//
//! Get the Command string from UART
//!
//! \param[in] pucBuffer - is the command store to which command will be
//! populated
//! \param[in] ucBufLen - is the length of buffer store available
//!
//! \return Length of the bytes received. -1 if buffer length exceeded.
//!
//*****************************************************************************
int GetCmd(char *pcBuffer,
unsigned int uiBufLen)
{
char cChar;
int iLen = 0;
UART_readPolling(uartHandle, &cChar, 1);
iLen = 0;
//
// Checking the end of Command
//
while(1)
{
//
// Handling overflow of buffer
//
if(iLen >= uiBufLen)
{
return(-1);
}
//
// Copying Data from UART into a buffer
//
if((cChar == '\r') || (cChar == '\n'))
{
UART_writePolling(uartHandle, &cChar, 1);
break;
}
else if(cChar == '\b')
{
//
// Deleting last character when you hit backspace
//
char ch;
UART_writePolling(uartHandle, &cChar, 1);
ch = ' ';
UART_writePolling(uartHandle, &ch, 1);
if(iLen)
{
UART_writePolling(uartHandle, &cChar, 1);
iLen--;
}
else
{
ch = '\a';
UART_writePolling(uartHandle, &ch, 1);
}
}
else
{
//
// Echo the received character
//
UART_writePolling(uartHandle, &cChar, 1);
*(pcBuffer + iLen) = cChar;
iLen++;
}
UART_readPolling(uartHandle, &cChar, 1);
}
*(pcBuffer + iLen) = '\0';
return(iLen);
}
//*****************************************************************************
//
//! Outputs a character string to the console
//!
//! This function
//! 1. prints the input string character by character on to the console.
//!
//! \param[in] str - is the pointer to the string to be printed
//!
//! \return none
//!
//! \note If UART_NONPOLLING defined in than Message or UART write should be
//! called in task/thread context only.
//
//*****************************************************************************
void Message(const char *str)
{
#ifdef UART_NONPOLLING
UART_write(uartHandle, str, strlen(str));
#else
UART_writePolling(uartHandle, str, strlen(str));
#endif
}
//*****************************************************************************
//
//! Clear the console window
//!
//! This function
//! 1. clears the console window.
//!
//! \param none
//!
//! \return none
//
//*****************************************************************************
void ClearTerm()
{
Message("\33[2J\r");
}
//*****************************************************************************
//
//! Read a character from the console
//!
//! \param none
//!
//! \return Character
//
//*****************************************************************************
char getch(void)
{
char ch;
UART_readPolling(uartHandle, &ch, 1);
return(ch);
}
//*****************************************************************************
//
//! Outputs a character to the console
//!
//! \param[in] char - A character to be printed
//!
//! \return none
//
//*****************************************************************************
void putch(char ch)
{
UART_writePolling(uartHandle, &ch, 1);
}

36
src/debug/uart_term.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef __UART_IF_H__
#define __UART_IF_H__
// TI-Driver includes
#include <ti/drivers/UART.h>
#include "ti_drivers_config.h"
//Defines
#define UART_PRINT Report
#define DBG_PRINT Report
#define ERR_PRINT(x) Report("Error [%d] at line [%d] in function [%s] \n\r",\
x, __LINE__, \
__FUNCTION__)
/* API */
UART_Handle InitTerm(void);
int Report(const char *pcFormat,
...);
int TrimSpace(char * pcInput);
int GetCmd(char *pcBuffer,
unsigned int uiBufLen);
void Message(const char *str);
void ClearTerm();
char getch(void);
void putch(char ch);
#endif // __UART_IF_H__

View File

@ -4,15 +4,18 @@
#include <ti/drivers/GPIO.h>
#include "ti_drivers_config.h"
#include "./header.h"
#include "debug/debug.h"
#include "header.h"
void Hardware_init(){
Board_init();
GPIO_init();
uartHandle = InitTerm();
LOG_TRACE("Hardware initialisation done\r\n");
}
int main(void){
Hardware_init() // initilize hardware
Hardware_init(); // initilize hardware
// ==============================================
// === tread for G sensor =======================
@ -23,14 +26,5 @@ int main(void){
BIOS_start();
return (0);
}
/*
* ======== dummyOutput ========
* Dummy SysMin output function needed for benchmarks and size comparison
* of FreeRTOS and TI-RTOS solutions.
*/
void dummyOutput(void)
{
return 0;
}

View File

@ -0,0 +1,171 @@
#include "mqtt/mqtt.h"
void MQTTTask(void * args){
mq_attr attr;
Timer_Params params;
// UART_Handle uartHandle;
MQTTClient_Handle mqttClientHandle;
// uartHandle = InitTerm();
// UART_control(uartHandle, UART_CMD_RXDISABLE, NULL);
// GPIO_init();
SPI_init();
// Timer_init();
int32_t ret = ti_net_SlNet_initConfig();
if(0 != ret)
{
LOG_ERROR("Failed to initialize SlNetSock\n\r");
}
// GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF);
// GPIO_write(CONFIG_GPIO_LED_1, CONFIG_GPIO_LED_OFF);
// GPIO_write(CONFIG_GPIO_LED_2, CONFIG_GPIO_LED_OFF);
// GPIO_setCallback(CONFIG_GPIO_BUTTON_0, pushButtonPublishHandler);
// GPIO_setCallback(CONFIG_GPIO_BUTTON_1, pushButtonConnectionHandler);
// configuring the timer to toggle an LED until the AP is connected
// Timer_Params_init(&params);
// params.period = 1000000;
// params.periodUnits = Timer_PERIOD_US;
// params.timerMode = Timer_CONTINUOUS_CALLBACK;
// params.timerCallback = (Timer_CallBackFxn)timerLEDCallback;
// timer0 = Timer_open(CONFIG_TIMER_0, &params);
// if (timer0 == NULL) {
// LOG_ERROR("failed to initialize timer\r\n");
// while(1);
// }
attr.mq_maxmsg = 10;
attr.mq_msgsize = sizeof(struct msgQueue);
appQueue = mq_open("appQueue", O_CREAT, 0, &attr);
if(((int)appQueue) <= 0){
while(1);
}
ret = WifiInit();
if(ret < 0){
while(1);
}
// GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF);
// GPIO_write(CONFIG_GPIO_LED_1, CONFIG_GPIO_LED_OFF);
// GPIO_write(CONFIG_GPIO_LED_2, CONFIG_GPIO_LED_OFF);
// params.period = 1500000;
// params.periodUnits = Timer_PERIOD_US;
// params.timerMode = Timer_ONESHOT_CALLBACK;
// params.timerCallback = (Timer_CallBackFxn)timerCallback;
// timer0 = Timer_open(CONFIG_TIMER_0, &params);
// if (timer0 == NULL) {
// LOG_ERROR("failed to initialize timer\r\n");
// while(1);
// }
// MQTT_DEMO:
ret = MQTT_IF_Init(mqttInitParams);
if(ret < 0){
while(1);
}
/*
* In case a persistent session is being used, subscribe is called before connect so that the module
* is aware of the topic callbacks the user is using. This is important because if the broker is holding
* messages for the client, after CONNACK the client may receive the messages before the module is aware
* of the topic callbacks. The user may still call subscribe after connect but have to be aware of this.
*/
ret = MQTT_IF_Subscribe(mqttClientHandle, "Broker/To/cc32xx", MQTT_QOS_2, BrokerCB);
ret |= MQTT_IF_Subscribe(mqttClientHandle, "cc32xx/ToggleLED1", MQTT_QOS_2, ToggleLED1CB);
ret |= MQTT_IF_Subscribe(mqttClientHandle, "cc32xx/ToggleLED2", MQTT_QOS_2, ToggleLED2CB);
ret |= MQTT_IF_Subscribe(mqttClientHandle, "cc32xx/ToggleLED3", MQTT_QOS_2, ToggleLED3CB);
if(ret < 0){
while(1);
}
else{
LOG_INFO("Subscribed to all topics successfully\r\n");
}
mqttClientHandle = MQTT_IF_Connect(mqttClientParams, mqttConnParams, MQTT_EventCallback);
if(mqttClientHandle < 0){
while(1);
}
// wait for CONNACK
while(connected == 0);
// GPIO_enableInt(CONFIG_GPIO_BUTTON_0);
struct msgQueue queueElement;
while(1){
mq_receive(appQueue, (char*)&queueElement, sizeof(struct msgQueue), NULL);
if(queueElement.event == APP_MQTT_PUBLISH){
LOG_TRACE("APP_MQTT_PUBLISH\r\n");
MQTT_IF_Publish(mqttClientHandle,
"cc32xx/ToggleLED1",
"LED 1 toggle\r\n",
strlen("LED 1 toggle\r\n"),
MQTT_QOS_2);
// GPIO_clearInt(CONFIG_GPIO_BUTTON_0);
// GPIO_enableInt(CONFIG_GPIO_BUTTON_0);
}
else if(queueElement.event == APP_MQTT_CON_TOGGLE){
LOG_TRACE("APP_MQTT_CON_TOGGLE %d\r\n", connected);
if(connected){
ret = MQTT_IF_Disconnect(mqttClientHandle);
if(ret >= 0){
connected = 0;
}
}else{
mqttClientHandle = MQTT_IF_Connect(mqttClientParams, mqttConnParams, MQTT_EventCallback);
if((int)mqttClientHandle >= 0){
connected = 1;
}
}
}
else if(queueElement.event == APP_MQTT_DEINIT){
break;
}
else if(queueElement.event == APP_BTN_HANDLER){
struct msgQueue queueElement;
ret = detectLongPress();
if(ret == 0){
LOG_TRACE("APP_BTN_HANDLER SHORT PRESS\r\n");
queueElement.event = APP_MQTT_CON_TOGGLE;
}
else{
LOG_TRACE("APP_BTN_HANDLER LONG PRESS\r\n");
queueElement.event = APP_MQTT_DEINIT;
}
ret = mq_send(appQueue, (const char*)&queueElement, sizeof(struct msgQueue), 0);
if(ret < 0){
LOG_ERROR("msg queue send error %d", ret);
}
}
}
deinit = 1;
if(connected){
MQTT_IF_Disconnect(mqttClientHandle);
}
MQTT_IF_Deinit();
// LOG_INFO("looping the MQTT functionality of the example for demonstration purposes only\r\n");
// sleep(2);
// goto MQTT_DEMO;
}

84
src/mqtt/mqtt.h Normal file
View File

@ -0,0 +1,84 @@
#include "./mqtt_if.h"
// #define SL_TASKSTACKSIZE 2048
// #define SPAWN_TASK_PRIORITY 9
// #define MQTT_MODULE_TASK_PRIORITY 2
// #define MQTT_MODULE_TASK_STACK_SIZE 2048
#define MQTT_WILL_TOPIC "jesus_cc32xx_will_topic"
#define MQTT_WILL_MSG "will_msg_works"
#define MQTT_WILL_QOS MQTT_QOS_2
#define MQTT_WILL_RETAIN false
#define MQTT_CLIENT_PASSWORD NULL
#define MQTT_CLIENT_USERNAME NULL
#define MQTT_CLIENT_KEEPALIVE 0
#define MQTT_CLIENT_CLEAN_CONNECT true
#define MQTT_CLIENT_MQTT_V3_1 true
#define MQTT_CLIENT_BLOCKING_SEND true
#define MQTT_CONNECTION_FLAGS MQTTCLIENT_NETCONN_URL
#define MQTT_CONNECTION_ADDRESS "mqtt.eclipse.org"
#define MQTT_CONNECTION_PORT_NUMBER 1883
mqd_t appQueue;
int connected;
int deinit;
Timer_Handle timer0;
int longPress = 0;
/* Client ID */
/* If ClientId isn't set, the MAC address of the device will be copied into */
/* the ClientID parameter. */
char ClientId[13] = {'\0'};
enum{
APP_MQTT_PUBLISH,
APP_MQTT_CON_TOGGLE,
APP_MQTT_DEINIT,
APP_BTN_HANDLER
};
struct msgQueue
{
int event;
char* payload;
};
// MQTT_IF_InitParams_t mqttInitParams =
// {
// MQTT_MODULE_TASK_STACK_SIZE, // stack size for mqtt module - default is 2048
// MQTT_MODULE_TASK_PRIORITY // thread priority for MQTT - default is 2
// };
MQTTClient_Will mqttWillParams =
{
MQTT_WILL_TOPIC, // will topic
MQTT_WILL_MSG, // will message
MQTT_WILL_QOS, // will QoS
MQTT_WILL_RETAIN // retain flag
};
MQTT_IF_ClientParams_t mqttClientParams =
{
ClientId, // client ID
MQTT_CLIENT_USERNAME, // user name
MQTT_CLIENT_PASSWORD, // password
MQTT_CLIENT_KEEPALIVE, // keep-alive time
MQTT_CLIENT_CLEAN_CONNECT, // clean connect flag
MQTT_CLIENT_MQTT_V3_1, // true = 3.1, false = 3.1.1
MQTT_CLIENT_BLOCKING_SEND, // blocking send flag
&mqttWillParams // will parameters
};
MQTTClient_ConnParams mqttConnParams =
{
MQTT_CONNECTION_FLAGS, // connection flags
MQTT_CONNECTION_ADDRESS, // server address
MQTT_CONNECTION_PORT_NUMBER, // port number of MQTT server
0, // method for secure socket
0, // cipher for secure socket
0, // number of files for secure connection
NULL // secure files
};

665
src/mqtt/mqtt_if.c Normal file
View File

@ -0,0 +1,665 @@
/*
* mqttclient_if.c
*
* Created on: Jan 22, 2020
* Author: a0227533
*/
#include "mqtt_if.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <mqueue.h>
#include "../debug/debug.h"
enum{
MQTT_STATE_IDLE,
MQTT_STATE_INITIALIZED,
MQTT_STATE_CONNECTED
};
#define MQTT_EVENT_RECV MQTT_EVENT_MAX // event for when receiving data from subscribed topics
#define MQTTAPPTHREADSIZE 2048
// structure for linked list elements to manage the topics
struct Node
{
MQTTClient_SubscribeParams topicParams;
MQTT_IF_TopicCallback_f topicCB;
struct Node* next;
};
struct msgQueue
{
int event;
char* topic;
char* payload;
};
static struct mqttContext
{
mqd_t msgQueue;
pthread_mutex_t *moduleMutex;
MQTTClient_Handle mqttClient;
MQTT_IF_EventCallback_f eventCB;
struct Node* head;
int moduleState;
uint8_t clientDisconnectFlag;
} mMQTTContext = {NULL, NULL, NULL, NULL, NULL, MQTT_STATE_IDLE, 0};
// Callback invoked by the internal MQTT library to notify the application of MQTT events
void MQTTClientCallback(int32_t event, void *metaData, uint32_t metaDateLen, void *data, uint32_t dataLen)
{
int status;
struct msgQueue queueElement;
switch((MQTTClient_EventCB)event)
{
case MQTTClient_OPERATION_CB_EVENT:
{
switch(((MQTTClient_OperationMetaDataCB *)metaData)->messageType)
{
case MQTTCLIENT_OPERATION_CONNACK:
{
LOG_TRACE("MQTT CLIENT CB: CONNACK\r\n");
queueElement.event = MQTT_EVENT_CONNACK;
break;
}
case MQTTCLIENT_OPERATION_EVT_PUBACK:
{
LOG_TRACE("MQTT CLIENT CB: PUBACK\r\n");
queueElement.event = MQTT_EVENT_PUBACK;
break;
}
case MQTTCLIENT_OPERATION_SUBACK:
{
LOG_TRACE("MQTT CLIENT CB: SUBACK\r\n");
queueElement.event = MQTT_EVENT_SUBACK;
break;
}
case MQTTCLIENT_OPERATION_UNSUBACK:
{
LOG_TRACE("MQTT CLIENT CB: UNSUBACK\r\n");
queueElement.event = MQTT_EVENT_UNSUBACK;
break;
}
}
break;
}
case MQTTClient_RECV_CB_EVENT:
{
LOG_TRACE("MQTT CLIENT CB: RECV CB\r\n");
MQTTClient_RecvMetaDataCB *receivedMetaData;
char *topic;
char *payload;
receivedMetaData = (MQTTClient_RecvMetaDataCB *)metaData;
// copying received topic data locally to send over msg queue
topic = (char*)malloc(receivedMetaData->topLen+1);
memcpy(topic, receivedMetaData->topic, receivedMetaData->topLen);
topic[receivedMetaData->topLen] = 0;
payload = (char*)malloc(dataLen+1);
memcpy(payload, data, dataLen);
payload[dataLen] = 0;
queueElement.event = MQTT_EVENT_RECV;
queueElement.topic = topic;
queueElement.payload = payload;
break;
}
case MQTTClient_DISCONNECT_CB_EVENT:
{
LOG_TRACE("MQTT CLIENT CB: DISCONNECT\r\n");
queueElement.event = MQTT_EVENT_SERVER_DISCONNECT;
break;
}
}
// signaling the MQTTAppThead of events received from the internal MQTT module
status = mq_send(mMQTTContext.msgQueue, (char*)&queueElement, sizeof(struct msgQueue), 0);
if(status < 0){
LOG_ERROR("msg queue send error %d", status);
}
}
// Helper function used to compare topic strings and accounts for MQTT wild cards
int MQTTHelperTopicMatching(char *s, char *p)
{
char *s_next = (char*)-1, *p_next;
for(; s_next; s=s_next+1, p=p_next+1)
{
int len;
if(s[0] == '#')
return 1;
s_next = strchr(s, '/');
p_next = strchr(p, '/');
len = ((s_next) ? (s_next - s) : (strlen(s))) + 1;
if(s[0] != '+')
{
if(memcmp(s, p, len) != 0)
return 0;
}
}
return (p_next)?0:1;
}
// This is the application thread for the MQTT module that signals
void *MQTTAppThread(void *threadParams)
{
int ret;
struct msgQueue queueElement;
while(1)
{
mq_receive(mMQTTContext.msgQueue, (char*)&queueElement, sizeof(struct msgQueue), NULL);
ret = 0;
if(queueElement.event == MQTT_EVENT_RECV)
{
LOG_TRACE("MQTT APP THREAD: RECV TOPIC = %s", queueElement.topic);
pthread_mutex_lock(mMQTTContext.moduleMutex);
if(mMQTTContext.head != NULL){
struct Node* tmp = mMQTTContext.head;
// check what queueElement.topic to invoke the appropriate topic callback event for the user
while(ret == 0){
ret = MQTTHelperTopicMatching(tmp->topicParams.topic, queueElement.topic);
if(ret == 1){
LOG_DEBUG("TOPIC MATCH %s\r\n", queueElement.topic);
tmp->topicCB(queueElement.topic, queueElement.payload);
break;
}
tmp = tmp->next;
if(tmp == NULL){
LOG_INFO("Cannot invoke CB for topic not in topic list\r\n");
LOG_INFO("TOPIC: %s \tPAYLOAD: %s\r\n", queueElement.topic, queueElement.payload);
break;
}
}
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
free(queueElement.topic);
free(queueElement.payload);
}
// when MQTT_IF_Deinit is called we must close the message queue and terminate the MQTTAppThread
else if(queueElement.event == MQTT_EVENT_DESTROY)
{
LOG_TRACE("MQTT APP THREAD: DESTROY\r\n");
mMQTTContext.eventCB(queueElement.event);
ret = mq_close(mMQTTContext.msgQueue);
if(ret < 0){
LOG_ERROR("msg queue close error %d", ret);
}
pthread_exit(0);
}
else if(queueElement.event == MQTT_EVENT_SERVER_DISCONNECT){
LOG_TRACE("MQTT APP THREAD: DISCONNECT\r\n");
int tmp; // tmp is to avoid invoking the eventCB while mutex is still locked to prevent deadlock
pthread_mutex_lock(mMQTTContext.moduleMutex);
// checks if the disconnect event came because the client called disconnect or the server disconnected
if(mMQTTContext.clientDisconnectFlag == 1){
tmp = 1;
mMQTTContext.clientDisconnectFlag = 0;
}
else{
tmp = 0;
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
if(tmp == 1){
mMQTTContext.eventCB(MQTT_EVENT_CLIENT_DISCONNECT);
}
else{
mMQTTContext.eventCB(queueElement.event);
}
}
else if(queueElement.event == MQTT_EVENT_CONNACK){
LOG_TRACE("MQTT APP THREAD: CONNACK\r\n");
pthread_mutex_lock(mMQTTContext.moduleMutex);
// in case the user re-connects to a server this checks if there is a list of topics to
// automatically subscribe to the topics again
if(mMQTTContext.head != NULL){
struct Node* curr = mMQTTContext.head;
struct Node* prev;
struct Node* tmp;
// iterate through the linked list until the end is reached
while(curr != NULL){
tmp = curr;
ret = MQTTClient_subscribe(mMQTTContext.mqttClient, &curr->topicParams, 1);
// if subscribing to a topic fails we must remove the node from the list since we are no longer subscribed
if(ret < 0){
LOG_ERROR("SUBSCRIBE FAILED: %s", curr->topicParams.topic);
// if the node to remove is the head update the head pointer
if(curr == mMQTTContext.head){
mMQTTContext.head = curr->next;
curr = curr->next;
}
else if(curr->next != NULL){
prev->next = curr->next;
curr = curr->next->next;
}
else{
prev->next = curr->next;
curr = curr->next;
}
// delete the node from the linked list
free(tmp->topicParams.topic);
free(tmp);
}
else{
prev = curr;
curr = curr->next;
}
}
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
// notify the user of the connection event
mMQTTContext.eventCB(queueElement.event);
}
else{
LOG_TRACE("MQTT APP THREAD: OTHER\r\n");
// if the module received any other event nothing else needs to be done except call it
mMQTTContext.eventCB(queueElement.event);
}
}
}
// this thread is for the internal MQTT library and is required for the library to function
void *MQTTContextThread(void *threadParams)
{
int ret;
LOG_TRACE("CONTEXT THREAD: RUNNING\r\n");
MQTTClient_run((MQTTClient_Handle)threadParams);
LOG_TRACE("CONTEXT THREAD: MQTTClient_run RETURN\r\n");
pthread_mutex_lock(mMQTTContext.moduleMutex);
ret = MQTTClient_delete(mMQTTContext.mqttClient);
if(ret < 0){
LOG_ERROR("client delete error %d", ret);
}
LOG_TRACE("CONTEXT THREAD: MQTT CLIENT DELETED")
mMQTTContext.moduleState = MQTT_STATE_INITIALIZED;
pthread_mutex_unlock(mMQTTContext.moduleMutex);
LOG_TRACE("CONTEXT THREAD EXIT\r\n");
pthread_exit(0);
return(NULL);
}
int MQTT_IF_Init(MQTT_IF_InitParams_t initParams)
{
int ret;
mq_attr attr;
pthread_attr_t threadAttr;
struct sched_param schedulingparams;
pthread_t mqttAppThread = (pthread_t) NULL;
if(mMQTTContext.moduleState != MQTT_STATE_IDLE){
LOG_ERROR("library only supports 1 active init call\r\n");
return -1;
}
// the mutex is to protect data in the mMQTTContext structure from being manipulated or accessed at the wrong time
mMQTTContext.moduleMutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
if(mMQTTContext.moduleMutex == NULL){
LOG_ERROR("malloc failed: mutex\r\n");
return -1;
}
ret = pthread_mutex_init(mMQTTContext.moduleMutex, (const pthread_mutexattr_t *)NULL);
if (ret != 0){
LOG_ERROR("mutex init failed\r\n");
return ret;
}
pthread_mutex_lock(mMQTTContext.moduleMutex);
// initializing the message queue for the MQTT module
attr.mq_maxmsg = 10;
attr.mq_msgsize = sizeof(struct msgQueue);
mMQTTContext.msgQueue = mq_open("msgQueue", O_CREAT, 0, &attr);
if(((int)mMQTTContext.msgQueue) <= 0){
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return (int)mMQTTContext.msgQueue;
}
pthread_attr_init(&threadAttr);
schedulingparams.sched_priority = initParams.threadPriority;
ret = pthread_attr_setschedparam(&threadAttr, &schedulingparams);
ret |= pthread_attr_setstacksize(&threadAttr, initParams.stackSize);
ret |= pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
ret |= pthread_create(&mqttAppThread, &threadAttr, MQTTAppThread, NULL);
if(ret == 0){
mMQTTContext.moduleState = MQTT_STATE_INITIALIZED;
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return ret;
}
int MQTT_IF_Deinit(MQTTClient_Handle mqttClientHandle)
{
int ret;
struct msgQueue queueElement;
pthread_mutex_lock(mMQTTContext.moduleMutex);
if(mMQTTContext.moduleState != MQTT_STATE_INITIALIZED){
if(mMQTTContext.moduleState == MQTT_STATE_CONNECTED){
LOG_ERROR("call disconnect before calling deinit\r\n");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
else if(mMQTTContext.moduleState == MQTT_STATE_IDLE){
LOG_ERROR("init has not been called\r\n");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
}
queueElement.event = MQTT_EVENT_DESTROY;
// since user called MQTT_IF_Deinit send the signal to the app thread so it may terminate itself
ret = mq_send(mMQTTContext.msgQueue, (const char*)&queueElement, sizeof(struct msgQueue), 0);
if(ret < 0){
LOG_ERROR("msg queue send error %d", ret);
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
struct Node* tmp = mMQTTContext.head;
// in case the user did not unsubscribe to topics this loop will free any memory that was allocated
while(tmp != NULL){
free(tmp->topicParams.topic);
mMQTTContext.head = tmp->next;
free(tmp);
tmp = mMQTTContext.head;
}
// setting the MQTT module state back so that user can call init if they wish to use it again
mMQTTContext.moduleState = MQTT_STATE_IDLE;
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return 0;
}
MQTTClient_Handle MQTT_IF_Connect(MQTT_IF_ClientParams_t mqttClientParams, MQTTClient_ConnParams mqttConnParams, MQTT_IF_EventCallback_f mqttCB)
{
int ret;
pthread_attr_t threadAttr;
struct sched_param priParam;
pthread_t mqttContextThread = (pthread_t) NULL;
MQTTClient_Params clientParams;
pthread_mutex_lock(mMQTTContext.moduleMutex);
// if the user has not called init this will return error since they're trying to connect without intializing the module
if(mMQTTContext.moduleState != MQTT_STATE_INITIALIZED){
if(mMQTTContext.moduleState == MQTT_STATE_CONNECTED){
LOG_ERROR("mqtt library is already connected to a broker\r\n");
}
else{
LOG_ERROR("must call init before calling connect\r\n");
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return (MQTTClient_Handle)-1;
}
// copying the event callback the user registered for the module context
mMQTTContext.eventCB = mqttCB;
// preparing the data for MQTTClient_create
clientParams.blockingSend = mqttClientParams.blockingSend;
clientParams.clientId = mqttClientParams.clientID;
clientParams.connParams = &mqttConnParams;
clientParams.mqttMode31 = mqttClientParams.mqttMode31;
mMQTTContext.mqttClient = MQTTClient_create(MQTTClientCallback, &clientParams);
if(mMQTTContext.mqttClient == NULL){
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return (MQTTClient_Handle)-1;
}
pthread_attr_init(&threadAttr);
priParam.sched_priority = 2;
ret = pthread_attr_setschedparam(&threadAttr, &priParam);
ret |= pthread_attr_setstacksize(&threadAttr, MQTTAPPTHREADSIZE);
ret |= pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
ret |= pthread_create(&mqttContextThread, &threadAttr, MQTTContextThread, NULL);
if(ret != 0){
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return (MQTTClient_Handle)-1;
}
// if the user included additional parameters for the client MQTTClient_set will be called
if(mqttClientParams.willParams != NULL){
MQTTClient_set(mMQTTContext.mqttClient, MQTTClient_WILL_PARAM, mqttClientParams.willParams, sizeof(MQTTClient_Will));
}
if(mqttClientParams.username != NULL){
MQTTClient_set(mMQTTContext.mqttClient, MQTTClient_USER_NAME, mqttClientParams.username, strlen(mqttClientParams.username));
}
if(mqttClientParams.password != NULL){
MQTTClient_set(mMQTTContext.mqttClient, MQTTClient_PASSWORD, mqttClientParams.password, strlen(mqttClientParams.password));
}
if(mqttClientParams.cleanConnect == false){
MQTTClient_set(mMQTTContext.mqttClient, MQTTClient_CLEAN_CONNECT, &mqttClientParams.cleanConnect, sizeof(mqttClientParams.cleanConnect));
}
if(mqttClientParams.keepaliveTime > 0){
MQTTClient_set(mMQTTContext.mqttClient, MQTTClient_KEEPALIVE_TIME, &mqttClientParams.keepaliveTime, sizeof(mqttClientParams.keepaliveTime));
}
ret = MQTTClient_connect(mMQTTContext.mqttClient);
if(ret < 0){
LOG_ERROR("connect failed: %d\r\n", ret);
}
else{
mMQTTContext.moduleState = MQTT_STATE_CONNECTED;
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
if(ret < 0){
return (MQTTClient_Handle)ret;
}
else{
return mMQTTContext.mqttClient;
}
}
int MQTT_IF_Disconnect(MQTTClient_Handle mqttClientHandle)
{
int ret;
pthread_mutex_lock(mMQTTContext.moduleMutex);
if(mMQTTContext.moduleState != MQTT_STATE_CONNECTED){
LOG_ERROR("not connected to broker\r\n");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
mMQTTContext.clientDisconnectFlag = 1;
ret = MQTTClient_disconnect(mqttClientHandle);
if(ret < 0){
LOG_ERROR("disconnect error %d", ret);
}
else{
mMQTTContext.moduleState = MQTT_STATE_INITIALIZED;
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return ret;
}
int MQTT_IF_Subscribe(MQTTClient_Handle mqttClientHandle, char* topic, unsigned int qos, MQTT_IF_TopicCallback_f topicCB)
{
int ret = 0;
struct Node* topicEntry = NULL;
pthread_mutex_lock(mMQTTContext.moduleMutex);
if(mMQTTContext.moduleState == MQTT_STATE_IDLE){
LOG_ERROR("user must call MQTT_IF_Init before using the MQTT module\r\n");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
// preparing the topic node to add it to the linked list that tracks all the subscribed topics
topicEntry = (struct Node*)malloc(sizeof(struct Node));
if(topicEntry == NULL){
LOG_ERROR("malloc failed: list entry\n\r");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
topicEntry->topicParams.topic = (char*)malloc((strlen(topic)+1)*sizeof(char));
if(topicEntry->topicParams.topic == NULL){
LOG_ERROR("malloc failed: topic\n\r");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
strcpy(topicEntry->topicParams.topic, topic);
topicEntry->topicParams.qos = qos;
topicEntry->topicCB = topicCB;
// adding the topic node to the linked list
topicEntry->next = mMQTTContext.head;
mMQTTContext.head = topicEntry;
if(mMQTTContext.moduleState == MQTT_STATE_CONNECTED){
ret = MQTTClient_subscribe(mMQTTContext.mqttClient, &topicEntry->topicParams, 1);
// if the client fails to subscribe to the node remove the topic from the list
if(ret < 0){
LOG_ERROR("subscribe failed %d. removing topic from list", ret);
free(topicEntry->topicParams.topic);
free(topicEntry);
}
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return ret;
}
int MQTT_IF_Unsubscribe(MQTTClient_Handle mqttClientHandle, char* topic)
{
int ret = 0;
pthread_mutex_lock(mMQTTContext.moduleMutex);
if(mMQTTContext.moduleState != MQTT_STATE_CONNECTED){
LOG_ERROR("not connected to broker\r\n");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
MQTTClient_UnsubscribeParams unsubParams;
unsubParams.topic = topic;
ret = MQTTClient_unsubscribe(mMQTTContext.mqttClient, &unsubParams, 1);
if(ret < 0){
LOG_ERROR("unsub failed\r\n");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return ret;
}
else{
// since unsubscribe succeeded the topic linked list must be updated to remove the topic node
struct Node* curr = mMQTTContext.head;
struct Node* prev;
while(curr != NULL){
// compare the current topic to the user passed topic
ret = MQTTHelperTopicMatching(curr->topicParams.topic, topic);
// if there is a match update the node pointers and remove the node
if(ret == 1){
if(curr == mMQTTContext.head){
mMQTTContext.head = curr->next;
}
else{
prev->next = curr->next;
}
free(curr->topicParams.topic);
free(curr);
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return ret;
}
prev = curr;
curr = curr->next;
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
}
LOG_ERROR("topic does not exist\r\n");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
int MQTT_IF_Publish(MQTTClient_Handle mqttClientParams, char* topic, char* payload, unsigned short payloadLen, int flags)
{
pthread_mutex_lock(mMQTTContext.moduleMutex);
if(mMQTTContext.moduleState != MQTT_STATE_CONNECTED){
LOG_ERROR("not connected to broker\r\n");
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return -1;
}
pthread_mutex_unlock(mMQTTContext.moduleMutex);
return MQTTClient_publish(mqttClientParams,
(char*)topic,
strlen((char*)topic),
(char*)payload,
payloadLen,
flags);
}

142
src/mqtt/mqtt_if.h Normal file
View File

@ -0,0 +1,142 @@
/*
* mqtt_module.h
*
* Created on: Jan 21, 2020
* Author: a0227533
*/
#ifndef MQTT_IF_H_
#define MQTT_IF_H_
#include <ti/net/mqtt/mqttclient.h>
#define MQTTCLIENT_MAX_SIMULTANEOUS_SUB_TOPICS 4
// MQTT events for event callback
enum
{
MQTT_EVENT_CONNACK,
MQTT_EVENT_SUBACK,
MQTT_EVENT_PUBACK,
MQTT_EVENT_UNSUBACK,
MQTT_EVENT_SERVER_DISCONNECT,
MQTT_EVENT_CLIENT_DISCONNECT,
MQTT_EVENT_DESTROY,
MQTT_EVENT_MAX
};
typedef void (*MQTT_IF_TopicCallback_f)(char* topic, char* payload);
typedef void (*MQTT_IF_EventCallback_f)(int32_t event);
typedef struct MQTT_IF_ClientParams
{
char *clientID;
char *username;
char *password;
uint16_t keepaliveTime;
bool cleanConnect;
bool mqttMode31; // false 3.1.1 (default) : true 3.1
bool blockingSend;
MQTTClient_Will *willParams;
} MQTT_IF_ClientParams_t;
typedef struct MQTT_IF_initParams
{
unsigned int stackSize;
uint8_t threadPriority;
} MQTT_IF_InitParams_t;
/**
\brief Create the infrastructure for the MQTT_IF (mqtt interface) module
\param[in] initParams: parameters to set stack size and thread priority for module
\return Success 0 or Failure -1
\sa MQTT_IF_Deinit()
*/
int MQTT_IF_Init(MQTT_IF_InitParams_t initParams);
/**
\brief Destroys the infrastructure created from calling MQTT_IF_Init
\param[in] mqttClientHandle: handle for the mqtt client module instance
\return Success 0 or Failure -1
\sa MQTT_IF_Init()
*/
int MQTT_IF_Deinit();
/**
\brief Connect will set all client and connection parameters and initiate a connection to the broker.
It will also register the event callback defined in the user's application and the create an
internal context thread for the internal MQTT library
\param[in] mqttClientParams: params for the mqtt client parameters
\param[in] mqttConnParams: params for the mqtt connection parameters
\param[in] mqttCB: the callback that is registered when for MQTT operation events (e.g. CONNACK, SUBACK...)
\return Success 0 or Failure -1
\sa MQTT_IF_Disconnect()
*/
MQTTClient_Handle MQTT_IF_Connect(MQTT_IF_ClientParams_t mqttClientParams, MQTTClient_ConnParams mqttConnParams, MQTT_IF_EventCallback_f mqttCB);
/**
\brief Instructs the internal MQTT library to close the MQTT connection to the broker
\param[in] mqttClientHandle: handle for the mqtt client module instance
\return Success 0 or Failure -1
\sa MQTT_IF_Connect()
*/
int MQTT_IF_Disconnect(MQTTClient_Handle mqttClientHandle);
/**
\brief Subscribes to the topics specified by the caller in subscriptionInfo. Topic subscriptions are agnostic to the
\ connection status. Meaning if you subscribe to topics then disconnect, the MQTT_IF module will still hold the topics
\ so on re-connect the original topics are subscribed to again automatically.
\param[in] mqttClientHandle: handle for the mqtt client module instance
\param[in] subscriptionInfo: data structure containing all the data required to subscribe
\param[in] numOfTopics: number of topics stored in subscriptionInfo
\return Success 0 or Failure -1
\sa MQTT_IF_Unsubscribe()
*/
int MQTT_IF_Subscribe(MQTTClient_Handle mqttClientHandle, char* topic, unsigned int qos, MQTT_IF_TopicCallback_f topicCB);
/**
\brief Unsubscribes to the topics specified by the caller in subscriptionInfo
\param[in] mqttClientHandle: handle for the mqtt client module instance
\param[in] subscriptionInfo: data structure containing all the data required to subscribe
\param[in] numOfTopics: number of topics stored in subscriptionInfo
\return Success 0 or Failure -1
\sa MQTT_IF_Subscribe()
*/
int MQTT_IF_Unsubscribe(MQTTClient_Handle mqttClientHandle, char* topic);
/**
\brief Publishes to the topic specified by the user
\param[in] mqttClientHandle: handle for the mqtt client module instance
\param[in] topic: topic user wants to publish to
\param[in] payload: payload to publish to topic
\param[in] payloadLen: length of payload passed by the user
\param[in] flags QOS define MQTT_PUBLISH_QOS_0, MQTT_PUBLISH_QOS_1 or MQTT_PUBLISH_QOS_2
use MQTT_PUBLISH_RETAIN is message should be retained
\return Success 0 or Failure -1
*/
//\param[in] flags QOS define MQTT_PUBLISH_QOS_0, MQTT_PUBLISH_QOS_1 or MQTT_PUBLISH_QOS_2
//use MQTT_PUBLISH_RETAIN if message should be retained
int MQTT_IF_Publish(MQTTClient_Handle mqttClientHandle, char* topic, char* payload, unsigned short payloadLen, int flags);
#endif /* MQTT_IF_H_ */

852
src/network/network_if.c Normal file
View File

@ -0,0 +1,852 @@
/*
* Copyright (c) 2016, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//*****************************************************************************
// network_if.c
//
// Networking interface functions for CC32xx device
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup common_interface
//! @{
//
//*****************************************************************************
/* Standard includes */
#include <string.h>
#include <stdlib.h>
/* Kernel (Non OS/Free-RTOS/TI-RTOS) includes */
#include <pthread.h>
#include <mqueue.h>
#include <unistd.h>
/* Simplelink includes */
#include <ti/drivers/net/wifi/simplelink.h>
/* Common interface includes */
#include "network_if.h"
#include "../debug/uart_term.h"
//*****************************************************************************
// LOCAL DEFINES
//*****************************************************************************
/* Network App specific status/error codes which are */
/* used only in this file. */
typedef enum
{
/* Choosing this number to avoid overlap with host-driver's error codes. */
DEVICE_NOT_IN_STATION_MODE = -0x7F0,
DEVICE_NOT_IN_AP_MODE = DEVICE_NOT_IN_STATION_MODE - 1,
DEVICE_NOT_IN_P2P_MODE = DEVICE_NOT_IN_AP_MODE - 1,
STATUS_CODE_MAX = -0xBB8
} e_NetAppStatusCodes;
//*****************************************************************************
// GLOBAL VARIABLES
//*****************************************************************************
/* Station IP address */
unsigned long g_ulStaIp = 0;
/* Network Gateway IP address */
unsigned long g_ulGatewayIP = 0;
/* Connection SSID */
unsigned char g_ucConnectionSSID[SL_WLAN_SSID_MAX_LENGTH + 1];
/* Connection BSSID */
unsigned char g_ucConnectionBSSID[SL_WLAN_BSSID_LENGTH ];
/* SimpleLink Status */
volatile unsigned long g_ulStatus = 0;
/* Connection time delay index */
volatile unsigned short g_usConnectIndex;
//*****************************************************************************
// SimpleLink Asynchronous Event Handlers -- Start
//*****************************************************************************
void SimpleLinkHttpServerEventHandler(
SlNetAppHttpServerEvent_t *pSlHttpServerEvent,
SlNetAppHttpServerResponse_t *
pSlHttpServerResponse)
{
}
void SimpleLinkNetAppRequestEventHandler(SlNetAppRequest_t *pNetAppRequest,
SlNetAppResponse_t *pNetAppResponse)
{
}
void SimpleLinkNetAppRequestMemFreeEventHandler(uint8_t *buffer)
{
}
//*****************************************************************************
//!
//! On Successful completion of Wlan Connect, This function triggers connection
//! status to be set.
//!
//! \param[in] pSlWlanEvent - pointer indicating Event type
//!
//! \return None
//!
//*****************************************************************************
void SimpleLinkWlanEventHandler(SlWlanEvent_t *pSlWlanEvent)
{
SlWlanEventDisconnect_t* pEventData = NULL;
switch(pSlWlanEvent->Id)
{
case SL_WLAN_EVENT_CONNECT:
SET_STATUS_BIT(g_ulStatus, STATUS_BIT_CONNECTION);
memcpy(g_ucConnectionSSID, pSlWlanEvent->Data.Connect.SsidName,
pSlWlanEvent->Data.Connect.SsidLen);
memcpy(g_ucConnectionBSSID, pSlWlanEvent->Data.Connect.Bssid,
SL_WLAN_BSSID_LENGTH);
UART_PRINT(
"[WLAN EVENT] STA Connected to the AP: %s , BSSID: "
"%x:%x:%x:%x:%x:%x\n\r", g_ucConnectionSSID,
g_ucConnectionBSSID[0], g_ucConnectionBSSID[1],
g_ucConnectionBSSID[2],
g_ucConnectionBSSID[3], g_ucConnectionBSSID[4],
g_ucConnectionBSSID[5]);
break;
case SL_WLAN_EVENT_DISCONNECT:
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_CONNECTION);
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_IP_ACQUIRED);
pEventData = &pSlWlanEvent->Data.Disconnect;
/* If the user has initiated 'Disconnect' request, 'reason_code' */
/* is SL_WLAN_DISCONNECT_USER_INITIATED */
if(SL_WLAN_DISCONNECT_USER_INITIATED == pEventData->ReasonCode)
{
UART_PRINT("Device disconnected from the AP on application's "
"request \n\r");
}
else
{
UART_PRINT("Device disconnected from the AP on an ERROR..!! \n\r");
}
break;
case SL_WLAN_EVENT_STA_ADDED:
/* when device is in AP mode and any client connects to it. */
SET_STATUS_BIT(g_ulStatus, STATUS_BIT_CONNECTION);
break;
case SL_WLAN_EVENT_STA_REMOVED:
/* when device is in AP mode and any client disconnects from it. */
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_CONNECTION);
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_IP_LEASED);
break;
default:
UART_PRINT("[WLAN EVENT] Unexpected event %d\n\r", pSlWlanEvent->Id);
break;
}
}
//*****************************************************************************
//
//! The Function Handles the Fatal errors
//!
//! \param[in] slFatalErrorEvent - Pointer to Fatal Error Event info
//!
//! \return None
//!
//*****************************************************************************
void SimpleLinkFatalErrorEventHandler(SlDeviceFatal_t *slFatalErrorEvent)
{
switch(slFatalErrorEvent->Id)
{
case SL_DEVICE_EVENT_FATAL_DEVICE_ABORT:
UART_PRINT(
"[ERROR] - FATAL ERROR: Abort NWP event detected: "
"AbortType=%d, AbortData=0x%x\n\r",
slFatalErrorEvent->Data.DeviceAssert.Code,
slFatalErrorEvent->Data.DeviceAssert.Value);
break;
case SL_DEVICE_EVENT_FATAL_DRIVER_ABORT:
UART_PRINT("[ERROR] - FATAL ERROR: Driver Abort detected. \n\r");
break;
case SL_DEVICE_EVENT_FATAL_NO_CMD_ACK:
UART_PRINT(
"[ERROR] - FATAL ERROR: No Cmd Ack detected "
"[cmd opcode = 0x%x] \n\r",
slFatalErrorEvent->Data.NoCmdAck.Code);
break;
case SL_DEVICE_EVENT_FATAL_SYNC_LOSS:
UART_PRINT("[ERROR] - FATAL ERROR: Sync loss detected n\r");
break;
case SL_DEVICE_EVENT_FATAL_CMD_TIMEOUT:
UART_PRINT(
"[ERROR] - FATAL ERROR: Async event timeout detected "
"[event opcode =0x%x] \n\r",
slFatalErrorEvent->Data.CmdTimeout.Code);
break;
default:
UART_PRINT("[ERROR] - FATAL ERROR: Unspecified error detected \n\r");
break;
}
}
//*****************************************************************************
//
//! This function handles network events such as IP acquisition, IP leased, IP
//! released etc.
//!
//! \param[in] pNetAppEvent - Pointer to NetApp Event Info
//!
//! \return None
//!
//*****************************************************************************
void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent)
{
switch(pNetAppEvent->Id)
{
case SL_NETAPP_EVENT_IPV4_ACQUIRED:
case SL_NETAPP_EVENT_IPV6_ACQUIRED:
SET_STATUS_BIT(g_ulStatus, STATUS_BIT_IP_ACQUIRED);
UART_PRINT("[NETAPP EVENT] IP acquired by the device\n\r");
break;
case SL_NETAPP_EVENT_DHCPV4_LEASED:
SET_STATUS_BIT(g_ulStatus, STATUS_BIT_IP_LEASED);
g_ulStaIp = (pNetAppEvent)->Data.IpLeased.IpAddress;
UART_PRINT("[NETAPP EVENT] IP Leased to Client: IP=%d.%d.%d.%d , ",
SL_IPV4_BYTE(g_ulStaIp,
3),
SL_IPV4_BYTE(g_ulStaIp,
2),
SL_IPV4_BYTE(g_ulStaIp, 1), SL_IPV4_BYTE(g_ulStaIp, 0));
break;
case SL_NETAPP_EVENT_DHCPV4_RELEASED:
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_IP_LEASED);
UART_PRINT("[NETAPP EVENT] IP Released for Client: "
"IP=%d.%d.%d.%d , ", SL_IPV4_BYTE(g_ulStaIp,
3),
SL_IPV4_BYTE(g_ulStaIp,
2),
SL_IPV4_BYTE(g_ulStaIp, 1), SL_IPV4_BYTE(g_ulStaIp, 0));
break;
default:
UART_PRINT("[NETAPP EVENT] Unexpected event [0x%x] \n\r",
pNetAppEvent->Id);
break;
}
}
//*****************************************************************************
//
//! This function handles resource request
//!
//! \param[in] pNetAppRequest - Contains the resource requests
//! \param[in] pNetAppResponse - Should be filled by the user with the
//! relevant response information
//!
//! \return None
//!
//*****************************************************************************
void SimpleLinkNetAppRequestHandler(SlNetAppRequest_t *pNetAppRequest,
SlNetAppResponse_t *pNetAppResponse)
{
/* Unused in this application */
}
//*****************************************************************************
//
//! This function handles HTTP server events
//!
//! \param[in] pServerEvent - Contains the relevant event information
//! \param[in] pServerResponse - Should be filled by the user with the
//! relevant response information
//!
//! \return None
//!
//****************************************************************************
void SimpleLinkHttpServerCallback(SlNetAppHttpServerEvent_t *pHttpEvent,
SlNetAppHttpServerResponse_t *pHttpResponse)
{
/* Unused in this application */
}
//*****************************************************************************
//
//! This function handles General Events
//!
//! \param[in] pDevEvent - Pointer to General Event Info
//!
//! \return None
//!
//*****************************************************************************
void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent)
{
/* Most of the general errors are not FATAL. are to be handled */
/* appropriately by the application. */
UART_PRINT("[GENERAL EVENT] - ID=[%d] Sender=[%d]\n\n",
pDevEvent->Data.Error.Code,
pDevEvent->Data.Error.Source);
}
//*****************************************************************************
//
//! This function handles socket events indication
//!
//! \param[in] pSock - Pointer to Socket Event Info
//!
//! \return None
//!
//*****************************************************************************
void SimpleLinkSockEventHandler(SlSockEvent_t *pSock)
{
/* This application doesn't work w/ socket - Events are not expected */
switch(pSock->Event)
{
case SL_SOCKET_TX_FAILED_EVENT:
switch(pSock->SocketAsyncEvent.SockTxFailData.Status)
{
case SL_ERROR_BSD_ECLOSE:
UART_PRINT(
"[SOCK ERROR] - close socket (%d) operation "
"failed to transmit all queued packets\n\r",
pSock->SocketAsyncEvent.SockTxFailData.Sd);
break;
default:
UART_PRINT(
"[SOCK ERROR] - TX FAILED : socket %d , "
"reason (%d) \n\n",
pSock->SocketAsyncEvent.SockTxFailData.Sd,
pSock->SocketAsyncEvent.SockTxFailData.Status);
break;
}
break;
case SL_SOCKET_ASYNC_EVENT:
{
UART_PRINT("[SOCK ERROR] an event received on socket %d\r\n",
pSock->SocketAsyncEvent.SockAsyncData.Sd);
switch(pSock->SocketAsyncEvent.SockAsyncData.Type)
{
case SL_SSL_NOTIFICATION_CONNECTED_SECURED:
UART_PRINT("[SOCK ERROR] SSL handshake done");
break;
case SL_SSL_NOTIFICATION_HANDSHAKE_FAILED:
UART_PRINT("[SOCK ERROR] SSL handshake failed with error %d\r\n",
pSock->SocketAsyncEvent.SockAsyncData.Val);
break;
case SL_SSL_ACCEPT:
UART_PRINT(
"[SOCK ERROR] Recoverable error occurred "
"during the handshake %d\r\n",
pSock->SocketAsyncEvent.SockAsyncData.Val);
break;
case SL_OTHER_SIDE_CLOSE_SSL_DATA_NOT_ENCRYPTED:
UART_PRINT("[SOCK ERROR] Other peer terminated the SSL layer.\r\n");
break;
case SL_SSL_NOTIFICATION_WRONG_ROOT_CA:
UART_PRINT("[SOCK ERROR] Used wrong CA to verify the peer.\r\n");
break;
default:
break;
}
break;
}
default:
UART_PRINT("[SOCK EVENT] - Unexpected Event [%x0x]\n\n", pSock->Event);
break;
}
}
//*****************************************************************************
// SimpleLink Asynchronous Event Handlers -- End
//*****************************************************************************
//*****************************************************************************
//
//! This function initializes the application variables
//!
//! \param None
//!
//! \return 0 on success, negative error-code on error
//
//*****************************************************************************
void InitializeAppVariables(void)
{
g_ulStatus = 0;
g_ulStaIp = 0;
g_ulGatewayIP = 0;
memset(g_ucConnectionSSID, 0, sizeof(g_ucConnectionSSID));
memset(g_ucConnectionBSSID, 0, sizeof(g_ucConnectionBSSID));
}
//*****************************************************************************
//
//! The function initializes a CC32xx device and triggers it to start operation
//!
//! \param[in] uiMode - device mode in which device will be configured
//!
//! \return 0 : success, -ve : failure
//
//*****************************************************************************
long Network_IF_InitDriver(uint32_t uiMode)
{
long lRetVal = -1;
/* Reset CC32xx Network State Machine */
InitializeAppVariables();
/* Following function configure the device to default state by cleaning */
/* the persistent settings stored in NVMEM (viz. connection profiles */
/* & policies, power policy etc) Applications may choose to skip this */
/* step if the developer is sure that the device is in its default state */
/* at start of application. Note that all profiles and persistent */
/* settings that were done on the device will be lost. */
lRetVal = sl_Start(NULL, NULL, NULL);
if(lRetVal < 0)
{
UART_PRINT("Failed to start the device \n\r");
LOOP_FOREVER();
}
switch(lRetVal)
{
case ROLE_STA:
UART_PRINT("Device came up in Station mode\n\r");
break;
case ROLE_AP:
UART_PRINT("Device came up in Access-Point mode\n\r");
break;
case ROLE_P2P:
UART_PRINT("Device came up in P2P mode\n\r");
break;
default:
UART_PRINT("Error:unknown mode\n\r");
break;
}
if(uiMode != lRetVal)
{
UART_PRINT("Switching Networking mode on application request\n\r");
/* Switch to AP role and restart */
lRetVal = sl_WlanSetMode(uiMode);
ASSERT_ON_ERROR(lRetVal);
lRetVal = sl_Stop(SL_STOP_TIMEOUT);
lRetVal = sl_Start(0, 0, 0);
ASSERT_ON_ERROR(lRetVal);
if(lRetVal == uiMode)
{
switch(lRetVal)
{
case ROLE_STA:
UART_PRINT("Device came up in Station mode\n\r");
break;
case ROLE_AP:
UART_PRINT("Device came up in Access-Point mode\n\r");
/* If the device is in AP mode, we need to wait for this */
/* event before doing anything. */
while(!IS_IP_ACQUIRED(g_ulStatus))
{
usleep(1000);
}
break;
case ROLE_P2P:
UART_PRINT("Device came up in P2P mode\n\r");
break;
default:
UART_PRINT("Error:unknown mode\n\r");
break;
}
}
else
{
UART_PRINT("could not configure correct networking mode\n\r");
LOOP_FOREVER();
}
}
else
{
if(lRetVal == ROLE_AP)
{
while(!IS_IP_ACQUIRED(g_ulStatus))
{
usleep(1000);
}
}
}
return(0);
}
//*****************************************************************************
//
//! The function de-initializes a CC32xx device
//!
//! \param None
//!
//! \return On success, zero is returned. On error, other
//
//*****************************************************************************
long Network_IF_DeInitDriver(void)
{
long lRetVal = -1;
UART_PRINT("SL Disconnect...\n\r");
/* Disconnect from the AP */
lRetVal = Network_IF_DisconnectFromAP();
/* Stop the simplelink host */
sl_Stop(SL_STOP_TIMEOUT);
/* Reset the state to uninitialized */
Network_IF_ResetMCUStateMachine();
return(lRetVal);
}
//*****************************************************************************
//
//! Connect to an Access Point using the specified SSID
//!
//! \param[in] pcSsid - is a string of the AP's SSID
//! \param[in] SecurityParams - is Security parameter for AP
//!
//! \return On success, zero is returned. On error, -ve value is returned
//
//*****************************************************************************
long Network_IF_ConnectAP(char *pcSsid,
SlWlanSecParams_t SecurityParams)
{
char acCmdStore[128];
unsigned short usConnTimeout;
unsigned char ucRecvdAPDetails;
long lRetVal;
unsigned long ulIP = 0;
unsigned long ulSubMask = 0;
unsigned long ulDefGateway = 0;
unsigned long ulDns = 0;
g_usConnectIndex = 0;
/* Disconnect from the AP */
Network_IF_DisconnectFromAP();
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_CONNECTION);
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_IP_ACQUIRED);
/* Continue only if SSID is not empty */
if(pcSsid != NULL)
{
/* This triggers the CC32xx to connect to a specific AP. */
lRetVal =
sl_WlanConnect((signed char *) pcSsid, strlen((const char *) pcSsid),
NULL, &SecurityParams, NULL);
ASSERT_ON_ERROR(lRetVal);
/* Wait for ~10 sec to check if connection to desire AP succeeds */
while(g_usConnectIndex < 10)
{
sleep(1);
if(IS_CONNECTED(g_ulStatus) && IS_IP_ACQUIRED(g_ulStatus))
{
break;
}
g_usConnectIndex++;
}
}
else
{
UART_PRINT("Empty SSID, Could not connect\n\r");
return(-1);
}
/* Check and loop until AP connection successful, else ask new AP SSID */
while(!(IS_CONNECTED(g_ulStatus)) || !(IS_IP_ACQUIRED(g_ulStatus)))
{
/* Disconnect the previous attempt */
Network_IF_DisconnectFromAP();
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_CONNECTION);
CLR_STATUS_BIT(g_ulStatus, STATUS_BIT_IP_ACQUIRED);
UART_PRINT("Device could not connect to %s\n\r", pcSsid);
do
{
ucRecvdAPDetails = 0;
UART_PRINT("\n\r\n\rPlease enter the AP(open) SSID name # ");
/* Get the AP name to connect over the UART */
lRetVal = GetCmd(acCmdStore, sizeof(acCmdStore));
if(lRetVal > 0)
{
/* remove start/end spaces if any */
lRetVal = TrimSpace(acCmdStore);
if(lRetVal)
{
/* Parse the AP name */
strncpy(pcSsid, acCmdStore, lRetVal);
if(pcSsid != NULL)
{
ucRecvdAPDetails = 1;
pcSsid[lRetVal] = '\0';
}
}
}
}
while(ucRecvdAPDetails == 0);
/* Set Security Parameters to OPEN security type. */
SecurityParams.Key = (signed char *) "";
SecurityParams.KeyLen = 0;
SecurityParams.Type = SL_WLAN_SEC_TYPE_OPEN;
UART_PRINT("\n\rTrying to connect to AP: %s ...\n\r", pcSsid);
/* Get the current timer tick and setup the timeout accordingly. */
usConnTimeout = g_usConnectIndex + 15;
/* This triggers the CC32xx to connect to specific AP. */
lRetVal =
sl_WlanConnect((signed char *) pcSsid, strlen((const char *) pcSsid),
NULL, &SecurityParams,NULL);
ASSERT_ON_ERROR(lRetVal);
/* Wait ~10 sec to check if connection to specified AP succeeds */
while(!(IS_CONNECTED(g_ulStatus)) || !(IS_IP_ACQUIRED(g_ulStatus)))
{
sleep(1);
if(g_usConnectIndex >= usConnTimeout)
{
break;
}
g_usConnectIndex++;
}
}
/* Put message on UART */
UART_PRINT("\n\rDevice has connected to %s\n\r", pcSsid);
/* Get IP address */
lRetVal = Network_IF_IpConfigGet(&ulIP, &ulSubMask, &ulDefGateway, &ulDns);
ASSERT_ON_ERROR(lRetVal);
/* Send the information */
UART_PRINT("Device IP Address is %d.%d.%d.%d \n\r\n\r",
SL_IPV4_BYTE(ulIP, 3), SL_IPV4_BYTE(ulIP, 2), SL_IPV4_BYTE(ulIP,
1),
SL_IPV4_BYTE(ulIP, 0));
return(0);
}
//*****************************************************************************
//
//! Disconnects from an Access Point
//!
//! \param none
//!
//! \return 0 disconnected done, other already disconnected
//
//*****************************************************************************
long Network_IF_DisconnectFromAP(void)
{
long lRetVal = 0;
if(IS_CONNECTED(g_ulStatus))
{
lRetVal = sl_WlanDisconnect();
if(0 == lRetVal)
{
while(IS_CONNECTED(g_ulStatus))
{
usleep(1000);
}
return(lRetVal);
}
else
{
return(lRetVal);
}
}
else
{
return(lRetVal);
}
}
//*****************************************************************************
//
//! Get the IP Address of the device.
//!
//! \param[in] pulIP - IP Address of Device
//! \param[in] pulSubnetMask - Subnetmask of Device
//! \param[in] pulDefaultGateway - Default Gateway value
//! \param[in] pulDNSServer - DNS Server
//!
//! \return On success, zero is returned. On error, -1 is returned
//
//*****************************************************************************
long Network_IF_IpConfigGet(unsigned long *pulIP,
unsigned long *pulSubnetMask,
unsigned long *pulDefaultGateway,
unsigned long *pulDNSServer)
{
unsigned short usDHCP = 0;
long lRetVal = -1;
unsigned short len = sizeof(SlNetCfgIpV4Args_t);
SlNetCfgIpV4Args_t ipV4 = { 0 };
/* get network configuration */
lRetVal =
sl_NetCfgGet(SL_NETCFG_IPV4_STA_ADDR_MODE, &usDHCP, &len,
(unsigned char *) &ipV4);
ASSERT_ON_ERROR(lRetVal);
*pulIP = ipV4.Ip;
*pulSubnetMask = ipV4.IpMask;
*pulDefaultGateway = ipV4.IpGateway;
*pulDefaultGateway = ipV4.IpDnsServer;
return(lRetVal);
}
//*****************************************************************************
//
//! This function obtains the server IP address using a DNS lookup
//!
//! \param[in] pcHostName The server hostname
//! \param[out] pDestinationIP This parameter is filled with host IP address
//!
//! \return On success, +ve value is returned. On error, -ve value is returned
//
//*****************************************************************************
long Network_IF_GetHostIP(char* pcHostName,
unsigned long * pDestinationIP)
{
long lStatus = 0;
lStatus =
sl_NetAppDnsGetHostByName((signed char *) pcHostName, strlen(
pcHostName), pDestinationIP, SL_AF_INET);
ASSERT_ON_ERROR(lStatus);
UART_PRINT("Get Host IP succeeded.\n\rHost: %s IP: %d.%d.%d.%d \n\r\n\r",
pcHostName, SL_IPV4_BYTE(*pDestinationIP,
3), SL_IPV4_BYTE(*pDestinationIP,
2),
SL_IPV4_BYTE(*pDestinationIP, 1),
SL_IPV4_BYTE(*pDestinationIP, 0));
return(lStatus);
}
//*****************************************************************************
//
//! Reset state from the state machine
//!
//! \param None
//!
//! \return none
//!
//*****************************************************************************
void Network_IF_ResetMCUStateMachine()
{
g_ulStatus = 0;
}
//*****************************************************************************
//
//! Return the current state bits
//!
//! \param None
//!
//! \return none
//!
//
//*****************************************************************************
unsigned long Network_IF_CurrentMCUState()
{
return(g_ulStatus);
}
//*****************************************************************************
//
//! Sets a state from the state machine
//!
//! \param[in] cStat - Status of State Machine defined in e_StatusBits
//!
//! \return none
//!
//*****************************************************************************
void Network_IF_SetMCUMachineState(char cStat)
{
SET_STATUS_BIT(g_ulStatus, cStat);
}
//*****************************************************************************
//
//! Unsets a state from the state machine
//!
//! \param[in] cStat - Status of State Machine defined in e_StatusBits
//!
//! \return none
//!
//*****************************************************************************
void Network_IF_UnsetMCUMachineState(char cStat)
{
CLR_STATUS_BIT(g_ulStatus, cStat);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************

176
src/network/network_if.h Normal file
View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 2016, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//*****************************************************************************
// network_if.h
//
// Networking interface macro and function prototypes for CC32xx device
//
//*****************************************************************************
#ifndef __NETWORK_IF__H__
#define __NETWORK_IF__H__
//*****************************************************************************
//
// If building with a C++ compiler, make all of the definitions in this header
// have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif
/* Simplelink includes */
#include <ti/drivers/net/wifi/simplelink.h>
/* Values for below macros shall be modified as per access-point(AP) */
/* properties SimpleLink device will connect to following AP when application */
/* is executed. */
/* AP SSID */
#define SSID_NAME "SPN24"
/* Security type (OPEN or WEP or WPA) */
#define SECURITY_TYPE SL_WLAN_SEC_TYPE_OPEN
/* Password of the secured AP */
#define SECURITY_KEY ""
#define SSID_AP_MODE "<ap-ssid>"
#define SEC_TYPE_AP_MODE SL_WLAN_SEC_TYPE_OPEN
#define PASSWORD_AP_MODE ""
/* Loop forever, user can change it as per application's requirement */
#define LOOP_FOREVER() \
{ \
while(1) {; } \
}
/* check the error code and handle it */
#define ASSERT_ON_ERROR(error_code) \
{ \
if(error_code < 0) \
{ \
ERR_PRINT(error_code); \
return error_code; \
} \
}
#define SL_STOP_TIMEOUT 200
/* Status bits - used to set/reset the corresponding bits in given a variable */
typedef enum
{
/* If this bit is set: Network Processor is powered up */
STATUS_BIT_NWP_INIT = 0,
/* If this bit is set: the device is connected to the AP or client is */
/* connected to device (AP) */
STATUS_BIT_CONNECTION,
/* If this bit is set: the device has leased IP to any connected client. */
STATUS_BIT_IP_LEASED,
/* If this bit is set: the device has acquired an IP */
STATUS_BIT_IP_ACQUIRED,
/* If this bit is set: the SmartConfiguration process is started from */
/* SmartConfig app */
STATUS_BIT_SMARTCONFIG_START,
/* If this bit is set: the device (P2P mode) found any p2p-device in scan */
STATUS_BIT_P2P_DEV_FOUND,
/* If this bit is set: the device (P2P mode) found any p2p-negotiation */
/* request */
STATUS_BIT_P2P_REQ_RECEIVED,
/* If this bit is set: the device(P2P mode) connection to client (or */
/* reverse way) is failed */
STATUS_BIT_CONNECTION_FAILED,
/* If this bit is set: the device has completed the ping operation */
STATUS_BIT_PING_DONE,
/* If this bit is set: the device has acquired an IPv6 address. */
STATUS_BIT_IPV6L_ACQUIRED,
/* If this bit is set: the device has acquired an IPv6 address. */
STATUS_BIT_IPV6G_ACQUIRED,
STATUS_BIT_AUTHENTICATION_FAILED,
STATUS_BIT_RESET_REQUIRED,
}e_StatusBits;
#define CLR_STATUS_BIT_ALL(status_variable) (status_variable = 0)
#define SET_STATUS_BIT(status_variable, bit) (status_variable |= (1 << (bit)))
#define CLR_STATUS_BIT(status_variable, bit) (status_variable &= ~(1 << (bit)))
#define CLR_STATUS_BIT_ALL(status_variable) (status_variable = 0)
#define GET_STATUS_BIT(status_variable, bit) (0 != \
(status_variable & (1 << (bit))))
#define IS_CONNECTED(status_variable) GET_STATUS_BIT( \
status_variable, \
STATUS_BIT_CONNECTION)
#define IS_IP_ACQUIRED(status_variable) GET_STATUS_BIT( \
status_variable, \
STATUS_BIT_IP_ACQUIRED)
//*****************************************************************************
// APIs
//*****************************************************************************
long Network_IF_InitDriver(uint32_t uiMode);
long Network_IF_DeInitDriver(void);
long Network_IF_ConnectAP(char * pcSsid,
SlWlanSecParams_t SecurityParams);
long Network_IF_DisconnectFromAP();
long Network_IF_IpConfigGet(unsigned long *aucIP,
unsigned long *aucSubnetMask,
unsigned long *aucDefaultGateway,
unsigned long *aucDNSServer);
long Network_IF_GetHostIP(char* pcHostName,
unsigned long * pDestinationIP);
unsigned long Network_IF_CurrentMCUState(void);
void Network_IF_UnsetMCUMachineState(char stat);
void Network_IF_SetMCUMachineState(char stat);
void Network_IF_ResetMCUStateMachine(void);
//*****************************************************************************
//
// Mark the end of the C bindings section for C++ compilers.
//
//*****************************************************************************
#ifdef __cplusplus
}
#endif
#endif // __NETWORK_IF__H__