Using the Connector

Introduction

Managed IoT Cloud (MIC) is a secure cloud platform for device and data management that generates valuable and useful insights about your connected products. It provides the building blocks you need to connect your product, collect and store all product data, and extract value and insights from that data. It includes a self-service tool and a customizable application to get you started quickly, and when your digital service starts to grow, Managed IoT Cloud scales with you, globally. Telenor Connexion cooperates with device and application partners to provide a complete end-to-end solution for your digital services. Business relations with the partners are solely established by you based on your needs.

The Connector

The Connector is an optional software component that runs on the Thing and simplifies connecting Things to the cloud. The Connector is delivered as a binary library with header files for a selected number of targets. The software base is ANSI C99 making it extremely portable, most of the time the modification needed to support a new HW target is mapping the I/Os and developing a modem driver if one is not already available for the selected modem.

Note

When the connector is adapted to support a new HW target, there is usually already an existing code base for handling all of the application functionality.
The connector only adds the cloud connectivity and a resource repository.
For a limited number of targets, based on the NXP Kinetis K64 platform, there is additional functionality. More specific, the connector has a complete support for all of the HW functions of a barebone 3GGV02 supplied by JEMAC, and supports all of the HW functions of the 3GGV03 that are present on the 3GGV02 target.
This makes the 3GGV02 and 3GGV03 suitable for projects where no HW is already chosen and the requirements of the application in regards to HW interfaces etc. are met by these.

Supported targets

Current supported targets

Name Supplier HW Features Modem Notes
3GGV02 JEMAC 2 x 4-20mA/0-10V A/D inputs* 1 x D/A output* RS232 port* RS485 bus* Ethernet port* GPS* Expansion port for Accelerometer etc Cinterion EHS8 Supported by BIST**
3GGV03 JEMAC 2 x 4-20mA/0-10V A/D inputs* 1 x D/A output* RS232 port* RS485 bus* Ethernet port* GPS* Optional WiFi Bluetooth Accelerometer etc. uBlox SARA U201 Supported by BIST**
Customer Proprietary - Not supported by Connector Quectel BG96
Customer Proprietary - 4 x 4-20mA/0-10V 12 bit A/D converters logic level serial I/O. Simcom SIM900 / SIM800 Supported by BIST**
Customer Proprietary - Not supported by Connector Cinterion BG2

Functionality natively supported by Connector*
BIST** - **B**uilt **I**n **S**elf **T**est, for setting serial number, storing Passport etc

Getting started with the Connector

Before getting going with using the Connector on any of the HW targets, Things need to be created as well as Passports. A complete walkthrough how to create things and download their Certificates and private keys is available here MIC App Board User Guide

The Passport concept and how to provision a Passport

When creating a thing in MIC, certificates and private keys are automatically created and provided for download as a .zip-file. The Connector uses something called a Passport which is a way of provisioning IoT-Endpoint, thingId, Certificate, root CA and Private key as a single file.

Creating a Passport

When the passport(s) has been downloaded, they will reside in a file named similarly to the batch-4-9005671155616735.zip-file below

Unzip the file and make sure that the following files are present in the same folder as all the folders containing the credentials of the things. These files will be provided on request.

The connector

File name Description Comment
CA.pem The root CA. When using an ATS-suffixed IotEndpoint, make sure that this is the 2048 bit RSA root CA for the Amazon Trust Services Endpoint
cc3250.dll A dll file used by the Passport builder
MakePassport.bat A batch-file calling the .exe with the proper parameters.
MakePassport.exe The Passport builder program.

The MakePassport.bat-file contains an IoT Endpoint that is generic, preferably it should be modified and the generic endpoint should be replaced with the value of the IotEndpointATS-key from the Manifest of the stack. The ATS-Endpoint for the Demo-stack (a1ek3lbmx2jfb9-ats.iot.eu-west-1.amazonaws.com) is in the .bat file currently distributed.

  1. Now, Drag and drop each thing-folder on the MakePassport.bat-file. Inside of the folders a cc2_pp.bin and a cc2_pp.c-file will be created, each generating a DOS-window dialogue. Passport creation terminal output

Storing a passport

Installing and preparing terminal program.

  1. Download and install the software Coolterm from http://freeware.the-meiers.org/

  2. Set Coolterm to use 115200 bps 8/1/n and enable Local Echo in Connection/Options/Terminal.

  3. Use Coolterm menu alternative Connection -> Send String (CTRL-T) to add a send string

    init_filesystem
    
    

    (There should be a new line after the text)

  4. Use Coolterm menu alternative Connection -> Send String (CTRL-T) to add a send string

store_passport 

(yes, a space at the end) 5. Use Coolterm menu alternative Connection -> Send String (CTRL-T) to add a send string

end_passport
  1. Use Coolterm menu alternative Connection -> Send String (CTRL-T) to add a send string
restart

(There should be a new line after the text)

  1. Use Coolterm menu alternative Connection -> Send String (CTRL-T) to add a send string
nvminfoput snr_consec 

(yes, a space at the end)

When done, it should look like this:

Storing the Passport

  1. Make sure that the thing is programmed with the correct BIST for the HW target using using a Segger Flasher ARM programmer.

  2. Click “Connect” in the Coolterm Window.

  3. Power supply is turned off for a short while (ca 2s).

  4. The following text should be present in the Coolterm Window:

BIST [HW Name] Ver: [Latest version] Build time [Build time of BIST FW] 
Enter Command. 
Type "help" for list of commands 
Serial FLASH SST25VF032B found! 
PCB Serial Number: 0 
Error opening passport. 
PCB MAC ADDRESS: 70:B3:D5:27:D0:00 
Last Production Test result: NOT TESTED 
USIM Selected. 

>
  1. Using Coolterm, now send “init_filesystem”. After completion, the following text should display:
>init_filesystem 

Formatting filesystem, this may take up to 20 seconds, please wait! 

init_filesystem OK 
>
  1. Now send “store_passport “ and use Windows File explorer to drag and drop the cc2_pp.bin-binary file that belongs to the unit and can be found in the thing folders after completing Creating a Passport above into the terminal window.

  2. When the binary file has been transferred, send the “end_passport” string.

  3. The result should look like https://docs.telenorconnexion.com/thing/bist/#store-passport

  4. Send the “nvminfoput snr_consec “ string followed by the wanted serial number of the device and enter.
    The device should now store the serial number and indicate that the procedure went OK.

>nvminfoput snr_consec [WANTED SERIAL NUMBER] 

nvminfoput OK
>
  1. Send the “restart\r\n” string.

    The unit should now restart. and display something similar to this:

BIST [HW Name] Ver: [Latest version] Build time [Build time of BIST FW] 
Enter Command. 
Type "help" for list of commands 
Serial FLASH SST25VF032B found! 
PCB Serial Number: [THE PROGRAMMED SERIAL NUMBER] 
Passport opened OK, Thing ID: [thingId of the downloaded passport]
PCB MAC ADDRESS: 70:B3:D5:27:D0:00 
Last Production Test result: NOT TESTED 
USIM Selected. 

>

Developing with the Connector Library

When developing with the Connector Library there are a few things that may be good to know to get started easily.

  • Currently, Connector Development is done on Windows using IAR Embedded Workbench for ARM.
  • You will see the word ETIF_ a lot, ETIF is an abbreviation for **E**mbedded **T**arget **I**ndependent **F**ramework
  • You can set timers and delays as seen in the various code examples, the shortest delay is 0-1ms, meaning that if something is scheduled to happen after 1 ms, it may happen after less than 1ms too.
  • Basing all development off a real or Substed O:-drive makes things a lot easier, especially when help is needed from the Connector Library Devs.

Targets only using modem drivers and Resource Repository

For these targets, the functions in the table below will be the most likely to be used by the application:

Function / Handler / Macro name Description
ETIF_ResourcePut Used for getting a resource value from the Resource Repository, commonly called when an incoming event has triggered the Resource Event handler
ETIF_ResourceGet Used for setting a resource value to the Resource Repository and further on to the cloud platform
ETIF_CellDrv_SubscribeNetworkStatus(Event_NetWorkStatus) Used for setting the event handler for network status events from the cellular modem
ETIF_Resource_SubscribeHandlerEvents(Event_ResourceHandler) Used for setting the event handler for global event handler events
ETIF_ADD_APP_RESOURCE(NAME, DATA_TYPE, RESOURCE_TYPE_SIZE, UCUM, DEFAULT_VALUE, EVENT_HANDLER) A macro for adding resources to the resource Repository

3GGV02 and 3GGV03 targets

When developing for these targets, there are a much bigger set of functions that will be used by the application. These are all documentet in the Doxygen documentation

Installing the Connector Library

The Connector library is supplied as a .zip-file. The contents of the zip-file should be placed in the root of the o: drive. When unpacked it should look similar to this: ETIF_LIB

The .svn folder is present when using SVN for version handling.

Doxygen documentation

A Doxygen generated documentation of the ETIF Framework can be found in O:\ETIF_LIB\doc\html Please refer to this if any of the functions used in the source walkthrough below needs more explanation.

Installing IAR EWB

The currently used version of IAR EWB is 7.40.3.8938 No special considerations needed when installing, but make sure that using the correct version.

Installing KSDK

KSDK is the Kinetis Software Development Kit supplied by NXP. The current version of the KSDK used by the Connector is 1.1.0 and it should be installed to c:\Freescale The KSDK can be found at NXP - Kinetis SDK 1.1.0 Mainline - Windows.

Using the ETIF_NewApp_MIC.bat-file for setting up an example project

When starting a new project, the ETIF_NewApp_MIC.bat-file can be used for setting up a project for the 3GGV02 and 3GGV03-targets. The ETIF_NewApp_MIC.bat-file is supplied as a part of the Library and can be found in O:\ETIF_LIB\Tools. When run, the script asks for the following:

Batch file output and Wanted Input Valid input
HW target 3GGV02 or 3GGV03
Project drive [Enter] for o: or any other valid drive letter
Project home directory Any directory name
Project directory does not existDo you want to create it (Y/N)? Y or N - If user enters N, building project will fail.
Project name? Any name for the project
Brief project description? Any description for the project
Author name? Any name
Default device serial number? Any serial number that fits into 32 bits
Project ExampleProj is being created please wait……………..Generating batch file for fetching Release files……..The project file o:\ExampleProj\ExampleProj\fw\V01\prj\IARARM\ExampleProj.ewwcan now be opened in IAR workbench and built.Ready! Press any key to continue…. [Enter] to finish

Output and input to ETIF_NewApp_MIC.bat

The ETIF_TestSuiteFramework

Included in the delivery of the library for 3GGV02 and 3GGV03 from JEMAC, is a suite of tests designed to test as many of the different functionalities offered for 3GGV02 and 3GGV02. The project can be found in O:\ETIF_TestSuiteFramework\ETIF_TestSuiteFramework\Fw\V01\Prj\IARARM and the source files explained below can be found at O:\ETIF_TestSuiteFramework\ETIF_TestSuiteFramework\Fw\V01\Src.

Please note that the ETIF_TestSuiteFramework is built for the purpose of sequentially testing all the features of the ETIF.
Among other things, macros has been added to facilitate easily adding more test cases to be run in sequence.
These test cases are in fact normal subthreads but they are added to the application in a different way.
A simpler “typical use case” will be added to compliment the project and source code in ETIF_TestSuiteFramework.

Walktrough of different ETIF_TestSuiteFramework source

In this section, the source code of the main thread in a number of ETIF_TestSuiteFramework test cases are gone through. The code examples are available as is and functioned with no issues as of October 24th 2018. Only the sections of the code relevant to the walkthrough of the different functionalities are shown here, for the complete code for each section, a link to the raw source code file, in the state it was October 24th 2018, is provided.

File Functionality explained / demonstrated / exemplified
ETIF_TestCELL_CLOUD.c How to check if there is a SIM-Card installedHow to check if unit can register to home networkHow to check if unit can attach to Packet serviceHow to check for Cloud Connect 2 PassportHow to Check connection to cloudResource Event handler routine with examples of how to use flags for checks.
ETIF_TestDAC_ADC.c What files to include How to initialize ADC and DAC How to set a DAC output level How to do an ADC measurement
ETIF_TestFileXfer-multi.c How to to a file download How to do a file upload
ETIF_TestGPS.c How to open and close the GPS Stream Example GPS Stream handlerHow to restart GPS stream if it is stopped because of no lock
ETIF_TestLAN.c How to open and close a local socket How to send data on a stream Example stream handler
ETIF_TestMISC.c How to do user reset
ETIF_TestNVM.c How to store value in non volatile configuration How to read value from non volatile configuration
ETIF_TestProxy.c How to open the MQTT-Proxy stream How to send data to proxy topic Example stream event handler for MQTT Proxy
ETIF_TestRESOURCE_THRESHOLDS.c When a resource is sent or not depending on threshold settings
ETIF_TestSERIAL.c How to open an RS232 stream How to open an RS485 stream Example Stream Event Handler for RS232 stream Example Stream Event handler for RS485 stream
ETIF_TestSuspendResume.c How to suspend cloud connectivity. How to resume cloud connectivity
ETIF_TestThreadCtrlAbortCatch.c ETIF_TestThreadCtrlTimeoutChildBlocking.c Two examples of thread timeout and aborted subthread functionality along with catch functionality
ETIF_TestThreadCtrlBreak.c Thread break functionality
ETIF_TestThreadCtrlTimeoutChild.c Timeout in the current thread and catch functionality

ETIF_TestCELL_CLOUD.c

Raw ETIF_TestCELL_CLOUD.c

How to check if there is a SIM-card installed

In this snippet, the software waits for the ICCID-information to be updated by the cellular modem. When the modem has updated this information, the result is printed, and since this is /source code for a test suite, the test result is saved.

    while(1)
    {
      memcpy(Tmp, ETIF_CellularSIMICC(), 21);                                   // Copy the ICCID to temporary buffer using ETIF API.

      if(strstr(Tmp, "SIM not inserted"))                                       // Check if content of string indicates that no SIM is inserted
      {
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("SIM does not exist."));
        TSF_AuditAppendTestComment("SIM does not exist.");
        break;
      }
      else if( Tmp[0] != 0)
      {
        c8 testcomment[40];
        snprintf(testcomment, sizeof(testcomment), "SIM ICCID: %s", Tmp);       // Or if content of string is a real value
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("SIM exists, %s", testcomment));
        TSF_AuditAppendTestComment(testcomment);                                // Append value as a testcomment
        TSF_AuditAppendTestVerdict("OK");                                       // And set verdict
        break;
      }
      ETIF_THREAD_DELAY(500);
    }

How to check if unit can register to home network

This test is based on using the ETIF Flag functionality to set flags in the Network Event handler. The flags are added in the ETIF_AppRegistry.h-file and are set by the Event_NetWorkStatus - Network event handler in ETIF_TestSuiteFramework.c.

    ETIF_THREAD_WAIT_UNTIL(ETIF_FLAG_CHK(REGISTERED_HOME) || ETIF_FLAG_CHK(REGISTERED_ROAMING));    // Wait until atleast one of the flags have been set, if modem never 
                                                                                                    // registers, this test will eventually time out
    if(ETIF_FLAG_CHK(REGISTERED_HOME))
    {                                                                           // Registered to home network
      TSF_AuditAppendTestComment("Registered Home Network");                    // Append relevant testcomment
    }
    else if(ETIF_FLAG_CHK(REGISTERED_ROAMING))                                  // Registered to roaming network
    {
      TSF_AuditAppendTestComment("Registered Roaming Network");                 // Append relevant testcomment
    }

How to check if unit can attach to Packet service

This test is based on using the ETIF Flag functionality to set flags in the Network Event handler. The flag is added in the ETIF_AppRegistry.h-file and set by the Event_NetWorkStatus - Network event handler in ETIF_TestSuiteFramework.c.

    ETIF_THREAD_WAIT_UNTIL(ETIF_FLAG_CHK(PACKET_SERVICE_ATTACHED));             // Check flag

    TSF_AuditAppendTestVerdict("OK");                                           // Add verdict

How to check for Cloud Connect 2 Passport

This test uses passport handling functionality to check if there is a valid passport available in the file system.

  if(CCP_OpenPassport() < 0)                                                    // Try to open passport, If result < 0, something is wrong.
  {
    TSF_AuditAppendTestComment("No Passport found, filesystem broken?");        // Append relevant testcomment
    TSF_AuditAppendTestVerdict("FAILED");                                       // Append verdict
  }
  else
  {
    extern const c8 * ccp_p_thing_id;
    snprintf(Tmp, sizeof(Tmp), "Thing ID: %s", ccp_p_thing_id);                 // If result is >= 0, the passport was opened OK, checksum etc. is correct.
    TSF_AuditAppendTestComment(Tmp);                                            // Append relevant testcomment
    TSF_AuditAppendTestVerdict("OK");                                           // Append verdict
  }

How to Check connection to cloud

This test is based on using the ETIF Flag functionality to set flags in the Network Event handler. The flag is added in the ETIF_AppRegistry.h-file and set by the Event_NetWorkStatus - Network event handler in ETIF_TestSuiteFramework.c.

  ETIF_THREAD_WAIT_UNTIL(ETIF_FLAG_CHK(CLOUD_CONNECTED));                       // Wait until atleast one of the flags have been set, if the ETIF_RESOURCE_EDGE_CONNECT-event is
                                                                                // never received by the event handler, the test will eventually time out.
  TSF_AuditAppendTestVerdict("OK");

ETIF_TestDAC_ADC.c

Raw ETIF_TestDAC_ADC.c

Enable DAC and ADC functionality.

In order for being able to use the DAC. the ADC and DAC source code needs to be added, either by adding the c-file to your project or by including the c-file directly in the /source:

#include "ADC_DAC.c"                                                            // Contains DAC and ADC functionality

Then, the adc_dac_device_config() function needs to be called to complete calibration etc.

  // ADC + DAC
  adc_dac_device_config();  

How to set the DAC

    mDACPut12BitVal(1000);                                                      // Set the DAC output to 1000 bits out of 4096 bit resolution.

How to read an ADC

Below, one of the ADC differential pairs are read. What input is read differs depending on what HW is used and how any multiplexers on the board are set.

    for(i = 0; i < ADC_MEAN_VAL_DIVIDER; i++)                                   // Read the input a number of times for smoothing using mean value
    {
      adc_mean_val += mADCGetCh2_1Blocking;                                     // Read ADC1 Diff Pair 1
      ETIF_THREAD_DELAY(150);
    } 

The macros availiable to read the diff pairs are these:
The logic of the naming is based on the input configuration for the 3GGV02 HW.

mADCGetCh2_0Blocking                                                            // Read ADC1 Diff Pair 1
mADCGetCh2_1Blocking                                                            // Read ADC1 Diff Pair 0
mADCGetCh1_0Blocking                                                            // Read ADC0 Diff Pair 1
mADCGetCh1_1Blocking                                                            // Read ADC1 Diff Pair 0

ETIF_TestFileXfer-multi.c

In this section examples of how to do file up and download.
Each operation needs an eventhandler capable of handling events of the tEtifResourceEventCommands type. The event handlers look a little bit different depending on if an upload or a download is in progress.
In the test code, the file in which the test progress is stored is first uploaded in it´s current state, and then downloaded and compared to the original file. This process is repeated three times, to make sure that the process is stable.

How to upload a file

A typical event handler for this kind of operation looks like this:

/*******************************************************************************
*                                                                              *
*             F I L E   U P L O A D   E V E N T   H A N D L E R                *
*                                                                              *
*******************************************************************************/

u8 FileUploadEvent(s8 Cmd, u8 **pBuffer, u32 *Nb)
{
  
  static u32 RecordsSent=0;
  static u32 TotNb=0;
  static u8 Record[100];

  switch(Cmd)
  {

    case ETIF_RESOURCE_FILE_EMPTY:                                              // This event indicates that all data in the pipe has been sent

      if(TotNb == 0)                                                            // TotNb == 0 indicates that this is the first time this event is received during the 
      {                                                                         // current operation
        if(f_open(&uploadfile, "TstAudit.txt", FA_READ) != FR_OK)               // Try to open file, in this case it is hardcoded that it is the TstAudit-file
        {
          break;                                                                // If file open error, break.
        }
      }
      if(TotNb < flnfo.fsize)                                                   // Has the entire file been uploaded yet?
      {
        f_read(&uploadfile, Record, sizeof(Record), Nb);                        // Read some bytes and place in buffer
        *pBuffer=&Record[0];

        TotNb+=*Nb;                                                             // Increase byte count
        RecordsSent++;
        ETIF_DEBUG_STR(ETIF_DEBUG_TRACE,("Send record no: %u total number of bytes %lu", RecordsSent, TotNb));
      }
      else                                                                      // Entire file sent
      {
        ETIF_DEBUG_STR(ETIF_DEBUG_TRACE,("End of file, total number of bytes sent %lu", TotNb));
        *Nb=0;
      }

    break;

    case ETIF_RESOURCE_FILE_TRANSFER_ERROR:                                     // File transfer error event received from http-client
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("File upload ended in error!"));
        TotNb = 0;
        RecordsSent=0;
    break;

    case ETIF_RESOURCE_FILE_SESSION_END:                                        // File session end event received from http-client
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("File upload Session ended - successfully!"));
        f_close(&uploadfile);                                                   // Make sure that file is closed
        RecordsSent=0;                                                          // Reset counters
        TotNb = 0;
        ETIF_FLAG_SET(FILE_UPLOAD_FINISHED);                                    // Set flag that indicates to application that file upload is done
    break;

  }
  return(OK);

/************************ End of FileTransmitEvent ****************************/
}

The code below shows how to start the file upload and some extra checks and controls for safety.

      Test_FileURL[0] = 0;                                                      // Reset first pos in File URL string buffer.
      // Print the wanted file name for upload to string buffer, since we need this for the download URL in next test stage.
      snprintf(Test_FileURL, sizeof(Test_FileURL) - 1, "TestHelperTempFiles/TST_%s_%02d%02d%02d_%02d%02d.md", ccp_p_thing_id, pDate->tm_year-100, pDate->tm_mon + 1, pDate->tm_mday, pDate->tm_hour, pDate->tm_min);                                           
      ETIF_DEBUG_STR(ETIF_DEBUG_TRACE, ("Trying file upload to: %s", Test_FileURL));
      if(f_stat("TstAudit.txt", &flnfo) == FR_OK)                               // Check that the test audit file is present and also get file info, including size.
        {
          ETIF_FLAG_RES(HTTP_CLIENT_FILE_TRANSFER_FINNISHED);                   // Reset finished flag (this flag is added in ETIF_Registry.h)
          filexferStatus = ETIF_Resource_PutFile(Test_FileURL, flnfo.fsize, FileUploadEvent);   // Call the file upload API with the URL, the size of the file and the upload event handler.
          ETIF_DEBUG_STR(ETIF_DEBUG_TRACE, ("File XFER start: %s", TheFileXferStartStatuses[filexferStatus + ETIF_RESOURCE__XFER_STATUS_OFFSET]));
          FileXferTestStartTimeoutEvent(ETIF_TIMER_EVENT_SSH, 45000);           // Set a timeout timer.
        }

      ETIF_THREAD_WAIT_UNTIL(ETIF_FLAG_CHK(FILE_TRANSFER_STARTED) || tFileXferTestStartTimeout);    // Wait for HTTP-Client to set FILE_TRANSFER_STARTED flag or timeout
      
      if((filexferStatus == ETIF_RESOURCE__FILE_XFER_START_OK) && !tFileXferTestStartTimeout)       // If transfer started, and not timeout
      {
        FileXferTestStartTimeoutEvent(ETIF_TIMER_EVENT_STP);                                        // Stop timeout timer
        ETIF_THREAD_WAIT_UNTIL(ETIF_FLAG_CHK(FILE_UPLOAD_FINISHED));                                // Wait until HTTP-client/upload event handler sets the flag FILE_UPLOAD_FINISHED
        TSF_AuditAppendTestComment("File transfer finished, file uploaded.");
        TSF_AuditAppendTestVerdict("OK");                                                           // Append test verdict.  
        file_upload_ok = TRUE;
        ETIF_FLAG_RES(FILE_UPLOAD_FINISHED);
        ETIF_FLAG_RES(FILE_TRANSFER_STARTED);
      }
      else{                                                                                         // File transfer start timeout
        TSF_AuditAppendTestComment("File transfer start timeout");
        TSF_AuditAppendTestVerdict("FAILED");  
        TestResults->NbFaild++;
      }
      tFileXferTestStartTimeout = 0;
      tTest_PSURLTimeout = 0;  

How to download a file

A typical event handler for this kind of operation looks like this:

/*******************************************************************************
*                                                                              *
*           F I L E   D O W N L O A D   E V E N T   H A N D L E R              *
*                                                                              *
*******************************************************************************/

u8 TestFileDownloadEvent(s8 Cmd, u8 *pBuffer, u16 Nb)
{
  static u32 Total=0;                                                           
  static tBOOL dl_file_open_ok = FALSE;
  static FRESULT f_open_result;
  
  switch(Cmd)
  {
    case ETIF_RESOURCE_FILE_DATA_RECEIVED:                                                      // Data has been received and needs to be handled, in this case, stored to a file
      if (Total == 0)                                                                           // Is this the first set of data in the download?
      {                                                                                         // Yes
       f_open_result = f_open(&downloadfile, p_filenames[1], FA_WRITE | FA_CREATE_ALWAYS);      // Open file
       ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("File open result: %s", p_fresult[f_open_result]));    
       if(f_open_result == FR_OK)                                                               // Was file opened successfully?
       {
         dl_file_open_ok = TRUE;                                                                // Yes!
       }
      }
      if(dl_file_open_ok)                                                                       
      {
        UINT bw;
        Total+=Nb;
        f_write(&downloadfile, pBuffer, Nb, &bw);                                               // Store data   
        ETIF_DEBUG_STR(ETIF_DEBUG_TRACE, ("Received %u total %lu (written: %u)", Nb, Total, bw));
      }
      else
      {
        ETIF_FLAG_SET(HTTP_CLIENT_FILE_TRANSFER_ERROR);                                         // If not able to open file, throw error
        ETIF_FLAG_SET(FILE_DOWNLOAD_FINISHED);                                                  // And end file transfer session
      }
    break;

    case ETIF_RESOURCE_FILE_TRANSFER_ERROR:                                                     // Handle file transfer error thrown by HTTP-client
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("File download ended in error!"));
        ETIF_FLAG_SET(FILE_DOWNLOAD_FINISHED);
        f_close(&downloadfile);                                                                 // Make sure open file is closed before leaving

    break;

    case ETIF_RESOURCE_FILE_SESSION_END:                                                        // Handle file session done event from http-client

      Total+=Nb;

      ETIF_DEBUG_STR(ETIF_DEBUG_TRACE, ("End of file transfer, received %u total %lu", Nb, Total));
      f_close(&downloadfile);                                                                   // Make sure open file is closed before leaving

      Total=0;

      ETIF_FLAG_SET(FILE_DOWNLOAD_FINISHED);

    break;

  }

  return(OK);

/************************ End of FileReceiverEvent ****************************/
}

The code below shows how to start the file download and some extra checks and controls for safety.

        memcpy(Filename, Test_FileURL, strlen(Test_FileURL));                                           // Backup previously used filename.
        nprintf(Test_FileURL, sizeof(Test_FileURL) - 1, "things/%s/%s", ccp_p_thing_id, &Filename[0]);  // Add thingid to path
        ETIF_DEBUG_STR(ETIF_DEBUG_TRACE, ("Trying file download from: %s", Test_FileURL));
        {
          ETIF_FLAG_RES(HTTP_CLIENT_FILE_TRANSFER_FINNISHED);

          filexferStatus = ETIF_Resource_GetFile(Test_FileURL, TestFileDownloadEvent);                  // Call the file download API with the URI and the Event handler
          ETIF_DEBUG_STR(ETIF_DEBUG_TRACE, ("File XFER start: %s", TheFileXferStartStatuses[filexferStatus + ETIF_RESOURCE__XFER_STATUS_OFFSET]));
          FileXferTestStartTimeoutEvent(ETIF_TIMER_EVENT_SSH, 45000);                                   // Set a timeout timer.
        }
        ETIF_THREAD_WAIT_UNTIL(ETIF_FLAG_CHK(FILE_TRANSFER_STARTED) || tFileXferTestStartTimeout);      // Wait for HTTP-Client to set FILE_TRANSFER_STARTED flag or timeout      
        if(!tFileXferTestStartTimeout && (filexferStatus == ETIF_RESOURCE__FILE_XFER_START_OK))         // If transfer started, and not timeout
        {
          FileXferTestStartTimeoutEvent(ETIF_TIMER_EVENT_STP);                                          // Stop timeout timer
          ETIF_THREAD_WAIT_UNTIL(ETIF_FLAG_CHK(FILE_DOWNLOAD_FINISHED));                                // Wait until HTTP-client/download event handler sets the flag 
          ETIF_FLAG_RES(FILE_TRANSFER_STARTED);                                                         // FILE_DOWNLOAD_FINISHED
          
        /*************************** Check file. ******************************/
          extern char * p_fresult[];
          static FILINFO orgfilnfo,dlfilnfo;
          static s32 fsizechk;
          static c8 charbuforg[101];
          static c8 charbufdl[101];
          static UINT bytesreadorg;//,bytesreaddl;
          
          if((f_stat(p_filenames[0], &orgfilnfo) == FR_OK) && (f_stat(p_filenames[1], &dlfilnfo) == FR_OK))
          { // Both files exist
            if( orgfilnfo.fsize >= dlfilnfo.fsize)
            {
              fsizechk = dlfilnfo.fsize;
              if((f_open(&uploadfile, p_filenames[0], FA_READ) == FR_OK) && (f_open(&downloadfile, p_filenames[1], FA_READ) == FR_OK))
              {
                while(fsizechk > 0)
                {
                  if(fsizechk < 100)
                  {
                    f_read(&uploadfile, &charbuforg, fsizechk, &bytesreadorg); 
                    f_read(&downloadfile, &charbufdl, fsizechk, &bytesreadorg);
                  }
                  else
                  {
                    f_read(&uploadfile, &charbuforg, 100, &bytesreadorg); 
                    f_read(&downloadfile, &charbufdl, 100, &bytesreadorg);                
                  }
                  if(strcmp(charbuforg, charbufdl))
                  {
                    TSF_AuditAppendTestComment("File transfer test error: Files does not match");
                    TSF_AuditAppendTestVerdict("FAIL");  
                    break;
                  }
                  fsizechk-=100;
                  //printf("%s", &charbuf);
                  memset(charbuforg, 0, sizeof(charbuforg));
                  memset(charbufdl, 0, sizeof(charbufdl));
                }
                f_close(&uploadfile); 
                f_close(&downloadfile);
                TSF_AuditAppendTestComment("File transfer finished, file downloaded.");
                TSF_AuditAppendTestVerdict("OK");  
              }
              else
              {
                TSF_AuditAppendTestComment("File transfer error: Unable to open file for compare.");
                TSF_AuditAppendTestVerdict("FAIL");          
              }            
            }
            else
            {
              TSF_AuditAppendTestComment("File transfer error: Wrong File size.");
              TSF_AuditAppendTestVerdict("FAIL");          
            }
            
          }
          else
          {
            TSF_AuditAppendTestComment("File transfer error:: File missing.");
            TSF_AuditAppendTestVerdict("FAIL");  
          }
          
          ETIF_FLAG_RES(FILE_DOWNLOAD_FINISHED);
        }
        else{
          TSF_AuditAppendTestComment("File transfer start timeout");
          TSF_AuditAppendTestVerdict("FAILED");  
          TestResults->NbFaild++;
        }
      }
      Test_FileURL[0] = 0;
      tFileXferTestStartTimeout = 0;
      tTest_PSURLTimeout = 0; 
    }
          

ETIF_TestGPS.c

Raw ETIF_TestGPS.c In this section some GPS functionaliy is described

How to open and close the GPS Stream

To open the GPS-stream all that has to be done is to provide a handle and the uri-prefix of cellular.gps://.
To handle events on the stream a stream event handler must be provided. Open:

ETIF_StreamClientOpen(&hGPSStream, "cellular.gps://", 0, StreamEvent_GPS); // Subscribe to GPS coordinates

Close:

ETIF_StreamClientClose(&hGPSStream);

Example GPS Stream handler

tStreamEventRet StreamEvent_GPS(tStreamEventHandlerCmd Cmd, s16 (*StreamCallBack)(void *Dest))
{
  static u8 NbGPSPayLoad = 0;
  static u8 BuGPSPayLoad[100];
   
  switch(Cmd)
  {
      case STREAM_DATA_RECEIVE:
      {
        while(StreamCallBack(&BuGPSPayLoad[NbGPSPayLoad++]) && (NbGPSPayLoad < sizeof(BuGPSPayLoad)));          // Fetch all the GPS data from the stream
        BuGPSPayLoad[NbGPSPayLoad]=0;
        NbGPSPayLoad=0;
        if(strstr((const char *)BuGPSPayLoad, "$GPGGA"))                                                        // Check if data contains GPGGA payload
        {
          if(NMEA_DecodeGpsSentence(&BuGPSPayLoad[0], 100))                                                     // Call NMEA decoder with pointer to payload
          {
            ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("GPS Number of satellites: %u", atoi((char const *)gps_info.no_satellites)));
            if(gps_info.latitude[0] && gps_info.longitude[0])
            {
                snprintf(lat_lng, 100, "%s,%s", gps_info.decimal_latitude, gps_info.decimal_longitude);
                ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("GPS latitude/longitude decimal: %s,%s", gps_info.decimal_latitude, gps_info.decimal_longitude));
                ETIF_FLAG_SET(GPS_LOCK_ACHIEVED);                                                               // Set flag for test
            }
          }
          else
          {
            ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("GPS Number of satellites: %u", atoi((char const *)gps_info.no_satellites)));
          }
        }

      }
        break;
      case STREAM_OPEN:
      {
         
      }
      break;
      
      case STREAM_CLOSED:
      {
        hGPSStream = 0;
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream Closed"));
      }
      break;
      
      default:
      {
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream unhandled/unknown event. > %u <", Cmd));
      }
      break;
  }
  return(0);

/***************************** End of function ********************************/
}

How to restart GPS stream if it is stopped because of no lock

      ETIF_THREAD_WAIT_UNTIL((ETIF_FLAG_CHK(GPS_LOCK_ACHIEVED)) || (hGPSStream <= 0));  // Wait until either flag is set that lock is achieved or stream closes
                                                                                        // by itself due to no lock, perhaps because of cold start.
      if(ETIF_FLAG_CHK(GPS_LOCK_ACHIEVED))
      {
        snprintf(Tmp, sizeof(Tmp), "GPS FIX Achieved, coordinates= %s", lat_lng);
        TSF_AuditAppendTestComment(Tmp);
        TSF_AuditAppendTestVerdict("OK");
      }
      else
      {
        TSF_AuditAppendTestComment("GPS Timed out, no fix, trying to restart");
        TSF_AuditAppendTestVerdict("OK");
/******************* Test stage 3 - Try Restart GPS Stream ********************/

        TestStage++;
        TSF_AuditAppendTestStage((c8 *)&TestStage_RestartGPSStream, TestStage);

        ETIF_StreamClientOpen(&hGPSStream, "cellular.gps://", 0, StreamEvent_GPS); // Subscribe to GPS coordinates

        if(hGPSStream > 0)
        {
          TSF_AuditAppendTestVerdict("OK");
        }
        else
        {
          TestResults->NbFaild++;
          TSF_AuditAppendTestComment("Failed to reopen GPS Stream");
          TSF_AuditAppendTestVerdict("FAILED");
        }

        ETIF_THREAD_DELAY(1000);
      }
      ETIF_THREAD_DELAY(5000);
      ETIF_StreamClientClose(&hGPSStream);

  }

ETIF_TestLAN.c

Raw ETIF_TestLAN.c In this section, it is shown how to open and handle a local LAN socket.

How to open and close a local socket

To open a LAN-socket all that has to be done is to provide a handle, the uri-prefix of ethernet.tcp:// followed by the ip and port.
To handle events on the stream a stream event handler must be provided.

Open:

ETIF_StreamClientOpen(&hStreamHandle, "ethernet.tcp://192.168.0.231:8887", 0, StreamEventTestLAN);

Close:

ETIF_StreamClientClose(&hStreamHandle);

How to send data on socket

ETIF_StreamClientWrite(&hStreamHandle, "ECHO\r", 5);    // Stream handle, string or pointer to string and number of data to send.

Example stream handler

/*******************************************************************************
*                                                                              *
*               T C P   S T R E A M   E V E N T   H A N D L E R                *
*                                                                              *
*******************************************************************************/
tStreamEventRet StreamEventTestLAN(tStreamEventHandlerCmd Cmd, s16 (*StreamGetCallBack)(void *Dest))
{

  switch(Cmd)
  {
      case STREAM_DATA_RECEIVE:

        NbServerDataInput=0;
        while(StreamGetCallBack(&ServerDataInput[NbServerDataInput++]) && (NbServerDataInput < (sizeof(ServerDataInput)-1)));
        ServerDataInput[NbServerDataInput]=0;

      break;

      case STREAM_OPEN:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream has opened."));
     break;

      case STREAM_CLOSED:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream has closed."));
      break;

      case STREAM_EMPTY:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream all data sent."));
      break;

      default:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream unhandled/unknown event."));
      break;
  }

  return(0);
/***************************** End of function ********************************/
}

ETIF_TestMISC.c

Raw ETIF_TestMISC.c In this section it is shown how to trigger a user reset. The tests also tests that the watchdog timer is functional and the built in functionality for setting the RTC at connection time is functional.

How to do a user reset

Simply call this macro:

ETIF_SYSTEM_REBOOT();

ETIF_TestNVM.c

Raw ETIF_TestNVM.c In this section usage of non volatile configuration parameters are shown. The non volatile parameters are added in the NvmCfg_3GGV0XCCD.h-file. After the section below, any parameters may be added, but the below section is reserved.

/*******************************************************************************
*                                Configuration
*******************************************************************************/
//              ref_name              type   min_value   max_value  default_value )
//******************* Start of production data ********************************/
NCFG_AddNvmCfg( dummy_field_for_test,   u8,          10,       100,        100 )
NCFG_AddNvmCfg( dummy_field2_for_test, u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( snr_consec,            u32,          0, 0xFFFFFFFF,          0 )      // Holds the consec number of the serial number of this unit.
NCFG_AddNvmCfg( prod_test_result,       u8,          0,       0xFF,       0xFF )      // Indicates the test result from the last performed production test. 0 means tested OK, 0xFF means not tested and other values are error codes.
NCFG_AddNvmCfg( prod_test_time,        u32,          0, 0xFFFFFFFF,          0 )      // Holds the time (in seconds since 2000-01-01 0:00) when the first production test was performed.
NCFG_AddNvmCfg_Struct( mac_address,   tMAC,          _DEFAULT_MAC_ADDR_        )      // Holds the MAC address of this unit.
NCFG_AddNvmCfg( server_update_interval,   u32,       5, (14*3600),     (10*60) )     // Update interval for the values sent to the server, in seconds.

// Not used fields for future use
NCFG_AddNvmCfg( not_used_field1,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field2,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field3,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field4,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field5,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field6,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field7,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field8,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field9,       u32,          0, 0xFFFFFFFF,          0 )
NCFG_AddNvmCfg( not_used_field10,      u32,          0, 0xFFFFFFFF,          0 )

#define last_prod_cfg_field            not_used_field10
//******************** End of production data *********************************/

/*******************************************************************************
/       DO NOT MODIFY/ADD/REMOVE ANY NVMCFG MEMBERS ABOVE THIS POINT
*******************************************************************************/

How to store value in non volatile configuration

The NCFG values are set using different macros. Normal non string, struct or array type values: NCFG_SetValue(ref_name, value); String type values: NCFG_SetData_String( ref_name, p_src, size ) Struct type values: NCFG_SetData_Struct( ref_name, struct_data ) Array type values: NCFG_SetData_Array( ref_name, index, data )

How to read value from non volatile configuration

The NCFG values are read using different macros. Normal non string, struct or array type values: NCFG_GetValue( ref_name ); String type values: NCFG_GetPointer_String( ref_name ) Struct type values: NCFG_GetData_Struct( ref_name ) Array type values: NCFG_GetData_Array( ref_name, index )

ETIF_TestProxy.c

Raw ETIF_TestProxy.c In this section example usage of the MQTT Proxy is shown

How to open the MQTT-Proxy stream

Simply call the ETIF_ResourceProxyOpenfunction with a Stream event handler. ETIF_ResourceProxyOpen(StreamEvent_ResourceProxy);

How to send data to proxy topic

ETIF_ResourceProxyWrite("\n", 1);

Example stream event handler for MQTT Proxy

/*******************************************************************************
*                                                                              *
*            P R O X Y   S T R E A M   E V E N T   H A N D L E R               *
*                                                                              *
*******************************************************************************/
tStreamEventRet StreamEvent_ResourceProxy(tStreamEventHandlerCmd Cmd, s16 (*StreamGetCallBack)(void *Dest))
{

  switch (Cmd)
  {

    case STREAM_DATA_RECEIVE:
      ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Received data on proxy stream!"));

        NbProxyDataInput=0;
        while(StreamGetCallBack(&ProxyDataInput[NbProxyDataInput++]) && (NbProxyDataInput < (sizeof(ProxyDataInput)-1)));
        ProxyDataInput[NbProxyDataInput]=0;

        printf("\r\nProxydata: %s",ProxyDataInput); 
        ETIF_DEBUG_BIN(ETIF_DEBUG_TRACE, ("Received on Proxy Stream"), ProxyDataInput, NbProxyDataInput);

        ETIF_FLAG_SET(PROXY_DATA_AVAILABLE);
        
    break;

    case STREAM_OPEN:
      ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Proxy stream has opened."));
      ETIF_FLAG_SET(PROXY_STREAM_OPEN);
    break;

    case STREAM_CLOSED:
      ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Proxy stream has closed."));
      ETIF_FLAG_RES(PROXY_STREAM_OPEN);
      
    break;

    case STREAM_EMPTY:
      ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Proxy stream all data sent."));
    break;

    default:
      ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Proxy stream unhandled/unknown event."));
    break;
  }

  return(0);

/***************************** End of function ********************************/
}

ETIF_TestRESOURCE_THRESHOLDS.c

Raw ETIF_TestRESOURCE_THRESHOLDS.c In this section the effect of resource thresholds are explained. Using flags set in the resourceEventHandler for the resources used for the test, the test cases are built. The threshold is set when registering the resource in the ETIF_AppRegistry.h-file

Thresholds for non string type resources

When the new value of a non string type resource is set, the resource is ALWAYS sent if the threshold is set to 0.
If the threshold is set to something larger than 0, the value in the resource registry is only updated if the absolute value of the deviation is greater than the threshold.

Thresholds for string type resources

When the new value of a string type resource is set, the resource is ALWAYS sent if the threshold is set to 0.
If the threshold is set to something larger than 0, the value in the resource registry is only updated if string value have at least one character that is different from the previous string.

ETIF_TestSERIAL.c

Raw ETIF_TestSERIAL.c In this section some serial stream functionality is in focus

How to open an RS232 stream

When opening a an RS232 stream, the stream uri needs to contain serial://uart2,followed by the serial parameters in this order: bps, number of databits, number of stopbits, parity.
The choices for parity is n/N = none, o/O = Odd or e/E = Even.

Example:

    ETIF_StreamClientOpen(&hStreamHandle1st, "serial://uart2,9600,7,1,O", 0, StreamEvent_RS232);

How to open an RS485 stream

When opening a an RS485 stream, the stream uri needs to contain serial://uart0,followed by the serial parameters in this order: bps, number of databits, number of stopbits, parity.
The choices for parity is n/N = none, o/O = Odd or e/E = Even.

Example:

    ETIF_StreamClientOpen(&hStreamHandle1st, "serial://uart0,115200,8,1,n", 0, StreamEvent_RS485);

Example Stream Event Handler for RS232 stream

/*******************************************************************************
*                                                                              *
*            R S 2 3 2   S T R E A M   E V E N T   H A N D L E R               *
*                                                                              *
*******************************************************************************/
tStreamEventRet StreamEvent_RS232(tStreamEventHandlerCmd Cmd, s16 (*StreamGetCallBack)(void *Dest))
{

  switch(Cmd)
  {
      case STREAM_DATA_RECEIVE:
        if( NbSerialDataInput < 1500 )
        {
          while( StreamGetCallBack( &SerialDataInput[NbSerialDataInput++]) )
          {
            if( NbSerialDataInput >= 1500 )
            {
              break;
            }
          }
          SerialDataInput[sizeof(SerialDataInput)-1]=0;
          ExtInputBufferReadyEvent(ETIF_TIMER_EVENT_SSH, 100);
        }

        
      break;

      case STREAM_OPEN:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream has opened."));
        //ETIF_FLAG_SET(TCP_SOCKET_CONNECTED);
     break;

      case STREAM_CLOSED:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream has closed."));
        //ETIF_FLAG_RES(TCP_SOCKET_CONNECTED);
      break;

      case STREAM_EMPTY:
        //ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream all data sent."));
      break;

      default:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream unhandled/unknown event."));
      break;
  }

  return(0);
/***************************** End of function ********************************/
}

Example Stream Event handler for RS485 stream

/*******************************************************************************
*                                                                              *
*            R S 2 3 2   S T R E A M   E V E N T   H A N D L E R               *
*                                                                              *
*******************************************************************************/
tStreamEventRet StreamEvent_RS485(tStreamEventHandlerCmd Cmd, s16 (*StreamGetCallBack)(void *Dest))
{

  switch(Cmd)
  {
      case STREAM_DATA_RECEIVE:
        if( NbSerialDataInput < 1500 )
        {
          while( StreamGetCallBack( &SerialDataInput[NbSerialDataInput++]) )
          {
            if( NbSerialDataInput >= 1500 )
            {
              break;
            }
          }
          SerialDataInput[sizeof(SerialDataInput)-1]=0;
          ExtInputBufferReadyEvent(ETIF_TIMER_EVENT_SSH, 100);
        }  
        
      break;

      case STREAM_OPEN:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream has opened."));
        //ETIF_FLAG_SET(TCP_SOCKET_CONNECTED);
     break;

      case STREAM_CLOSED:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream has closed."));
        //ETIF_FLAG_RES(TCP_SOCKET_CONNECTED);
      break;

      case STREAM_EMPTY:
        //ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream all data sent."));
      break;

      default:
        ETIF_DEBUG_ASC(ETIF_DEBUG_TRACE, ("Stream unhandled/unknown event."));
      break;
  }

  return(0);
/***************************** End of function ********************************/
}

ETIF_TestSuspendResume

Raw ETIF_TestSuspendResume.c By default, at boot, the resourcehandler / cloud connectivity functionality is active but it can be disabled if application software does not want this functionality.
In this section it is shown how the Suspend and resume functionality for the Cloud connectivity can be used.

Suspend

To suspend the resource handler, the function ETIF_ResourceHandlerSuspend() is called. The application can consider the Resource Handler / Cloud Connection to be suspended when the flag CLOUD_RESOURCE_HANDLER_DISSABLED has been set and the flag CLOUD_CONNECTED is no longer set.

Resume

To resume the resource handler, the function ETIF_ResourceHandlerResume() is called. The application can consider the Resource Handler / Cloud Connection to be resume/enabled when the flag CLOUD_RESOURCE_HANDLER_DISSABLED has been cleared and the flag CLOUD_CONNECTED has been set.

Thread Control functionality

In ETIF, there is functionality to catch different types of thread misbehaviour. When a thread finishes in a way that it is not supposed to finish, some cleaning up may be needed to avoid running out of resources like timers and memory.
In this section this functionality is explained and exemplified.

Thread timeout - catch

Raw ETIF_TestSuspendResume.c If a thread does not finish it´s tasks within an alotted timeframe, it can be made to timeout.
In this section it is shown how to setup the timeout and how to clean up the thread in case of a timeout.

  ETIF_THREAD_TIMEOUT_BEGIN(10000);                                             // To add timeout functionality, add this 
  {                                                                             // after the ´ETIF_THREAD_BEGIN` macro.
    /************ Test stage 1 - Test thread timeout in child ************/    
    TSF_AuditAppendTestStage((c8 *)&TestStage_ThreadTimeoutChild, TestStage);   
    while(--thread_timeout_wait)
    {
      printf(".");
      ETIF_THREAD_DELAY(1000);
    }
  }
    
  ETIF_THREAD_TIMEOUT_CATCH:                                                    // If we get here, the thread has not
                                                                                // finished it´s activities in the alloted
    TSF_AuditAppendTestComment("Thread timeout is functional.");                // time. Now actions may be taken based on
    TSF_AuditAppendTestVerdict("OK");                                           // this fact.

      
  ETIF_THREAD_TIMEOUT_END();                                                    // This macro call have to be here too
                                                                                // before the ETIF_THREAD_END macro.

Thread abort - catch

Raw ETIF_TestThreadCtrlAbortCatch.c
Raw ETIF_TestThreadCtrlTimeoutChildBlocking.c
A thread may be aborted by the parent thread if the applications requires this.
How to do this, and how the aborted thread can clean up after being aborted is shown here. It may not be apparent that the subthread is aborted in the code below, but the subthread is in fact aborted if the parent thread times out. The ETIF_TestThreadCtrlTimeoutChildBlocking.c is another example of the same functionality, but is designed to test a different aspect of the thread control functionality.

/*******************************************************************************
*                                                                              *
*     S U B T H R E A D   T O   B E   A B O R T E D   W I T H   C A T C H      *
*                                                                              *
*******************************************************************************/

tETIF_THREAD SubThreadToBeAbortedWithCatch(tETIF_SUB_THREAD)
{

    ETIF_THREAD_BEGIN(CHILD);

    while(1)
    {
      ETIF_THREAD_YIELD();                                                      // This subthread really does not to anything
    }                                                                           // but yield in a loop
    
    ETIF_THREAD_CANCEL_CATCH:
    
    sub_has_been_aborted = TRUE;      

    ETIF_THREAD_END();

/*********************** E N D   O F   F U N C T I O N ************************/
}
  ETIF_THREAD_TIMEOUT_BEGIN(10000);

  /************ Test stage 1 - Test thread abort with catch************/   
  TSF_AuditAppendTestStage((c8 *)&TestStage_ThreadAbortCatch, TestStage);

  ETIF_THREAD_SPAWN(SubThreadToBeAbortedWithCatch(ETIF_SUB_THREAD));    // Spawn the subtread
  
  ETIF_THREAD_TIMEOUT_CATCH:                                            // Since the subtread will never return, timeout will
                                                                        // happen
  ETIF_THREAD_DELAY(1000);
    
  if(sub_has_been_aborted)                                              // This boolean is set to true in the catch/cleanup
  {                                                                     // of the subtread
         // If here - Thread break works
    TSF_AuditAppendTestComment("Sub thread has been aborted");
    TSF_AuditAppendTestVerdict("OK");    
    TestResults->NbTests=TestStage;
  }
  else
  {
    TestResults->NbFaild++;
    TSF_AuditAppendTestComment("Sub thread not aborted");
    TSF_AuditAppendTestVerdict("FAILED");
    TestResults->NbTests=TestStage;
  }

Thread break - catch

Raw ETIF_TestThreadCtrlBreak.c

tETIF_THREAD Thread_TestThreadCtrlBreak(tETIF_SUB_THREAD, tTestResult *TestResults)
{

  static u8 i;
  static time_t timestart, timestop;
  static u8 thread_timeout_wait = 15;
  static tBOOL tVar= 1;
  
  ETIF_THREAD_BEGIN(CHILD);
  TestStage++;
  TSF_AuditAppendTest("Test Thread Control: Break When");
  //ETIF_THREAD_DELAY(1200);
  
  TestResults->NbTests=0;
  TestResults->NbFaild=0;
 

  /************ Test stage 1 - Test ETIF_THREAD_BREAK_WHEN ************/   
  TSF_AuditAppendTestStage((c8 *)&TestStage_ThreadBreakWhen, TestStage);

  ETIF_THREAD_BREAK_WHEN(tVar);                                                 // In this test, the condition for break is 
                                                                                // quite simple
  // If here, then break does not work.
  TestResults->NbFaild++;
  TSF_AuditAppendTestComment("Thread Break does not work");
  TSF_AuditAppendTestVerdict("FAILED");
  TestResults->NbTests=TestStage;
  TestStage = 0;

  ETIF_THREAD_BREAK_CATCH;                                                      // If we skip here, tread break works as
                                                                                // expected
  // If here - Thread break works
  TSF_AuditAppendTestComment("Thread Break is functional");
  TSF_AuditAppendTestVerdict("OK");    
  TestResults->NbTests=TestStage;
  TestStage = 0;    
  ETIF_THREAD_BREAK_END();
  
  ETIF_THREAD_END();

/*********************** E N D   O F   F U N C T I O N ************************/
}

FAQ