Your Setup Console

WSS over Wi-Fi on Amazon FreeRTOS

The document explains how to build and run Wi-Fi Simple Setup over Wi-Fi on Amazon FreeRTOS (WSSoWiFi on A:FreeRTOS). Although these instructions are based on the Esp32 Dev Kit and ESP32-WROOM-32D + ESP-32S development board, most of the package is based on A:FreeRTOS APIs and is platform agnostic. See "Platform" for information on making platform specific changes to the example.

Prerequisite

  • ESP32-WROOM-32D + ESP-32S development board
  • Amazon FreeRTOS 202002.00
  • Wi-Fi Radio
  • C development environment
  • Minimum 128KB of RAM available
  • Minimum 1MB of flash memory available
  • Support for mbedTLS https://tls.mbed.org
  • A 1P Wi-Fi provisioner. 3P provisioner is not supported yet. An Echo device is a 1P provisioner.

Setting up Environment and Run Demo

This section provides guidance on downloading and building the dependencies. It then describes how to configure, build, flash and run the WSSoWiFi A:FreeRTOS program on your Esp32 development board.

Tools required

  • cmake
  • python 3.7

If you do not have any of the tools mentioned above installed, install them before proceeding.

Download ESP-IDF Toolchain

Follow the ESP-IDF installation instructions.

Download FFS C packages

Download the ffs-provisionee-sdk-master package from the developer.amazon.com. The WSSoWiFi on A:FreeRTOS code is under the ffs_amazon_freertos folder.

cd ffs-provisionee-sdk-master/ffs_amazon_freertos

Set The Device Configuration and Credentials

Device Configurations

Open the file ffs_amazon_freertos/espressif_app/wifi_provisionee/ffs_amazon_freertos_device_configuration.c and set the following constants to values appropriate for you device:

const char *const FFS_DEVICE_MANUFACTURER_NAME  = "Manufacturer Name";
const char *const FFS_DEVICE_MODEL_NUMBER       = "Model Number";
const char *const FFS_DEVICE_SERIAL_NUMBER      = "Device Serial Number";
const char *const FFS_DEVICE_PIN                = "Device PIN";
const char *const FFS_DEVICE_HARDWARE_REVISION  = "Hardware Revision";
const char *const FFS_DEVICE_FIRMWARE_REVISION  = "Firmware Revision";
const char *const FFS_DEVICE_CPU_ID             = "CPU ID";
const char *const FFS_DEVICE_DEVICE_NAME        = "Device Name";
const char *const FFS_DEVICE_PRODUCT_INDEX      = "Product Index";

This information is used during Wi-Fi simple setup and allows Amazon to identify your device properly.

Set Credentials

The FFS Simple Setup SDK needs to authenticate with the Amazon cloud. For development and testing, you should use device DHA material signed by a development DAK. Request a development DAK from the Amazon Frustration Free Simple Setup Developer Portal.

Please review Provisionee Manufactoring guideline for DHA process.

Once you have received your generated DHA material, open the file ffs_amazon_freertos/espressif_app/configs/ffs_amazon_freertos_credentials.h and paste your keys and certificate as cstrings:

#define DEVICE_PRIVATE_KEY      "Paste Device DHA Private Key here"
#define DEVICE_TYPE_PUBLIC_KEY  "Paste Device Type Public Key here"
#define DEVICE_PUBLIC_KEY       "Paste Device DHA Public Key here"
#define DEVICE_CERTIFICATE      "Paste Device DHA Certificate here"

Download and Build Amazon FreeRTOS

The reference package is based on version 202002.00 of Amazon FreeRTOS. Download this version of FreeRTOS using the following command:

git clone --branch 202002.00 https://github.com/aws/amazon-freertos.git --recurse-submodules freertos

Create build files for Amazon FreeRTOS using the following command:

cmake -S . -B build

Build the Demo and Flash Your Device

Setup the PATH and IDF_PATH environment variables:

export PATH=$PATH:<workspace>/ffs_amazon_freertos/freertos/vendors/espressif/esp-idf/tools
export IDF_PATH=<workspace>/ffs_amazon_freertos/freertos/vendors/espressif/esp-idf

Build the binary:

cmake --build build -j4

Build and flash the binary (This will generate the build to flash on your Espressif device):

cmake --build build -j4 --target flash

To only flash what has been built:

`idf.py flash`

If you run into a problem with the default port number used to flash to your device, you can override the default port number by using the -p port_number command line argument. For example:

idf.py -p *your_port* flash

Refer to ESP-IDF Programming Guide to determine the port number used to flash your device.

Open the Monitor

Use the following command to reboot the board and connect to the board monitor. After reboot the FFS Wi-Fi Simple Setup process will start running. The system will print log messages to the shell.

idf.py monitor

Type ctrl+] to quit the monitor.

Examining the Result

Review the output. If FFS Wi-Fi simple setup was successful, the system will print the following message

Ffs Wi-Fi provisionee task reached terminal state
End Ffs Wi-Fi provisionee task
Provisioning was successful.

This indicates that FFS Wi-Fi simple setup was successfully and the board is connected to the Wi-Fi network.

If the message Provisioning was successful does not appear, FFS Wi-Fi simple setup was not successful. In this case, example the log for the following pattern:

Response body: {"canProceed":true,"nextProvisioningState":<*NEXT_STEP*>,"nonce": ...

The log entry will indicate the provisioning step that failed.

Development

Platforms

This example and instruction are based on Esp32 Dev Kit. Running it on other platforms requires further changes.

Directed scan

The Amazon Free RTOS Wi-Fi module does not provide a mechanism for directed scans. The example implements this functional specifically for the Esp32 Dev Kit in function ffsDirectedScan specifically for Esp32 Dev Kit. For other platforms, a new implementation of this function is necessary. The implementation is found in libffs/src/ffs/amazon_freertos/ffs_amazon_freertos_directed_scan.c:

#define FFS_DIRECTED_SCANNING_PLATFORM_IN_USE  FFS_PLATFORM_NO_PLATFORM // -1 represents no platform

#ifdef FFS_DIRECTED_SCANNING_PLATFORM
    #define FFS_DIRECTED_SCANNING_PLATFORM_IN_USE   FFS_DIRECTED_SCANNING_PLATFORM
#endif

...

FFS_RESULT ffsDirectedScan(const FfsUserContext_t *userContext, const char *ssid, bool *const found)
{
#if FFS_DIRECTED_SCANNING_PLATFORM_IN_USE == FFS_PLATFORM_ESP32
    return ffsDirectedScanEsp32 (userContext, ssid, found);
#else
    ffsLogWarning("Unsupported directed scanning platform. Encoded SSID will not work.");
    return FFS_NOT_IMPLEMENTED;
#endif
}

You can add your platform in libffs/include/ffs/amazon_freertos/ffs_amazon_freertos_platforms.h

#define FFS_PLATFORM_NO_PLATFORM    -1
#define FFS_PLATFORM_ESP32           1

// Define a new platform macro with another integer here.
**#define <*your_platform*>             <*number*>**

Then, add the implementation of your device to libffs/src/ffs/amazon_freertos/ffs_amazon_freertos_directed_scan.c:

#define FFS_DIRECTED_SCANNING_PLATFORM_IN_USE       FFS_PLATFORM_NO_PLATFORM // -1 represents no platform
#ifdef FFS_DIRECTED_SCANNING_PLATFORM
    #define FFS_DIRECTED_SCANNING_PLATFORM_IN_USE   FFS_DIRECTED_SCANNING_PLATFORM
#endif

...

FFS_RESULT ffsDirectedScan(const FfsUserContext_t *userContext, const char *ssid, bool *const found)
{
#if FFS_DIRECTED_SCANNING_PLATFORM_IN_USE == FFS_PLATFORM_ESP32
    return ffsDirectedScanEsp32 (userContext, ssid, found);
**#elif FFS_DIRECTED_SCANNING_PLATFORM_IN_USE == <*your_platform*>
    <*your_implementation*>**
#else
    ffsLogWarning("Unsupported directed scanning platform. Encoded SSID will not work.");
    return FFS_NOT_IMPLEMENTED;
#endif
}

Finally, define FFS_DIRECTED_SCANNING_PLATFORM as <*your_platform*> macro by editing ffs_amazon_freertos/CMakefile.txt:

...
message(INFO "Creating build files for Wifi Provisionee Application")

### Edit here
# Specify platform. This macro is used in ffsDirectedScan. For the meaning of the values, refer to libffs/include/ffs_amazon_freertos_platforms.h
**add_definitions( -DFFS_DIRECTED_SCANNING_PLATFORM=<*your_platform*> )**

# Add wifi provisionee cmake subdirectory
add_subdirectory(espressif_app/wifi_provisionee)
...

File Structures

The libffs folder, excluding the ffsDirectedScan function, is expected to be portable over Amazon FreeRTOS platforms. However, all the files not inside the libffs folder can differ from one platform to the other. The way Amazon FreeRTOS boots on a platform is different. Therefore, if you are trying to use a different platform with this reference implementation, keep in mind it will require changes to the ffsDirectedScan files and require you to create application files that work with your platform. For application files that work with espressif Esp32, look inside the espressif_app folder.

Main Function

The main function app_main() is located at ffs_amazon_freertos/espressif_app/wifi_provisionee/main.c.

int app_main( void )
{
    // Initialize ESP board and FreeRTOS system.
    ...

    // Run runFrustrationFreeSetup
    **xTaskCreate****(runFrustrationFreeSetup, "FrustrationFreeSetup", FFS_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, &ffsTaskHandle);**

    // Process the result of runFrustrationFreeSetup
    xEventGroupWaitBits(ffsProvisioningResultEventGroup, FFS_PROVISIONING_RESULT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
    xSemaphoreTake(ffsProvisioningResultSemaphore, portMAX_DELAY);
    FFS_PROVISIONING_RESULT result = ffsProvisioningResult;
    xSemaphoreGive(ffsProvisioningResultSemaphore);

    vEventGroupDelete(ffsProvisioningResultEventGroup);
    vSemaphoreDelete(ffsProvisioningResultSemaphore);

    if (result == FFS_PROVISIONING_RESULT_PROVISIONED)
    {
        ffsLogInfo("Provisioning was successful.");
    }
    else
    {
        ffsLogInfo("Provisioning was not successful.");
        // Here, you should add a manual method to provision the device.
    }

    return 0;
}

The function runFrustrationFreeSetup drives the FFS Wi-Fi Simple Setup process by calling ffsProvisionDevice(&provisioningArguments). Parameters like DEVICE_PRIVATE_KEY were set at above (see Set Credentials). You can override these parameters by using pointers to your secure storage rather than the constants.

static void runFrustrationFreeSetup(void *args) {
    FfsProvisioningArguments_t provisioningArguments = {
        .privateKey              = DEVICE_PRIVATE_KEY,
        .privateKeySize          = sizeof(DEVICE_PRIVATE_KEY),
        .privateKeyType          = FFS_KEY_TYPE_PEM,
        .publicKey               = DEVICE_PUBLIC_KEY,
        .publicKeySize           = sizeof(DEVICE_PUBLIC_KEY),
        .publicKeyType           = FFS_KEY_TYPE_PEM,
        .deviceTypePublicKey     = DEVICE_TYPE_PUBLIC_KEY,
        .deviceTypePublicKeySize = sizeof(DEVICE_TYPE_PUBLIC_KEY),
        .deviceTypePublicKeyType = FFS_KEY_TYPE_PEM,
        .certificate             =  DEVICE_CERTIFICATE,
        .certificateSize         = sizeof(DEVICE_CERTIFICATE),
        .certificateType         = FFS_KEY_TYPE_PEM,
    };

    FFS_PROVISIONING_RESULT result = ffsProvisionDevice(&provisioningArguments);

    // Send the result
    xSemaphoreTake(ffsProvisioningResultSemaphore, portMAX_DELAY);
    ffsProvisioningResult = result;
    xSemaphoreGive(ffsProvisioningResultSemaphore);
    xEventGroupSetBits(ffsProvisioningResultEventGroup, FFS_PROVISIONING_RESULT_BIT);

    vTaskDelete(ffsTaskHandle);
}

If you need to do anything after the FFS process, you can add code to the end of the app_main() function.

New Files

If you want to create any new file under espressif_app/wifi_provisionee, make sure the source files are under espressif_app/wifi_provisionee/src and the header files are under espressif_app/wifi_provisionee/include. Otherwise, espressif_app/wifi_provisionee/CMakeLists.txt needs modification.

Document History

Version Date Author Description
1.02 July 30, 2020. Amazon. General Availability

Last updated: Nov 04, 2020