WICED HTTP Client

WICED HTTP & 943907 & CY3280 CapSense

Summary

In the previous articles I talked about the GE Hackathon, using WICED and CapSense, and finally creating a Particle Photon configuration.  In this article I will show you the WICED HTTP Client firmware which will read the button state and send it via WICED HTTP to the Particle Cloud.  To build this project I will start from the I2C Read firmware that I talked about in this article.

There are two parts of this application

  • The “main” application which reads the buttons and sends a message
  • The “sendMessage” function which builds a WICED HTTP message and sends it to the Particle cloud.

Main Application

I took the code from the previous example (CY3280 –> I2C –> WICED) and only made a few modifications (though I rearranged things a bit to make it easier to look at)

  • I joined the network (line 126)
  • I look up the IP address of the Particle Cloud (line 128)
  • Then I send a HIGH or LOW via the sendMessage function based on the state of the buttons (all the buttons do the same thing)
#include "wiced.h" 
#include <stdlib.h> 

#define I2C_ADDRESS (0x37) 
#define BUTTON_REG (0xAA) 
wiced_semaphore_t buttonPress; // used to signal in ISR to signal main
void application_start( )
{
    wiced_init();                                 // Initialize the WICED device
    wiced_rtos_init_semaphore(&requestSemaphore); // Initialize
    wiced_result_t result;

    wiced_network_up(WICED_STA_INTERFACE, WICED_USE_EXTERNAL_DHCP_SERVER, NULL);

    wiced_hostname_lookup( SERVER_HOST, &ip_address, DNS_TIMEOUT_MS, WICED_STA_INTERFACE );
    wiced_rtos_init_semaphore(&buttonPress);

    // WICED_GPIO_9 is the MBR3 Interrupt Pin
    wiced_gpio_init(WICED_GPIO_9,INPUT_PULL_UP);
    wiced_gpio_input_irq_enable(WICED_GPIO_9, IRQ_TRIGGER_FALLING_EDGE, button_isr, NULL); /* Setup interrupt */

    /* Setup I2C master */
    const wiced_i2c_device_t i2cDevice = {
            .port = WICED_I2C_2,
            .address = I2C_ADDRESS,
            .address_width = I2C_ADDRESS_WIDTH_7BIT,
            .speed_mode = I2C_STANDARD_SPEED_MODE
    };

    wiced_i2c_init(&i2cDevice);

    /* Tx buffer is used to set the offset */
    uint8_t tx_buffer[] = {BUTTON_REG};
    uint8_t buttonStatus;
    while ( 1 )
    {
        wiced_rtos_get_semaphore(&buttonPress,WICED_WAIT_FOREVER);

        // Do this until the MBR3 is alive.  It goes into deep sleep and wakes when you
        // send the first command.
        do {
            result = wiced_i2c_write(&i2cDevice, WICED_I2C_START_FLAG | WICED_I2C_STOP_FLAG, tx_buffer, sizeof(tx_buffer));
        }
        while(result != WICED_SUCCESS);

        result=wiced_i2c_read(&i2cDevice, WICED_I2C_START_FLAG | WICED_I2C_STOP_FLAG, &buttonStatus, sizeof(buttonStatus));
        if(buttonStatus > 0)
        {
            WPRINT_APP_INFO(("Sending On\n"));
            sendMessage("HIGH");
        }
        else
        {
            WPRINT_APP_INFO(("Sending Off\n"));
            sendMessage("LOW");
        }

    }
}

Send Message via WICED HTTP

The WICED HTTP sendMessage function simply

  • Creates a http_client (which is just a mechanism to keep track of an HTTP connection
  • Sets up a connection (lines 77-80)
  • Makes the connection (line 82)
  • Creates the message (line 88) in “application/x-www-form-urlencoded” format
  • Builds the HTTP headers for a HTTP “POST” (lines 90-105)
  • Write the Request (lines 108 –> 112)
  • Waits for the response using semaphore (line 114)
  • Destroys the connection (line 115 –> 116)
#include "wiced_tls.h" 
#include "http_client.h" 
#define SERVER_PORT ( 443 ) 
#define SERVER_HOST "api.particle.io" 
#define SERVER_RESOURCE "/v1/devices/2a001b000347353137323334/digitalwrite" 
#define PARTICLE_ACCESS_TOKEN "1311f9217a60" 
#define DNS_TIMEOUT_MS ( 10000 ) 
#define CONNECT_TIMEOUT_MS ( 3000 ) 
wiced_semaphore_t requestSemaphore; // used to signal request is done static http_client_t client; 
static http_request_t request; 
static http_client_configuration_info_t client_configuration; 
static wiced_ip_address_t ip_address; 

/* void sendMessage - Send HTTP request to turn on or off the LED
 */
void sendMessage( char *state )
{

    http_client_init( &client, WICED_STA_INTERFACE, event_handler, NULL );

    /* configure HTTP client parameters */
    client_configuration.flag = (http_client_configuration_flags_t)(HTTP_CLIENT_CONFIG_FLAG_SERVER_NAME | HTTP_CLIENT_CONFIG_FLAG_MAX_FRAGMENT_LEN);
    client_configuration.server_name = (uint8_t*)SERVER_HOST;
    client_configuration.max_fragment_length = TLS_FRAGMENT_LENGTH_1024;
    http_client_configure(&client, &client_configuration);

    http_client_connect( &client, (const wiced_ip_address_t*)&ip_address, SERVER_PORT, HTTP_USE_TLS, CONNECT_TIMEOUT_MS );

    http_header_field_t header[3]; // Three headers
    char messageBody[128];        // Enough to hold the message body
    char messageLengthBuffer[10]; // Enough to hold the characters for the Content-Length: header

    sprintf(messageBody,"access_token=%s&params=D7%%2C%s",PARTICLE_ACCESS_TOKEN,state);

    header[0].field        = HTTP_HEADER_HOST;
    header[0].field_length = sizeof( HTTP_HEADER_HOST ) - 1;
    header[0].value        = SERVER_HOST;
    header[0].value_length = sizeof( SERVER_HOST ) - 1;

#define MIME_FORM_URL "application/x-www-form-urlencoded"
    header[1].field        = HTTP_HEADER_CONTENT_TYPE;
    header[1].field_length = sizeof( HTTP_HEADER_CONTENT_TYPE ) - 1;
    header[1].value        =  MIME_FORM_URL;
    header[1].value_length = sizeof(  MIME_FORM_URL ) - 1;

    sprintf(messageLengthBuffer," %d",strlen(messageBody)); // Put the message body into the buffer so that you can strlen it
    header[2].field        = HTTP_HEADER_CONTENT_LENGTH;
    header[2].field_length = sizeof( HTTP_HEADER_CONTENT_LENGTH ) - 1;
    header[2].value        =  messageLengthBuffer;
    header[2].value_length = strlen(messageLengthBuffer);

    // Build the HTTP Message
    http_request_init( &request, &client, HTTP_POST, SERVER_RESOURCE, HTTP_1_1 );
    http_request_write_header( &request, &header[0], 3 ); // 3 headers
    http_request_write_end_header( &request );
    http_request_write(&request,(uint8_t*)messageBody,strlen(messageBody));
    http_request_flush( &request );

    wiced_rtos_get_semaphore(&requestSemaphore,10000); // wait up to 10 seconds to close the request and the client
    http_request_deinit(&request);
    http_client_deinit(&client);
}

WICED HTTP Event Handler

The way that the WICED HTTP  executes is that it has a worker thread waiting on the TCP socket.  When it gets a response it runs your callback function and tells you what happened.  In this case I just tell my thread to close the connection and move on.

/*
 * void event_handler() is called by the http_client function when
 *  Data is received from the server
 *  a connection is made
 *  a disconnect occurs
 *
 *  When data is received I assume that the response is good and I reset the semaphore so that another request can happen
 */

static void event_handler( http_client_t* client, http_event_t event, http_response_t* response )
{
    switch( event )
    {
        case HTTP_CONNECTED: // Dont do anything
        break;

        case HTTP_DISCONNECTED: // Disconnect if you get this event
            wiced_rtos_set_semaphore(&requestSemaphore);
        break;

        case HTTP_DATA_RECEIVED: // Disconnect if you get this event
            wiced_rtos_set_semaphore(&requestSemaphore);
        break;

        default:
        break;
    }
}

 

CY3280 MBR3 & WICED CYW943907

Summary

In the last Article I talked about the GE Megahackathon.  One of the groups at the event got interested in using a CY3280 MBR3 to send signals via a WICED CYW943907 to the Particle IO server which was connected to a Particle Photon.  I helped them with the implementation and thought that it would be useful to show here.

CYW3280 & WICED CYW943907

Cypress CY3280 MBR3

The CY3280 MBR development kit is a CapSense demonstration kit that shows the Mechanical Button Replacement 3 chip.  It features 4 CapSense buttons with LEDs, a proximity sensor, and a buzzer.  It is connected to another MCU via the Arduino pins. of the WICED CYW943907.  The device sits on the I2C bus and acts as an I2C Slave.  You configure it using EZ Click.

When you run EZ Click you can setup the configure the internal registers of the MBR3 to make the board act like a bunch of different things.  In this case I turned on

  • The MBR buttons 1-4 (you can see them in the picture above)
  • The Flanking Sensor rejection which makes it so that you can only press one button at a time.
  • All of the automatic tuning features.

EZ-Click CY3280

Once the main CapSense is configured, I moved to the other part of the configuration where I setup

  • The 4 LEDs to toggle and be full brightness when on
  • The buzzer to buzz for 100ms at 4kHz when something happens
  • The host interrupt pin as CS15/SH/HI.  This made the Arduino pin D2 be an interrupt when something happened so that WICED would poll the MBR3

EZ-Click CY3280

Once these settings were all done, I downloaded the firmware configuration via the KitProg USB connector.  Then I tested it using the bridge control panel which I have shown you a bunch of different times in the past.  The MBR3 acts as an I2C slave.  To find out what the state of the buttons are you need to read register 0xAA.  The only little trick is that the chip goes to sleep to save power.  In order to wake it up you need to send an I2C transaction, which ends up getting NAK’d.  But the next transaction you send will be ACKd.  In the screenshot below you can see that I tried two of the buttons (0x08 and 0x20)

Bridge Control Panel

One problem that I had is that the power system of this board is setup to take 5V from the Arduino base board but the WICED development kit gives only 3.3v.  Here is a picture of the power system from the MBR3 schematic.

CY3280 Power Supply

The MBR3 can run on 3.3Vs.  In fact it can run all the way down to 1.7v and up to 5.5v, but for some reason (which I can’t remember) we made the board only work with 5.0v.  To fix this problem I removed J12 and then wired a wire from the 3.3V Arduino pin.  The wire is soldered onto the 3.3v pin, but has a female connector on the other side so that it can be plugged into J12.  Here is a picture:

CY3280

The last thing that I needed to do was move the jumpers to position “A” which made the host interrupt pin be connected to D2, and move the I2C jumpers so that the MBR3 was connected to the Arduino instead of the P5LP kitprog.  You can see that in the J3_scl and J3_sda in the picture above.

WICED CYW943907

The CYW934907AEVAL1F is an development kit for the Cypress 43907 MCU+WiFi module.  The WICED CYW943907 board can do dual band (2.4 and 5Ghz), 802.11 a/b/g/n,  Ethernet and a whole bunch of other stuff.

WICED CYW943907

The first firmware that I wrote in WICED Studio:

  • Sets up an ISR to unlock a semaphore when the interrupt occurs
  • Initialized WICED_GPIO_9 to be an input and connected to an ISR … this is also known as Arduino D2
  • Setup the I2C Master Hardware in the 43907
  • Wait for a semaphore (from the ISR)
  • Read the I2C register 0xAA from the MBR

The only trick in the firmware is that I read the I2C with a “do” loop until I get a valid result, meaning that the MBR3 has woken up.

#include "wiced.h"

#define I2C_ADDRESS (0x37)
#define BUTTON_REG (0xAA)

wiced_semaphore_t buttonPress;

/* Interrupt service routine for the button */
void button_isr(void* arg)
{
    wiced_rtos_set_semaphore(&buttonPress);
}

/* Main application */
void application_start( )
{
    wiced_init();	/* Initialize the WICED device */
    WPRINT_APP_INFO(("Started\n"));

    wiced_result_t result;
    wiced_rtos_init_semaphore(&buttonPress);

    // WICED_GPIO_9 is the MBR3 Interrupt Pin
    wiced_gpio_init(WICED_GPIO_9,INPUT_PULL_UP);
    wiced_gpio_input_irq_enable(WICED_GPIO_9, IRQ_TRIGGER_FALLING_EDGE, button_isr, NULL); /* Setup interrupt */

    /* Setup I2C master */
    const wiced_i2c_device_t i2cDevice = {
            .port = WICED_I2C_2,
            .address = I2C_ADDRESS,
            .address_width = I2C_ADDRESS_WIDTH_7BIT,
            .speed_mode = I2C_STANDARD_SPEED_MODE
    };

    wiced_i2c_init(&i2cDevice);

    /* Tx buffer is used to set the offset */
    uint8_t tx_buffer[] = {BUTTON_REG};
    uint8_t buttonStatus;

    while ( 1 )
    {

        wiced_rtos_get_semaphore(&buttonPress,WICED_WAIT_FOREVER);

        // Do this until the MBR3 is alive.  It goes into deep sleep and wakes when you
        // send the first command.
        do {
            result = wiced_i2c_write(&i2cDevice, WICED_I2C_START_FLAG | WICED_I2C_STOP_FLAG, tx_buffer, sizeof(tx_buffer));
        }
        while(result != WICED_SUCCESS);

        result=wiced_i2c_read(&i2cDevice, WICED_I2C_START_FLAG | WICED_I2C_STOP_FLAG, &buttonStatus, sizeof(buttonStatus));
        WPRINT_APP_INFO(("Button State = %X\n", buttonStatus)); /* Print data to terminal */
    }
}

Once that is programmed I program and test the firmware.

Testing WICED CYW943907

In the next article I will modify all of this firmware and make the WICED CYW943907 send data via HTTP to the Cloud.

Embedded World 2017: WICED WiFi, MQTT and the Amazon IoT Cloud (Part 2)

Summary

As I explained in yesterday’s article, I was unhappy about not connecting to Amazon AWS IoT cloud for my presentation at Electronica 2016.  In the last post I showed you how to build an Amazon AWS IoT MQTT Client in the WICED WiFi SDK that can Publish to the Amazon Message Broker.  Now I need to build a WICED App that can Subscribe to the ROBOT_POSITION topic and receive messages from the MQTT broker.  This series of articles is broken up like this:

  1. Amazon IoT & MQTT (Part 1)
  2. Modify & Test the WICED Publisher App (Part 1)
  3. Modify & Test the WICED Subscriber App (Part 2)
  4. Modify the Application to talk I2C to the PSoCs (Part 3)

Modify the WICED Subscriber App

As with the previous article, start by copying the App from the apps–>demo–>aws_iot–>pub_sub–>subscriber into your directory.  In my case that will be apps–>emb2017–>subscriber.  Then update the application “Name:” and “VALID_PLATFORMS” in the Makefile.  Remember that the App name must be unique.

WICED WiFi SDK

Then modify the DCT to have your networking information.  Don’t forget that the DCT is the device configuration table for WICED WiFi and is used to store the mostly static information (like network, passwords etc).

WICED WiFi Subscriber DCT

The next step is to make a few modifications to the actual firmware.  Specifically,

  • (line 60) Change the MQTT Broker IP address to the one assigned by Amazon
  • (line 61) Change the TOPIC to “ROBOT_POSITION”
  • (line 103) Print the message to the console

subscriber.c

In the last article I copied the Transport Layer Security (TLS) keys from Amazon into the resources–>apps–>aws_iot directory.  For this application I will use exactly the same keys.  Then, create a new make target for the App and program the board.

WICED WiFi Make Targets

Test the WICED WiFi Subscriber App

To test the application I will, once again, use the Amazon AWS IoT web MQTT Client to send messages to my board.  In the screen shot below you can see the console window of the 943907AEVAL1F board.  After programming it:

  • starts up
  • gets WICED and ThreadX going
  • connects to my network (WW101WPA, gets a DHCP address: 198.51.100.16)
  • Find the IP address of the MQTT broker (34.194.80.220)
  • Opens an MQTT connection to Amazon.

When I publish the message “20304050” using the MQTT Client to the “ROBOT_POSITION” topic,  you can see that it comes out on the console of the WICED WiFi development kit.

Amazon IoT MQTT Test Client

That proves that we have end-to-end communication.  In the last article, I will fix up the Publisher and Subscriber application to read and write the I2C connection so that it can actually do the Robot ARM control.