Trigger link on xdk
Answer
1/12/18 2:21 PM

I currently have a code that sends data to thingspeak to get a live monitoring of data.

I need help with a code that i can add on to my current code, that will store data to an external sd card stored on the xdk then read the data constantly, and if the data falls below certain value(e.g. luxData > 50), it will open a link.

Note: The link is just a simple link that triggers desktop notifications. So it will alert users when it requries attention.

 

Here's my current code

/*
* Licensee agrees that the example code provided to Licensee has been developed and released by Bosch solely as an example to be used as a potential reference for Licensee�s application development. 
* Fitness and suitability of the example code for any use within Licensee�s applications need to be verified by Licensee on its own authority by taking appropriate state of the art actions and measures (e.g. by means of quality assurance measures).
* Licensee shall be responsible for conducting the development of its applications as well as integration of parts of the example code into such applications, taking into account the state of the art of technology and any statutory regulations and provisions applicable for such applications. Compliance with the functional system requirements and testing there of (including validation of information/data security aspects and functional safety) and release shall be solely incumbent upon Licensee. 
* For the avoidance of doubt, Licensee shall be responsible and fully liable for the applications and any distribution of such applications into the market.
* 
* 
* Redistribution and use in source and binary forms, with or without 
* modification, are permitted provided that the following conditions are 
* met:
* 
*     (1) Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer. 
* 
*     (2) 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.  
*     
*     (3)The name of the author may not be used to
*     endorse or promote products derived from this software without
*     specific prior written permission.
* 
*  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*----------------------------------------------------------------------------*/

/**
* @ingroup APPS_LIST
*
* @defgroup HTTP_EXAMPLE_CLIENT HttpExampleClient
* @{
*
* @brief Demo application for communicating with the HTTP to GET and POST content on the Server and demonstrate the use of custom headers.
*
* @details This example shows how to use the network stack to perform an HTTP Client Request.
*
* The example connects to the server <a href="http://www.posttestserver.com">www.posttestserver.com</a> and establishes a connection to the server.
*
* To view your posts, browse to the year, month, day, time and directory name XDK:
* <a href="http://posttestserver.com/data/">http://posttestserver.com/data/</a> This means all posts are visible to everybody so don't test with secure credentials.
* There you can see your custem heders as well.
*
* You need to add your WLAN-Credatials in \ref HttpExampleClient.h\n
* When running the program keep the USB plugged in to the PC. You can see in the consol output of the XDK-Workbench the content of the GET request.
*
* @file HttpExampleClient.c
**/

/* module includes ********************************************************** */

/* own header files */
#include "XDKAppInfo.h"

#undef BCDS_MODULE_ID  /* Module ID define before including Basics package*/
#define BCDS_MODULE_ID XDK_APP_MODULE_ID_HTTP_EXAMPLE_CLIENT

/* own header files */
#include "HttpExampleClient.h"

/* system header files */
#include <stdio.h>

/* additional interface header files */
#include "BCDS_WlanConnect.h"
#include "BCDS_NetworkConfig.h"
#include "BCDS_CmdProcessor.h"
#include <Serval_HttpClient.h>
#include <Serval_Network.h>
#include "PAL_socketMonitor_ih.h"
#include "PAL_initialize_ih.h"
#include "BCDS_LightSensor.h"
#include "XdkSensorHandle.h"

/* constant definitions ***************************************************** */

/* local variables ********************************************************** */

/* global variables ********************************************************* */
static xTimerHandle connectTimerHandle; /**< variable to store timer handle*/
Ip_Address_T destAddr = UINT32_C(0);/*< variable to store the Ip address of the server */
static uint32_t intialOffset = UINT32_C(0); /* < variable to store the offset, the first byte to be received */
static uint32_t noOfBytesRecv = UINT32_C(512); /*< variable to store the number of bytes to receive */
char const *urlPtrReq = "/post.php?dump&html&dir=XDK"; /* URL string for the http website to post the payload*/
uint8_t payload[] = "XDK Testing"; /* payload to add to a request */
uint32_t tempData = UINT32_C(0);
uint32_t luxData = UINT32_C(0);
Accelerometer_XyzData_T aData = { INT32_C(0), INT32_C(0), INT32_C(0) };

/*Application Command Processor Instance */
CmdProcessor_T *AppCmdProcessor;

/* inline functions ********************************************************* */

/* local functions ********************************************************** */

/**
 * @brief This API is called when the HTTP page
 *      Connecting to a WLAN Access point.
 *       This function connects to the required AP (SSID_NAME).
 *       The function will return once we are connected and have acquired IP address
 *   @warning
 *      If the WLAN connection fails or we don't acquire an IP address, We will be stuck in this function forever.
 *      Check whether the callback "SimpleLinkWlanEventHandler" or "SimpleLinkNetAppEventHandler" hits once the
 *      sl_WlanConnect() API called, if not check for proper GPIO pin interrupt configuration or for any other issue
 *
 * @retval     RC_OK       IP address returned successfully
 *
 * @retval     RC_PLATFORM_ERROR         Error occurred in fetching the ip address
 *
 */
static retcode_t WlanConnect(void)
{
    NetworkConfig_IpSettings_T myIpSettings;
    char ipAddress[PAL_IP_ADDRESS_SIZE] = { 0 };
    Ip_Address_T* IpaddressHex = Ip_getMyIpAddr();
    WlanConnect_SSID_T connectSSID;
    WlanConnect_PassPhrase_T connectPassPhrase;
    Retcode_T ReturnValue = (Retcode_T) RETCODE_FAILURE;
    int32_t Result = INT32_C(-1);

    if (RETCODE_OK != WlanConnect_Init())
    {
        return (RC_PLATFORM_ERROR);
    }

    printf("Connecting to %s \r\n ", WLAN_CONNECT_WPA_SSID);

    connectSSID = (WlanConnect_SSID_T) WLAN_CONNECT_WPA_SSID;
    connectPassPhrase = (WlanConnect_PassPhrase_T) WLAN_CONNECT_WPA_PASS;
    ReturnValue = NetworkConfig_SetIpDhcp(NULL);
    if (RETCODE_OK != ReturnValue)
    {
        printf("Error in setting IP to DHCP \r\n");
        return (RC_PLATFORM_ERROR);
    }
    if (RETCODE_OK == WlanConnect_WPA(connectSSID, connectPassPhrase, NULL))
    {
        ReturnValue = NetworkConfig_GetIpSettings(&myIpSettings);
        if (RETCODE_OK == ReturnValue)
        {
            *IpaddressHex = Basics_htonl(myIpSettings.ipV4);
            Result = Ip_convertAddrToString(IpaddressHex, ipAddress);
            if (Result < 0)
            {
                printf("Couldn't convert the IP address to string format \r\n ");
                return (RC_PLATFORM_ERROR);
            }
            printf("Connected to WPA network successfully \r\n ");
            printf(" Ip address of the device %s \r\n ", ipAddress);
            return (RC_OK);
        }
        else
        {
            printf("Error in getting IP settings \r\n");
            return (RC_PLATFORM_ERROR);
        }
    }
    else
    {
        return (RC_PLATFORM_ERROR);
    }

}


/**
 * @brief This API is called after the HTTP connects with the server to get the Content.
 *
 * @param[in]: callfunc
 *               The structure storing the pointer to the message handler
 * @param[in]: retcode_t
 *               The return code of the HTTP connect
 * @retval: retcode_t
 *               The return code of the callback Function
 */
static retcode_t CallbackOnSent(Callable_T *callfunc, retcode_t status)
{
    BCDS_UNUSED(callfunc);

    if (status != RC_OK)
    {
        //printf("error occurred in connecting server \r\n");
    }
    return (RC_OK);
}

/**
 * @brief This API is called after the HTTP connects with the server to post the Content.
 *
 * @param[in]: callfunc
 *               The structure storing the pointer to the message handler
 * @param[in]: retcode_t
 *               The return code of the HTTP connect
 * @retval: retcode_t
 *               The return code of the callback Function
 */
static retcode_t CallbackOnRecv(Callable_T *callfunc, retcode_t status)
{
    BCDS_UNUSED(callfunc);

    if (status != RC_OK)
    {
        //printf("error occurred in connecting server \r\n");
    }
    else
    {
        printf("Post Request Sent \r\n");
    }
    return (RC_OK);
}

/**
 * @brief API responsible to pass the payload to the requested URL
 *
 * @param[in] omsh_ptr This data structure is used hold the buffer and information needed by the serializer.
 *
 */
static retcode_t httpPayloadSerializer(
        OutMsgSerializationHandover_T *omsh_ptr)
{
    retcode_t rc = RC_OK;
    memcpy(omsh_ptr->buf_ptr, payload, strlen((char*) payload));
    omsh_ptr->len = strlen((char*) payload);

    return rc;
}


static retcode_t httpPayloadSerializer2(
        OutMsgSerializationHandover_T *omsh_ptr)
{
    retcode_t rc2 = RC_OK;
    memcpy(omsh_ptr->buf_ptr, payload, strlen((char*) payload));
    omsh_ptr->len = strlen((char*) payload);

    return rc2;
}

/**
 * @brief API responsible to internal headers have been serialized but before the header-terminating token
 *
 * @param[in] omsh_ptr This data structure is used hold the buffer and information needed by the serializer.
 *
 */
static retcode_t serializeMyHeaders(OutMsgSerializationHandover_T *omsh_ptr)
{
    retcode_t rc;
    omsh_ptr->len = 0;
    int n;
    static const char* myheader1 = "MyHeader: XDK\r\n";
    static const char* myheader2 = "MyOtherHeader: TestPurpose\r\n";

    switch (omsh_ptr->position)
    {
    case 0:
        n = strlen(myheader1);
        rc = TcpMsg_copyStaticContent(omsh_ptr, myheader1, n);
        if (rc != RC_OK)
            return rc;
        omsh_ptr->position = 1;
    case 1:
        n = strlen(myheader2);
        rc = TcpMsg_copyContentAtomic(omsh_ptr, myheader2, n);
        if (rc != RC_OK)
            return rc;
        omsh_ptr->position = 2;
    default:
        return RC_OK;
        break;
    }
}

/**
 * @brief API responsible to Post Data on html page.
 *
 * @param[in] Not used.
 *
 *
 * @param[in] Not used.
 */
static void PostContentOnWebpage(void * param1, uint32_t param2)
{
    BCDS_UNUSED(param1);
    BCDS_UNUSED(param2);
    retcode_t rc = RC_OK;
    Msg_T* msg_ptr;
    Ip_Port_T destPort = (Ip_Port_T) DEST_PORT_NUMBER;
    static Callable_T RecvCallable;
    Callable_T * Callable_pointer;
    Callable_pointer = Callable_assign(&RecvCallable, CallbackOnRecv);
    if (Callable_pointer == NULL)
    {
        printf("Failed Callable_assign\r\n ");
        return;
    }
    rc = HttpClient_initRequest(&destAddr, Ip_convertIntToPort(destPort), &msg_ptr);

    if (rc != RC_OK || msg_ptr == NULL)
    {
        //printf("Failed HttpClient_initRequest \r\n ");
        return;
    }
    HttpMsg_serializeCustomHeaders(msg_ptr, serializeMyHeaders);
    HttpMsg_setReqMethod(msg_ptr, Http_Method_Post);

    rc = HttpMsg_setReqUrl(msg_ptr, urlPtrReq);
    if (rc != RC_OK)
    {
        printf("Failed to fill message \r\n ");
        return;
    }

    /* set content type and payload */
    HttpMsg_setContentType(msg_ptr, Http_ContentType_Text_Plain);

    rc = Msg_prependPartFactory(msg_ptr, &httpPayloadSerializer);
    if (RC_OK == rc)
    {
        rc = HttpClient_pushRequest(msg_ptr, &RecvCallable,
        NULL);
        if (rc != RC_OK)
        {
            printf("Failed HttpClient_pushRequest \r\n  ");
            return;
        }
    }
    if (rc != RC_OK)
    {
        printf("Failed to Fill the payload on payloadSerializer \r\n  ");
        return;
    }
}

/**
 * @brief This API is called after downloading the HTTP page from the server
 *
 * @param[in]: HttpSession_T
 *               The pointer holding the details of the http session
 * @param[in]: Msg_T
 *               The structure storing the pointer to the message handler
 * @param[in]: retcode_t
 *               The return code of the HTTP page download
 *
 * @retval: retcode_t
 *               The return code of the HTTP connect
 *
 */
static retcode_t HttpClientResponseCallback(HttpSession_T *httpSession,
        Msg_T *msg_ptr, retcode_t status)
{
    BCDS_UNUSED(httpSession);
    retcode_t rc = status;
    uint32_t pageContentSize; /* total length of the content at the server */
    bool flag = false; /* flag to set to true if this is the last piece of the message */
    Retcode_T returnValue = RETCODE_OK;
    if (rc != RC_OK)
    {
        /* Error occurred in downloading the page */
        printf("error occurred in downloading HTML \r\n");
    }
    else if (msg_ptr == NULL)
    {
        rc = RC_HTTP_PARSER_INVALID_CONTENT_TYPE;
    }
    else
    {
        rc = HttpMsg_getRange(msg_ptr, UINT32_C(0), &pageContentSize, &flag);
        if (rc != RC_OK)
        {
            printf("Failed to Get Range \r\n ");
        }
        else
        {
            if (HttpMsg_getContentType(msg_ptr) != Http_ContentType_Text_Html)
            {
                rc = RC_HTTP_INVALID_RESPONSE;
            }
            else
            {
                char const *content_ptr = "";
                unsigned int len = UINT32_C(0);
                HttpMsg_getContent(msg_ptr, &content_ptr, &len);
                printf("GET Response Content %s \r\n", content_ptr);
                intialOffset += (len);
                /* Clear the Content Buffer */
                memset(content_ptr, UINT32_C(0), len);
                /* check if this is the last piece of the message. This parameter will also be true if the message is not fragmented.*/
/*                if (flag == true)
                {
                    printf("Page content %lu Bytes Download Completed \r\n", pageContentSize);
                    if (xTimerStop(connectTimerHandle, 0) != pdTRUE)
                    {
                        assert(false);
                    }
                    /* En-queuing to application command processor to post the content on Http page */
/*                    returnValue = CmdProcessor_enqueue(AppCmdProcessor, PostContentOnWebpage, NULL, UINT32_C(0));
                    if (RETCODE_OK != returnValue)
                    {
                        printf("En-queuing to application command processor failed \r\n");
                    }
                } */
            }
        }
    }

    if (rc != RC_OK)
    {
        printf("error occurred in downloading HTML \r\n");
    }
    return (rc);
}
/* global functions ********************************************************** */

static void initSensor(void)
{
	Retcode_T returnValue = RETCODE_FAILURE;
	returnValue = Environmental_init(xdkEnvironmental_BME280_Handle);
	returnValue = LightSensor_init(xdkLightSensor_MAX44009_Handle);
	returnValue = Accelerometer_init(xdkAccelerometers_BMA280_Handle);
	if(RETCODE_OK != returnValue)
	{
		//printf("Light Sensor initialization Failed\n\r");
	}
}

static void readSensor(xTimerHandle xTimer)
{
	(void) xTimer;

	//uint32_t milliLuxData = UINT32_C(0);
	Retcode_T returnValue = RETCODE_FAILURE;

	returnValue = Environmental_readTemperature(xdkEnvironmental_BME280_Handle,
			&tempData);
	returnValue = LightSensor_readLuxData(xdkLightSensor_MAX44009_Handle,
				&luxData);
	returnValue = Accelerometer_readXyzGValue(xdkAccelerometers_BMA280_Handle,
	&aData);

	if(RETCODE_OK == returnValue)
	{
		//printf("Light sensor data obtained in milli lux: %d \n\r",(unsigned int) milliLuxData);
	}
}

/**
 * @brief API responsible to read html page content of the client and print it on the console.
 *
 * @param[in] Not used.
 *
 *
 * @param[in] Not used.
 */

static void loop(void)
{
	if(/*read sensor data*/ < 50)
	{
		
	}
}


static void PrintWebpageContent(void * param1, uint32_t param2)
{
    BCDS_UNUSED(param1);
    BCDS_UNUSED(param2);
    retcode_t rc = RC_OK;
    Msg_T* msg_ptr;
    Ip_Port_T destPort = (Ip_Port_T) DEST_PORT_NUMBER;
    static Callable_T SentCallable;
    const char url_ptr[100]; /* URL string for the http website */
    int n = sprintf(url_ptr,"/update?key=<WRITEKEY>&field1=%d&field2=%d",tempData/1000, luxData/1000);
    Callable_T * Callable_pointer;
    Callable_pointer = Callable_assign(&SentCallable, CallbackOnSent);
    if (Callable_pointer == NULL)
    {
        printf("Failed Callable_assign\r\n ");
        return;
    }
    rc = HttpClient_initRequest(&destAddr, Ip_convertIntToPort(destPort), &msg_ptr);

    if (rc != RC_OK || msg_ptr == NULL)
    {
        //printf("Failed HttpClient_initRequest \r\n ");
        return;
    }
    HttpMsg_setRange(msg_ptr, intialOffset, noOfBytesRecv);
    HttpMsg_setReqMethod(msg_ptr, Http_Method_Get);
    rc = HttpMsg_setReqUrl(msg_ptr, url_ptr);
    if (rc != RC_OK)
    {
        printf("Failed to fill message \r\n ");
        return;
    }

    rc = HttpClient_pushRequest(msg_ptr, &SentCallable,
            HttpClientResponseCallback);
    if (rc != RC_OK)
    {
        printf("Failed HttpClient_pushRequest \r\n  ");
        return;
    }
}

/**
 * @brief This API triggers periodically and initiate PrintWebpageContent to download the web page content.
 *
 * @param[in]: xTimer
 *               The timer handle of the function
 *
 */
static void ConnectServer(xTimerHandle xTimer)
{
    BCDS_UNUSED(xTimer);
    Retcode_T returnValue = RETCODE_OK;

    returnValue = CmdProcessor_enqueue(AppCmdProcessor, PrintWebpageContent, NULL, UINT32_C(0));
    if (RETCODE_OK != returnValue)
    {
        printf("En-queuing to application command processor failed \r\n");
    }
}

/* The description is in the interface header file. */
static void Init(void)
{
    retcode_t rc = RC_OK;

    rc = WlanConnect();
    if (RC_OK != rc)
    {
        printf("Network init/connection failed %i \r\n", rc);
        return;
    }

    rc = PAL_initialize();
    if (RC_OK != rc)
    {
        printf("PAL and network initialize %i \r\n", rc);
        return;
    }

    PAL_socketMonitorInit();

    /* start client */
    rc = HttpClient_initialize();
    if (rc != RC_OK)
    {
        printf("Failed to initialize http client \r\n ");
        return;
    }

    if (RC_OK != PAL_getIpaddress((uint8_t*) "api.thingspeak.com", &destAddr))
    {
        return;
    }

    else
    {
        uint32_t Ticks = 2000;

/*        if (Ticks != UINT32_MAX) /* Validated for portMAX_DELAY to assist the task to wait Infinitely (without timing out) */
/*        {
            Ticks /= portTICK_RATE_MS;
        }
        if (UINT32_C(0) == Ticks) /* ticks cannot be 0 in FreeRTOS timer. So ticks is assigned to 1 */
/*        {
            Ticks = UINT32_C(1);
        }
        /* Timer to Get Content from the connected server */
        connectTimerHandle = xTimerCreate((const char * const ) "ConnectServer", Ticks,TIMER_AUTORELOAD_ON, NULL, ConnectServer);
        if (connectTimerHandle != NULL)
        {
            if (xTimerStart(connectTimerHandle, TIMERBLOCKTIME) != pdTRUE)
            {
                assert(false);
            }
            else
            {
                printf("Started the timer successfully \r\n ");
            }

        }
    }
}

/**
 * @brief This is a template function where the user can write his custom application.
 *
 */
void appInitSystem(void * CmdProcessorHandle, uint32_t param2)
{
    if (CmdProcessorHandle == NULL)
    {
        printf("Command processor handle is null \n\r");
        assert(false);
    }
    uint32_t timerBlockTime = UINT32_MAX;
    uint32_t OneSecondDelay = UINT32_C(2000);
    uint32_t timerAutoReloadOn = pdTRUE;

    xTimerHandle SensorHandle= NULL;

    initSensor();

    SensorHandle = xTimerCreate((const char *) "readTempSensor", OneSecondDelay, timerAutoReloadOn, NULL, readSensor);

    xTimerStart(SensorHandle,timerBlockTime);

    AppCmdProcessor = (CmdProcessor_T *) CmdProcessorHandle;
    BCDS_UNUSED(param2);
    /*Call the RHC init API */
    Init();

}
/**@} */

 

0 (0 Votes)
RE: Trigger link on xdk
Answer
1/12/18 4:43 PM as a reply to Darren Tan.

Hello Darren,

a month ago, a new guide has been released, covering the topic of reading from and writing to an SD Card on the XDK.

Have you taken a look at it yet? You can find it in the Learning Section. It covers most relevant topics, from initialization to writing and reading and creating or deleting files.

The guide also features code snippets for every core functionality. I would recommend to copy most of the code into a new implementation file in your project, so that the SD Card functionality and the main application are separated, for better troubleshooting and debugging possibilites.

Please tell me if this was helpful, and do not hesitate to ask further questions.

Kind regards,
Franjo

0 (0 Votes)
RE: Trigger link on xdk
Answer
1/14/18 2:14 PM as a reply to Franjo Stjepandic.
Alright thanks will be sure to take a look at that. But again, how can i trigger a link when a certain requirement is met. (Eg. If(data < 50) {*trigger link*}
0 (0 Votes)
RE: Trigger link on xdk
Answer
1/15/18 12:03 PM as a reply to Darren Tan.
Also any idea on how to read data to change like the WPA SSID and password/ip addresses etc. from the SD card?
0 (0 Votes)
RE: Trigger link on xdk
Answer
1/15/18 5:20 PM as a reply to Darren Tan.

Hello Darren,

I seem to have missed the fact that you needed advice on triggering a link.

I am actually not quite sure what you mean by link. If the link is - more or less - just an internet URL, you can access it using the HTTP or the REST API. For both of these, a client module has to be initialized first. After that, messages can be created and pushed to the network from anywhere within the code.

We also have a guide for that in the Learning Section.

If I am mistaken in my understanding of the link you mentioned, could you please elaborate on what you mean by that?

Regarding your second question:
The SD-Card Guide should answer your questions. Chapter 5 is about reading and writing of files. The code snippet on page 11, shows how to save a string on the SD-Card.

const char FileContent[]="ID,\n, PW,\n"
Of course, you will have to initialize the SD card module before reading or writing. For that, please refer to chapters 3 and 4 of the same guide.

Optionally, you could take a look at the SdCardExample from the XDK-Workbench's Welcome screen, and see if you can reuse the code. The guide more or less explains all the functionality of that example.

If you have any additional questions, feel free to ask me.

Kind regards,
Franjo

 

0 (0 Votes)