IRI Example Programs

The ITK includes a number of example programs for Windows, Linux, and OS X. These examples demonstrate many of the features of the ITK and Indy Reader Modules. Each example is complete and self contained, and can be compiled and run without any modification. These examples contrast with the Configuration Examples, which contain code snippets that demonstrate key aspects of numerous specific use cases of the Indy Modules.

The examples are listed below, starting with the basic IRI_Intro example, with all of the remaining examples following in alphabetical order, followed by the platform ports and ipj_util code included with the examples.

Examples Directory Structure

Several example IRI programs (all IRI_*.c files) are provided with the release in the following locations:

ITK_C\Examples\ipj_util.c
ITK_C\Examples\ipj_util.h
ITK_C\Examples\IRI_Access.c
ITK_C\Examples\IRI_Antenna_Descriptors.c
ITK_C\Examples\IRI_Change_Baudrate.c
ITK_C\Examples\IRI_Empty.c
ITK_C\Examples\IRI_External_Antenna_Mux.c
ITK_C\Examples\IRI_GPIO.c
ITK_C\Examples\IRI_Intro.c
ITK_C\Examples\IRI_Loader.c
ITK_C\Examples\IRI_Multiple_Readers.c
ITK_C\Examples\IRI_Power_Management.c
ITK_C\Examples\IRI_Select.c
ITK_C\Examples\IRI_Test_CW_PRBS.c
ITK_C\Examples\Makefile
ITK_C\Examples\VS2005\Examples.sln
ITK_C\Examples\VS2005\README.txt
ITK_C\Examples\VS2005\stdbool.h
ITK_C\Examples\VS2005\stdint.h
ITK_C\Examples\VS2012\Examples.sln
ITK_C\Examples\VS2012\README.txt
ITK_C\Examples\VS2012\stdbool.h

The example programs are accompanied by example implementations of the platform specific code for a few platforms:

ITK_C\Library\platform_linux.c
ITK_C\Library\platform_osx.c
ITK_C\Library\platform_win32.c

These are documented below in the Platform Port Examples section.

The example programs are also accompanied by the ipj_util code, which implements reader functionality like performing inventory and tag read processing.

It is documented below in the ipj_util section.

Building, Running, and Debugging the Examples

Building and running the examples in Visual Studio in Windows

To build the examples in Visual Studio, open the one of the Examples.sln Visual Studio solutions and build it using the GUI.

To run the built examples in Windows using the command line, run the executable using the correct COM port as the argument, for example, type IRI_Intro COM1 .

Note

The correct COM port can easily be determined using the Indy Demo Tool GUI.

Debugging the examples in Visual Studio in Windows

To debug the examples in Visual Studio, perform the following steps:

  1. Right click on the desired example and select “Set as Startup Project”.
  2. Open the properties of the desired example project by right clicking the project and selecting “Properties”.
  3. Under “Configuration Properties”, select “Debugging”.
  4. In the “Command Arguments” field, enter the COM port that connects to your Indy device (e.g. COM1 ).
  5. Under “Configuration Properties”, expand “Linker” and select “Debugging”.
  6. Set the “Generate Debug Info” setting to “Yes (/DEBUG)”.
  7. Close the project configuration dialog.
  8. Press the “Local Windows Debugger” button, and debugging should begin.

Building and running the examples in the Linux command line

To build the examples from the Linux command line, type make in the \Examples\ directory

To run the examples in Linux in the console, run the output of the build using the /dev/ device as the argument, for example, type output/IRI_Intro /dev/ttyUSB0 .

IRI_Intro Example

The IRI_Intro example connects to an Indy Module and performs basic inventory for 1 second, printing read EPCs to the console or command line.

IRI_Intro - Source Code

IRI_Intro source code is provided in IRI_Intro.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"

/* PURPOSE: This example illustrates the use of the basic inventory operation
   and to retrieve Indy Module information. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 1000

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error = E_IPJ_ERROR_SUCCESS;
    uint32_t value;
    ipj_key_info keyinfo;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    /* Reader Info */
    printf("Indy Module Info\n");
    error = ipj_get_value(&iri_device, E_IPJ_KEY_SERIAL_NUMBER, &value);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_get_value E_IPJ_KEY_SERIAL_NUMBER");
    printf("Serial Number      : %d\n", value);
    ipj_get_value(&iri_device, E_IPJ_KEY_BOOTSTRAP_VERSION, &value);
    printf("Bootstrap Version  : 0x%08X\n", value);
    ipj_get_value(&iri_device, E_IPJ_KEY_BOOTSTRAP_CRC, &value);
    printf("Bootstrap CRC      : 0x%08X\n", value);
    ipj_get_value(&iri_device, E_IPJ_KEY_APPLICATION_VERSION, &value);
    printf("Application Version: 0x%08X\n", value);
    ipj_get_value(&iri_device, E_IPJ_KEY_APPLICATION_CRC, &value);
    printf("Application CRC    : 0x%08X\n", value);
    ipj_get_value(&iri_device, E_IPJ_KEY_MICROPROCESSOR_ID, &value);
    printf("Microprocessor     : 0x%08X\n", value);
    ipj_get(&iri_device, E_IPJ_KEY_MICROPROCESSOR_ID, 0, 1, &value);
    printf("Microprocessor Id  : 0x%08X", value);
    ipj_get(&iri_device, E_IPJ_KEY_MICROPROCESSOR_ID, 0, 2, &value);
    printf("-0x%08X", value);
    ipj_get(&iri_device, E_IPJ_KEY_MICROPROCESSOR_ID, 0, 3, &value);
    printf("-0x%08X", value);
    printf("\n\n");

    IPJ_CLEAR_STRUCT(keyinfo);

    /* Verify that we can indeed write the ANTENNA_TX_POWER key */
    error = ipj_get_info(&iri_device, E_IPJ_KEY_ANTENNA_TX_POWER, &keyinfo);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_get_info E_IPJ_KEY_ANTENNA_TX_POWER");

    /* Check to make sure the key has either write, or read/write permissions */
    if (keyinfo.key_permissions == E_IPJ_KEY_PERMISSIONS_READ_ONLY)
    {
        printf("ERROR: Unable to set ANTENNA_TX_POWER KEY\n\n");
        return -1;
    }

    /* Configure transmit power */
    error = ipj_set_value(&iri_device, E_IPJ_KEY_ANTENNA_TX_POWER, 2300);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_value E_IPJ_KEY_ANTENNA_TX_POWER");

    /* Start inventory */
    error = ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_perform_inventory");

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return error;
}

IRI_Access Example

The IRI_Access example demonstrates how to use the Access tag operation to write a tag’s EPC.

This example can be easily modified to write user memory by modifying the values of the E_IPJ_KEY_WRITE_MEM_BANK and E_IPJ_KEY_WRITE_WORD_POINTER keys.

The example can also be modified to read tag memory instead of writing it by changing the E_IPJ_KEY_TAG_OPERATION key to E_IPJ_TAG_OPERATION_TYPE_READ and configuring the READ keys listed below.

The following keys are used to configure the access write operation:

If a tag memory read is desired instead of a write, change the TAG_OPERATION key value to READ, and set these 3 keys instead of setting the last 3 keys above:

IRI_Access - Source Code

IRI_Access source code is provided in IRI_Access.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ipj_util.h"
#include "iri.h"

/* PURPOSE: This example illustrates the use of the tag operations
   Write and Write EPC. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 250

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

static ipj_error write_epc(ipj_iri_device* iri_device, uint16_t* epc)
{
    unsigned int i;
    ipj_error error;
    ipj_key_value key_value[16];
    ipj_key_value key_value_2[16];
    uint32_t key_value_count = 0;
    ipj_key_list key_list;
    ipj_key_list key_list_2;
    uint32_t key_list_count = 0;

    printf("Setting EPC to: ");

    ipj_util_print_epc(epc, 6, false);

    /* Enable tag write */
    key_value_count = 5;

    IPJ_CLEAR_STRUCT(key_list);
    IPJ_CLEAR_STRUCT(key_value);

    key_value[0].key = E_IPJ_KEY_TAG_OPERATION_ENABLE;
    key_value[0].value = true;

    key_value[1].key = E_IPJ_KEY_TAG_OPERATION;
    key_value[1].value = E_IPJ_TAG_OPERATION_TYPE_WRITE;

    key_value[2].key = E_IPJ_KEY_WRITE_MEM_BANK;
    key_value[2].value = E_IPJ_MEM_BANK_EPC;

    key_value[3].key = E_IPJ_KEY_WRITE_WORD_POINTER;
    key_value[3].value = 1;

    key_value[4].key = E_IPJ_KEY_WRITE_WORD_COUNT;
    key_value[4].value = 7;

    key_list_count = 1;
    key_list.key = E_IPJ_KEY_WRITE_DATA;
    key_list.list_count = 7;

    key_list.list[0] = 0x3000;

    /* Set last two halfwords of EPC to random numbers*/
    for (i = 1; i < 7; i++)
    {
        key_list.list[i] = epc[i - 1];
    }

    error = ipj_bulk_set(
            iri_device,
            &key_value[0],
            key_value_count,
            &key_list,
            key_list_count);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_bulk_set");

    /* Copy over the keys for the sake of simplicity */
    memcpy(&key_value_2, &key_value, sizeof(key_value));
    memcpy(&key_list_2, &key_list, sizeof(key_list));

    /* Set the desired key list read length*/
    key_list_2.length = 7;

    error = ipj_bulk_get(
            iri_device,
            key_value_2,
            key_value_count,
            &key_list_2,
            key_list_count);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_bulk_get");

    printf("\n");
    printf("Get Key Value Pairs\n");
    for (i = 0; i < key_value_count; i++)
    {
        printf(
                "Key: 0x%03x Value: %10d Bank Index:%d Value Index:%d\n",
                key_value_2[i].key,
                key_value_2[i].value,
                key_value_2[i].bank_index,
                key_value_2[i].value_index);
    }
    printf("\n");

    printf("Key List\n");
    printf(
            "Key: 0x%03x\t\t     Bank Index:%d Value Index:%d\t",
            key_list_2.key,
            key_list_2.bank_index,
            key_list_2.value_index);

    printf("\n[ ");
    for (i = 0; i < key_list_2.list_count; i++)
    {
        printf("0x%04X ", key_list_2.list[i]);
    }
    printf("]\n\n");

    return E_IPJ_ERROR_SUCCESS;
}

static ipj_error write_epc_feature(ipj_iri_device* iri_device, uint16_t* epc)
{
    unsigned int i;
    ipj_error error;
    ipj_key_value key_value[16];
    uint32_t key_value_count = 0;
    ipj_key_list key_list;
    uint32_t key_list_count = 0;

    printf("Setting EPC to: ");

    ipj_util_print_epc(epc, 6, false);

    /* Enable tag write */
    key_value_count = 4;

    IPJ_CLEAR_STRUCT(key_value);
    IPJ_CLEAR_STRUCT(key_list);

    key_value[0].key = E_IPJ_KEY_TAG_OPERATION_ENABLE;
    key_value[0].value = true;

    key_value[1].key = E_IPJ_KEY_TAG_OPERATION;
    key_value[1].value = E_IPJ_TAG_OPERATION_TYPE_WRITE_EPC;

    key_value[2].key = E_IPJ_KEY_WRITE_EPC_LENGTH_CONTROL;
    key_value[2].value = E_IPJ_WRITE_EPC_LENGTH_CONTROL_AUTO;

    key_value[3].key = E_IPJ_KEY_WRITE_WORD_COUNT;
    key_value[3].value = 6;

    key_list_count = 1;
    key_list.key = E_IPJ_KEY_WRITE_DATA;
    key_list.list_count = 6;

    /* Set EPC to random numbers*/
    for (i = 0; i < 6; i++)
    {
        key_list.list[i] = epc[i];
    }

    error = ipj_bulk_set(
            iri_device,
            &key_value[0],
            key_value_count,
            &key_list,
            key_list_count);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_bulk_set");

    return E_IPJ_ERROR_SUCCESS;
}

/* Main */
int main(int argc, char* argv[])
{
    /* Holder for EPC */
    uint16_t epc[6] = { 0 };

    /* Define error code */
    ipj_error error;

    /* Set-Get and Bulk_Set-Get variables */
    uint32_t i = 0;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Seed random number generator */
    srand((unsigned int) time(NULL));

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    /* Bulk_Set-Get example */
    /* Set a tag EPC */

    /* Generate 6 random numbers for EPC code */
    for (i = 0; i < 6; i++)
    {
        epc[i] = rand() % 0xffff;
    }

    /* Write EPC to tag */
    write_epc(&iri_device, epc);

    ipj_util_print_divider('*', 80);
    printf("EPC Write\n");
    ipj_util_print_divider('-', 80);

    /* Perform inventory to see results of EPC write */
    ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);

    /* Generate 6 random numbers for EPC code */
    for (i = 0; i < 6; i++)
    {
        epc[i] = rand() % 0xffff;
    }

    /* Write EPC to tag using WRITE_EPC feature */
    write_epc_feature(&iri_device, epc);

    ipj_util_print_divider('*', 80);
    printf("EPC Write Feature\n");
    ipj_util_print_divider('-', 80);

    /* Perform inventory to see results of EPC write */
    ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return 0;
}

IRI_Antenna_Descriptors Example

The IRI_Antenna_Descriptors example demonstrates how to use the Antenna Descriptors functionality of the modules, which allows physical or logical antennas to have their own individual configurations, using the key E_IPJ_KEY_ANTENNA_DESCRIPTORS.

IRI_Antenna_Descriptors - Source Code

IRI_Antenna_Descriptors source code is provided in IRI_Antenna_Descriptors.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"

/* PURPOSE: This file is used to demo the antenna descriptors feature, 
   using per antenna transmit power as an example. Each logical antenna has
   its own unique transmit power value, and these logical antennas can
   correspond to either physical antennas on the device, or antennas switched
   to using the external antenna mux feature. */

#define ANTENNA_SEQUENCE_OPTION_PHYSICAL 0
#define ANTENNA_SEQUENCE_OPTION_LOGICAL  1
#define NUM_ANTENNA_DESCRIPTORS          16
#define KVP_PER_ANTENNA_DESCRIPTOR       4

#define IPJ_EXAMPLE_DURATION_MS 10000

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

/* Each key-value pair consists of 32 bits to specify the key, bank index,
   and value index, followed by 32 bits that specify the value to be set. */
typedef struct
{
    uint16_t key;
    uint8_t bank_index;
    uint8_t value_index;

    uint32_t value;

} antenna_descriptor_kvp;

antenna_descriptor_kvp antenna_descriptors[NUM_ANTENNA_DESCRIPTORS][KVP_PER_ANTENNA_DESCRIPTOR] =
{
    /* Antenna Descriptor 1 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1000},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 2 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1100},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 3 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1200},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 4 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1300},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 5 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1400},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 6 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1500},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },
    
    /* Antenna Descriptor 7 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1600},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 8 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1700},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 9 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1800},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 10 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 1900},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 11 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 2000},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 12 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 2100},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 13 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 2150},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 14 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 2200},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },
    
    /* Antenna Descriptor 15 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 2250},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },

    /* Antenna Descriptor 16 */
    {
        {E_IPJ_KEY_ANTENNA_PHYSICAL_PORT, 0, 0, 1},
        {E_IPJ_KEY_ANTENNA_TX_POWER, 0, 0, 2300},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
    },
};

ipj_error set_logical_antenna_sequence_option();
ipj_error set_antenna_descriptors();
uint32_t get_key_bank_index_value_index_encoding(uint16_t key, uint8_t bank_index, uint8_t value_index);
ipj_error set_antenna_sequence();


int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error = E_IPJ_ERROR_SUCCESS;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    error = set_antenna_sequence();
    IPJ_UTIL_RETURN_ON_ERROR(error, "set_antenna_sequence");

    error = set_logical_antenna_sequence_option();
    IPJ_UTIL_RETURN_ON_ERROR(error, "set_logical_antenna_sequence_option");

    error = set_antenna_descriptors();
    IPJ_UTIL_RETURN_ON_ERROR(error, "set_antenna_descriptors");

    error = ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_perform_inventory");

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return error;
}

/* Setting the antenna sequence option to logical allows the antenna sequence
   key to be filled with logical antenna indexes, which do not have to
   correspond to physical antennas on the device. */
ipj_error set_logical_antenna_sequence_option()
{
    return ipj_set_value(
        &iri_device,
        E_IPJ_KEY_ANTENNA_SEQUENCE_OPTION,
        ANTENNA_SEQUENCE_OPTION_LOGICAL
    );
}

/* The antenna descriptor key consists of 16 banks of
   four key-value pairs. Each key value pair can be used
   to set the value of one other key when the associated
   antenna is to be switched to. */
ipj_error set_antenna_descriptors()
{
    ipj_error error;
    ipj_key_value key_value[16];
    unsigned int  key_value_count = 0;
    ipj_key_list  key_list;
    unsigned int  key_list_count = 1;
    unsigned int  i, j;

    memset(&key_value, 0, sizeof(key_value));
    memset(&key_list, 0, sizeof(key_list));

    key_list.has_key = true;
    key_list.key = E_IPJ_KEY_ANTENNA_DESCRIPTORS;

    key_list.list_count = 2 * KVP_PER_ANTENNA_DESCRIPTOR;

    key_list.has_bank_index = true;

    for(i = 0; i < NUM_ANTENNA_DESCRIPTORS; ++i)
    {
        key_list.bank_index = i;

        for(j = 0; j < KVP_PER_ANTENNA_DESCRIPTOR; ++j)
        {
            antenna_descriptor_kvp *kvp = &(antenna_descriptors[i][j]);

            key_list.list[(2*j)] = get_key_bank_index_value_index_encoding(
                kvp->key,
                kvp->bank_index,
                kvp->value_index
            );

            key_list.list[(2*j) + 1] = kvp->value;
        }

        error = ipj_bulk_set(&iri_device, &key_value[0], key_value_count, &key_list, key_list_count);

        if(error != E_IPJ_ERROR_SUCCESS)
        {
            break;
        }
    }

    return error;
}

/* Returns a 32 bit integer that contains the information specifying the key,
   bank index, and value index to set the value of. */
uint32_t get_key_bank_index_value_index_encoding(uint16_t key, uint8_t bank_index, uint8_t value_index)
{
    uint32_t result = key | ((bank_index & 0xff) << 16) | ((value_index & 0xff) << 24);

    return result;
}

ipj_error set_antenna_sequence()
{
    ipj_error error;
    ipj_key_value key_value[16];
    unsigned int  key_value_count = 0;
    ipj_key_list  key_list;
    unsigned int  key_list_count = 1;
    unsigned int  i;

    memset(&key_value, 0, sizeof(key_value));
    memset(&key_list, 0, sizeof(key_list));

    key_list_count = 1;
    key_list.key = E_IPJ_KEY_ANTENNA_SEQUENCE;
    key_list.list_count = NUM_ANTENNA_DESCRIPTORS;

    for(i = 0; i < key_list.list_count; ++i)
    {
        key_list.list[i] = i + 1;
    }

    error = ipj_bulk_set(&iri_device, &key_value[0], key_value_count, &key_list, key_list_count);

    return error;
}

IRI_Change_Baudrate Example

The IRI_Change_Baudrate example demonstrates how to change the baud rate of UART communication with an Indy Module using the ipj_modify_connection() API in the IRI library.

IRI_Change_Baudrate - Source Code

IRI_Change_Baudrate source code is provided in IRI_Change_Baudrate.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"

/* PURPOSE: This example illustrates the use of the change baud rate feature. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 250

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error;

    /* IRI Connection parameters */
    ipj_connection_params connection_params;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    printf("Setting Baud to 57600 and performing inventory\n");

    connection_params.serial.baudrate = E_IPJ_BAUD_RATE_BR57600;
    /* Change Baud rate to 57600 bps */
    error = ipj_modify_connection(
            &iri_device,
            E_IPJ_CONNECTION_TYPE_SERIAL,
            &connection_params);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_modify_connection");

    /* Perform inventory to test results of baud rate change */
    error = ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_perform_inventory");

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return 0;
}

IRI_Empty Example

The IRI_Empty example is an empty program including the IRI library that can be used as the basis for a program communicating with an Indy Module. The code connects to a reader module but does not perform any RFID operations.

IRI_Empty - Source Code

IRI_Empty source code is provided in IRI_Empty.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"

/* PURPOSE: This file is place holder template to begin a new IRI application. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 1000

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error = E_IPJ_ERROR_SUCCESS;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");


    /* YOUR CODE HERE */


    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return error;
}

IRI_External_Antenna_Mux Example

The IRI_External_Antenna_Mux example demonstrates how to use the External Antenna Mux functionality of the modules, which allows multiple antennas to be connected to a single antenna port by controlling an external antenna mux (RF switch) using the module GPIOs. The example also prints out the antenna number a tag is read on, by setting the E_IPJ_TAG_FLAG_BIT_ANTENNA bit in the E_IPJ_KEY_REPORT_CONTROL_TAG key, and printing the antenna in the ipj_tag struct, contained within the tag_operation_report struct, in the ipj_util_tag_operation_report_handler() function in the ipj_utils.c source file.

For more information on the mapping of antennas and GPIO states, see the E_IPJ_KEY_EXTERNAL_ANTENNA_MUX_NUM_ANTENNAS key docu

The following keys are used to configure antenna muxing:

IRI_External_Antenna_Mux - Source Code

IRI_External_Antenna_Mux source code is provided in IRI_External_Antenna_Mux.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"

/* PURPOSE: This file is used to demo the external antenna mux feature.
   The four GPIO pins are redirected to being used by the reader firmware
   to switch antennas using an external RF switch. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 2000

#define NUM_EXTERNAL_MUX_ANTENNAS 16

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

ipj_error enable_external_antenna_mux();
ipj_error disable_external_antenna_mux();

ipj_error config_external_antenna_mux(
    unsigned int num_antennas,
    unsigned int physical_port,
    unsigned int delay_microseconds
);

ipj_error set_antenna_sequence();

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error = E_IPJ_ERROR_SUCCESS;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    error = set_antenna_sequence();
    IPJ_UTIL_RETURN_ON_ERROR(error, "set_antenna_sequence");

    error = config_external_antenna_mux(NUM_EXTERNAL_MUX_ANTENNAS, 1, 0);
    IPJ_UTIL_RETURN_ON_ERROR(error, "config_external_antenna_mux");

    error = enable_external_antenna_mux();
    IPJ_UTIL_RETURN_ON_ERROR(error, "enable_external_antenna_mux");
	
	/* Enable antenna field in tag operation reports */
	error = ipj_set_value(&iri_device, E_IPJ_KEY_REPORT_CONTROL_TAG, E_IPJ_TAG_FLAG_BIT_EPC | E_IPJ_TAG_FLAG_BIT_TIMESTAMP | E_IPJ_TAG_FLAG_BIT_TID | E_IPJ_TAG_FLAG_BIT_ANTENNA);
	IPJ_UTIL_RETURN_ON_ERROR(error, "set_tag_operation_report_fields");

	/* Perform inventory */
    error = ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_perform_inventory");

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return error;
}

ipj_error enable_external_antenna_mux()
{
    return ipj_set_value(
        &iri_device,
        E_IPJ_KEY_EXTERNAL_ANTENNA_MUX_ENABLE,
        true
    );
}

ipj_error disable_external_antenna_mux()
{
    return ipj_set_value(
        &iri_device,
        E_IPJ_KEY_EXTERNAL_ANTENNA_MUX_ENABLE,
        false
    );
}

ipj_error config_external_antenna_mux(
    unsigned int num_antennas,
    unsigned int physical_port,
    unsigned int delay_microseconds
)
{
    ipj_error error;

    error = ipj_set_value(&iri_device, E_IPJ_KEY_EXTERNAL_ANTENNA_MUX_NUM_ANTENNAS, num_antennas);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_value E_IPJ_KEY_EXTERNAL_ANTENNA_MUX_NUM_ANTENNAS");

    error = ipj_set_value(&iri_device, E_IPJ_KEY_EXTERNAL_ANTENNA_MUX_PHYSICAL_PORT, physical_port);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_value EXTERNAL_ANTENNA_MUX_PHYSICAL_PORT");

    error = ipj_set_value(&iri_device, E_IPJ_KEY_EXTERNAL_ANTENNA_MUX_DELAY_MICROSECONDS, delay_microseconds);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_value EXTERNAL_ANTENNA_MUX_DELAY_MICROSECONDS");

    return error;
}

ipj_error set_antenna_sequence()
{
    ipj_error error;
    ipj_key_value key_value[16];
    unsigned int  key_value_count = 0;
    ipj_key_list  key_list;
    unsigned int  key_list_count = 1;
    unsigned int  i;

    memset(&key_value, 0, sizeof(key_value));
    memset(&key_list, 0, sizeof(key_list));

    key_list_count = 1;
    key_list.key = E_IPJ_KEY_ANTENNA_SEQUENCE;
    key_list.list_count = NUM_EXTERNAL_MUX_ANTENNAS;

    for(i = 0; i < key_list.list_count; ++i)
    {
        key_list.list[i] = i + 1;
    }

    error = ipj_bulk_set(&iri_device, &key_value[0], key_value_count, &key_list, key_list_count);

    return error;
}

IRI_GPIO Example

The IRI_GPIO example demonstrates how to use Indy Modules’ GPIOs as inputs and outputs, including triggering inventories.

The following keys are used to configure the GPIOs:

IRI_GPIO - Source Code

IRI_GPIO source code is provided in IRI_GPIO.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/

/* NOTE: For this example, you will need to jumper GPIO0 to GPIO1 */
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"
#include "platform.h"

/* PURPOSE: This example illustrates the use GPIOs to initiate an inventory
   operation.  It also has an example of how to override the stop_handler
   versus using the default handler. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 5000

/* Declare local report handlers */
static ipj_error report_handler(
        ipj_iri_device* iri_device,
        ipj_report_id report_id,
        void* report);

static ipj_error stop_report_handler(
        ipj_iri_device* iri_device,
        ipj_stop_report* ipj_stop_report);

static uint32_t ipj_stopped_flag;

static struct ipj_handler event_handlers[] =
{
    { E_IPJ_HANDLER_TYPE_REPORT, &report_handler }
};

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

ipj_error register_handlers(ipj_iri_device* iri_device)
{
    ipj_error error;
    unsigned int i;
    for (i = 0; i < (sizeof(event_handlers) / sizeof(event_handlers[0])); i++)
    {
        error = ipj_register_handler(
                iri_device,
                event_handlers[i].type,
                event_handlers[i].handler);
        if (error)
        {
            return error;
        }
    }
    return E_IPJ_ERROR_SUCCESS;
}

static ipj_error perform_gpio_triggered_inventory(
        ipj_iri_device* iri_device,
        uint32_t timeout_ms)
{
    uint32_t end_time_ms;
    ipj_error error;
    ipj_key_value key_value[16];
    uint32_t key_value_count = 0;

    IPJ_CLEAR_STRUCT(key_value);

    /* GPIO 1 as output resting low*/
    key_value[0].key = E_IPJ_KEY_GPIO_MODE;
    key_value[0].value = E_IPJ_GPIO_MODE_OUTPUT;
    key_value[0].bank_index = 1;
    key_value_count++;

    key_value[1].key = E_IPJ_KEY_GPIO_STATE;
    key_value[1].value = E_IPJ_GPIO_STATE_LO;
    key_value[1].bank_index = 1;
    key_value_count++;

    /* GPIO2 as floating input with attached actions */
    key_value[2].key = E_IPJ_KEY_GPIO_MODE;
    key_value[2].value = E_IPJ_GPIO_MODE_INPUT_ACTION;
    key_value[2].bank_index = 2;
    key_value_count++;

    key_value[3].key = E_IPJ_KEY_GPIO_STATE;
    key_value[3].value = E_IPJ_GPIO_STATE_FLOAT;
    key_value[3].bank_index = 2;
    key_value_count++;

    key_value[4].key = E_IPJ_KEY_GPIO_HI_ACTION;
    key_value[4].value = E_IPJ_GPI_ACTION_START_INVENTORY;
    key_value[4].bank_index = 2;
    key_value_count++;

    key_value[5].key = E_IPJ_KEY_GPIO_LO_ACTION;
    key_value[5].value = E_IPJ_GPI_ACTION_STOP_INVENTORY;
    key_value[5].bank_index = 2;
    key_value_count++;

    /* Set the keys */
    error = ipj_bulk_set(iri_device, &key_value[0], key_value_count, NULL, 0);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_bulk_set");

    /* start the GPIO set up */
    error = ipj_start(iri_device, E_IPJ_ACTION_GPIO);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_start E_IPJ_ACTION_GPIO");

    /* set GPIO1 high */
    error = ipj_set(iri_device, E_IPJ_KEY_GPIO_STATE, 1, 0, E_IPJ_GPIO_STATE_HI);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set E_IPJ_KEY_GPIO_STATE");

    /* Set example end time */
    end_time_ms = platform_timestamp_ms_handler() + timeout_ms;

    /*  Perform receive until end time reached */
    while (platform_timestamp_ms_handler() < end_time_ms)
    {
        /* Call ipj_receive to process tag reports  */
        error = ipj_receive(iri_device);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_receive");
    }

    /* Set GPIO1 Low  & Stop inventory  */
    error = ipj_set(iri_device, E_IPJ_KEY_GPIO_STATE, 1, 0, E_IPJ_GPIO_STATE_LO);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set E_IPJ_KEY_GPIO_STATE");

    error = ipj_stop(iri_device, E_IPJ_ACTION_GPIO);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_stop E_IPJ_ACTION_GPIO");

    /* Set stop end time */
    end_time_ms = platform_timestamp_ms_handler() + timeout_ms;

    /*  Collect the last few tags and look for the stop report */
    while (!ipj_stopped_flag && platform_timestamp_ms_handler() < end_time_ms)
    {
        /* Call ipj_receive to process tag reports  */
        error = ipj_receive(iri_device);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_receive");
    }
    return E_IPJ_ERROR_SUCCESS;
}

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error;

    uint32_t end_message_ms;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    /*
     * Override the report handler so the local stop_handler can be called and
     * stop perform_gpio_triggered_inventory
     */
    register_handlers(&iri_device);

    /* Display a message to the user for ~5 seconds */
    end_message_ms = platform_timestamp_ms_handler() + 5000;
    printf("Please jump GPIO1 to GPIO2 for this demonstration\n");
    while (platform_timestamp_ms_handler() < end_message_ms)
    {
        /* Do nothing */
    }

    /* Start inventory */
    error = perform_gpio_triggered_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "perform_gpio_triggered_inventory");

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return 0;
}

/* Report handler processes asynchronous reports */
static ipj_error report_handler(
        ipj_iri_device* iri_device,
        ipj_report_id report_id,
        void* report)
{
    ipj_error error = E_IPJ_ERROR_SUCCESS;
    /* Case statement for each report type */
    switch (report_id)
    {
        case E_IPJ_REPORT_ID_TAG_OPERATION_REPORT:
            error = ipj_util_tag_operation_report_handler(
                    iri_device,
                    (ipj_tag_operation_report*) report);
            break;
        case E_IPJ_REPORT_ID_STOP_REPORT:
            error = stop_report_handler(iri_device, (ipj_stop_report*) report);
            break;
        case E_IPJ_REPORT_ID_GPIO_REPORT:
            error = ipj_util_gpio_report_handler(
                    iri_device,
                    (ipj_gpio_report*) report);
            break;
        default:
            printf(
                    "%s: REPORT ID: %d NOT HANDLED\n",
                    (char*) iri_device->reader_identifier,
                    report_id);
            error = E_IPJ_ERROR_GENERAL_ERROR;
            break;
    }
    return error;
}

/* Stop report handler processes asynchronous reports */
static ipj_error stop_report_handler(
        ipj_iri_device* iri_device,
        ipj_stop_report* ipj_stop_report)
{
    if (ipj_stop_report->error == E_IPJ_ERROR_SUCCESS)
    {
        /* Print reader identifier */
        printf("%s: STOPPED\n", (char*) iri_device->reader_identifier);

        /* Set the stopped flag, the stop report does not have any fields that
         * need to be checked */
        ipj_stopped_flag = 1;
    }
    else
    {
        IPJ_UTIL_PRINT_ERROR(ipj_stop_report->error,"stop_report");
    }
    return ipj_stop_report->error;
}

IRI_Loader Example

The IRI_Loader example demonstrates how to load an application or stored settings image into an Indy Module via its bootloader using the ipj_reset() and ipj_flash_handle_loader_block() API in the IRI host library.

IRI_Loader - Source Code

IRI_Loader source code is provided in IRI_Loader.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#if defined(__GNUC__)
    #include <unistd.h>
#else
    #include <io.h>
#endif
#include "ipj_util.h"
#include "iri.h"

/* PURPOSE: This example illustrates the use of the image loader to download
   firmware to the device. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 1000

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error;

    /* Storage buffer for device read */
    uint8_t file_buf[300];
    FILE* image_file_handle;

    int chunk_size;

    /* connection parameters */
    ipj_connection_params params;

    /* High speed flag */
    bool high_speed = false;

    if ((argc < 3) || (argc > 4))
    {
        printf("\n\nUsage:"
                "\n\tIRI_Loader.exe COMx <image_location> [-s] \n"
                "where: \n"
                "\tx is a COM port number\n"
                "\t<image_location> is an absolute path\n"
                "\t-s for high speed 921600 baud update (optional)\n");
        return -1;
    }

    /* Determine if we're in high speed mode or not */
    if ((argc == 4) && (strcmp(argv[3], "-s") == 0))
    {
        high_speed = true;
    }

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    /* Put the device in bootloader mode */
    error = ipj_reset(&iri_device, E_IPJ_RESET_TYPE_TO_BOOTLOADER);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_reset E_IPJ_RESET_TYPE_TO_BOOTLOADER");

    if (high_speed)
    {
        /* Speed up the upgrade process */

        /* Perform a modify connection command to bring the device
         * and host up to 921600 baud */
        params.serial.baudrate = E_IPJ_BAUD_RATE_BR921600;
        params.serial.parity = E_IPJ_PARITY_PNONE;

        error = ipj_modify_connection(&iri_device,
        E_IPJ_CONNECTION_TYPE_SERIAL, &params);
        if (error)
        {
            printf("Unable to change baud rate");
            return -1;
        }
    }

#if defined(__GNUC__)
    image_file_handle = fopen(argv[2], "rb");
#else
    fopen_s(&image_file_handle, argv[2], "rb");
#endif

    if (image_file_handle == NULL)
    {
        printf("Unable to open image file\n");
        return -1;
    }

    /* Get the image chunk size.  This is stored in the first 32 bits
     * of the upgrade image */
    if (fread(file_buf, 4, 1, image_file_handle) == 0)
    {
        printf("Unable to determine chunk size\n");
        return -1;
    }

    chunk_size = (file_buf[0] & 0xff) | (file_buf[1] << 8) | (file_buf[2] << 16)
            | (file_buf[3] << 24);

    printf("Image chunk size: %d\n", chunk_size);
    printf(
            "(%d bytes header | %d bytes payload | 2 bytes CRC)\n",
            12,
            (chunk_size - 2) - 12);

    if (chunk_size < 22 || chunk_size > 270)
    {
        printf("Invalid chunk size\n");
        return -1;
    }

    /* For each chunk in the image file, write it to the Indy Module */
    while (fread(file_buf, chunk_size, 1, image_file_handle) > 0)
    {
        error = ipj_flash_handle_loader_block(&iri_device, chunk_size, file_buf);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_flash_handle_loader_block");
    }

    printf("Image load complete\n");

    if (high_speed)
    {
        /* Return to our previous baud rate */
        params.serial.baudrate = E_IPJ_BAUD_RATE_BR115200;
        error = ipj_modify_connection(&iri_device,
        E_IPJ_CONNECTION_TYPE_SERIAL, &params);
        if (error)
        {
            printf("Unable to change baud rate");
            return -1;
        }
    }

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return 0;
}

IRI_Multiple_Readers Example

The IRI_Multiple_Readers example connects to multiple Indy Modules and performs basic inventory using all of them by instantiating multiple ipj_iri_device structs. The example implements connection with 5 Indy modules, but can be modified to change that number.

IRI_Multiple_Readers - Source Code

IRI_Multiple_Readers source code is provided in IRI_Multiple_Readers.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"
#include "platform.h"

/* PURPOSE: This example illustrates the use of multiple reader modules from 
   one application. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 1000
#define MAX_READERS 5

/* Declare local report handlers */
static ipj_error report_handler(
        ipj_iri_device* iri_device,
        ipj_report_id report_id,
        void* report);

static ipj_error stop_report_handler(
        ipj_iri_device* iri_device,
        ipj_stop_report* ipj_stop_report);

/* Allocate memory for iri device */
static ipj_iri_device iri_devices[MAX_READERS];

static uint32_t ipj_stopped_flags[MAX_READERS];

static struct ipj_handler event_handlers[] =
{
    { E_IPJ_HANDLER_TYPE_REPORT, &report_handler }
};

static ipj_error register_handlers(ipj_iri_device* iri_device)
{
    ipj_error error;
    unsigned int i;
    for (i = 0; i < (sizeof(event_handlers) / sizeof(event_handlers[0])); i++)
    {
        error = ipj_register_handler(
                iri_device,
                event_handlers[i].type,
                event_handlers[i].handler);
        if (error)
        {
            return error;
        }
    }
    return E_IPJ_ERROR_SUCCESS;
}

static ipj_error perform_inventory(int num_readers, uint32_t timeout_ms)
{
    uint32_t end_time_ms;
    ipj_error error;
    int i;
    bool all_stopped_flag = false;

    for (i = 0; i < num_readers; i++)
    {
        ipj_stopped_flags[i] = 0x00;
        error = ipj_start(&iri_devices[i], E_IPJ_ACTION_INVENTORY);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_start E_IPJ_ACTION_INVENTORY");
    }

    /* Set example end time */
    end_time_ms = platform_timestamp_ms_handler() + timeout_ms;

    /*  Perform receive until end time reached */
    while (platform_timestamp_ms_handler() < end_time_ms)
    {
        for (i = 0; i < num_readers; i++)
        {
            /* Call ipj_receive to process tag reports  */
            error = ipj_receive(&iri_devices[i]);
            IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_receive");
        }
    }

    for (i = 0; i < num_readers; i++)
    {
        /* Stop inventory  */
        error = ipj_stop(&iri_devices[i], E_IPJ_ACTION_INVENTORY);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_stop");
    }

    /* Set stop end time */
    end_time_ms = platform_timestamp_ms_handler() + timeout_ms;

    while (!all_stopped_flag && platform_timestamp_ms_handler() < end_time_ms)
    {
        for (i = 0; i < num_readers; i++)
        {
            /*  Collect the last few tags and look for the stop report */
            if (!ipj_stopped_flags[i])
            {
                /* Call ipj_receive to process tag reports  */
                error = ipj_receive(&iri_devices[i]);
                IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_receive");
            }
            all_stopped_flag &= ipj_stopped_flags[i];
        }
    }
    return E_IPJ_ERROR_SUCCESS;
}

/* Main */
int main(int argc, char* argv[])
{
    /* Loop placeholder */
    int i;

    /* Define error code */
    ipj_error error = E_IPJ_ERROR_SUCCESS;

    if (argc < 2)
    {
        printf(
                "\n\nUsage:\t%s COMx COMy...COMz \n\nwhere x/y/z is a COM port number (Maximum 5 readers)\n\n",
                argv[0]);
        return -1;
    }

    /* Loop through all of the devices we've supplied and set them up */
    for (i = 0; i < argc - 1; i++)
    {
        /* Common example setup */
        error = ipj_util_setup(&iri_devices[i], argv[1 + i]);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

        /*
         * Override the report handler so the local stop_handler can be called
         */
        register_handlers(&iri_devices[i]);
    }

    /* Start and run inventory with all devices for the specified
     * duration */
    error = perform_inventory(argc - 1, IPJ_EXAMPLE_DURATION_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "perform_inventory");

    /* Loop through and disconnect/deinit each iri_device */
    for (i = 0; i < argc - 1; i++)
    {
        /* Common example cleanup */
        error = ipj_util_cleanup(&iri_devices[i]);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");
    }
    return error;
}

/* Report handler processes asynchronous reports */
static ipj_error report_handler(
        ipj_iri_device* iri_device,
        ipj_report_id report_id,
        void* report)
{
    ipj_error error = E_IPJ_ERROR_SUCCESS;
    /* Case statement for each report type */
    switch (report_id)
    {
        case E_IPJ_REPORT_ID_TAG_OPERATION_REPORT:
            error = ipj_util_tag_operation_report_handler(
                    iri_device,
                    (ipj_tag_operation_report*) report);
            break;
        case E_IPJ_REPORT_ID_STOP_REPORT:
            error = stop_report_handler(iri_device, (ipj_stop_report*) report);
            break;
        case E_IPJ_REPORT_ID_GPIO_REPORT:
            error = ipj_util_gpio_report_handler(
                    iri_device,
                    (ipj_gpio_report*) report);
            break;
        default:
            printf(
                    "%s: REPORT ID: %d NOT HANDLED\n",
                    (char*) iri_device->reader_identifier,
                    report_id);
            error = E_IPJ_ERROR_GENERAL_ERROR;
            break;
    }
    return error;
}

/* Tag report handler processes asynchronous reports */
static ipj_error stop_report_handler(
        ipj_iri_device* iri_device,
        ipj_stop_report* ipj_stop_report)
{
    int i;
    if (ipj_stop_report->error == E_IPJ_ERROR_SUCCESS)
    {
        /* Print reader identifier */
        printf("%s: STOPPED\n", (char*) iri_device->reader_identifier);

        /* Set the stopped flag, the stop report does not have any fields that
         * need to be checked */
        for (i = 0; i < MAX_READERS; i++)
        {
            if (&iri_devices[i] == iri_device)
            {
                ipj_stopped_flags[i] = 1;
            }
        }
    }
    else
    {
        printf("IPJ_STOP Error. Error Code:%x\n\n", ipj_stop_report->error);
    }
    return ipj_stop_report->error;
}

IRI_Power_Management Example

The IRI_Power_Management example demonstrates changing Indy Module power modes by starting the various ipj_action types using the ipj_start() function included in the IRI host library.

IRI_Power_Management - Source Code

IRI_Power_Management source code is provided in IRI_Power_Management.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"
#include "platform.h"

/* PURPOSE: This example illustrates the use of the power management modes. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 1000

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

static ipj_error sleep_ms(uint32_t sleep_time_ms)
{
    uint32_t end_time_ms = platform_timestamp_ms_handler() + sleep_time_ms;
    printf("Sleeping for %d milliseconds\n", sleep_time_ms);

    while (platform_timestamp_ms_handler() < end_time_ms)
        ;
    return E_IPJ_ERROR_SUCCESS;
}

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error = E_IPJ_ERROR_SUCCESS;
    uint32_t val = 0;
    int retries = 10;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    /* Configure transmit power */
    error = ipj_set_value(&iri_device, E_IPJ_KEY_ANTENNA_TX_POWER, 2300);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_value E_IPJ_KEY_ANTENNA_TX_POWER");

    /* Start inventory */
    error = ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_perform_inventory");

    /* Put the device into standby mode */
    error = ipj_start(&iri_device, E_IPJ_ACTION_STANDBY);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_start E_IPJ_ACTION_STANDBY");

    /* Sleep for 5 seconds */
    sleep_ms(5000);

    printf("Attempting to wake Indy Module\n");

    /* Set the receive timeout MS to a lower number (100ms) */
    error = ipj_set_receive_timeout_ms(&iri_device, 100);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_receive_timeout_ms");

    /* Spin on IPJ_GET_VALUE (any key will do) until the device responds */
    do
    {
        error = ipj_get_value(&iri_device, E_IPJ_KEY_ANTENNA_TX_POWER, &val);
    } while (error && retries--);
    IPJ_UTIL_RETURN_ON_ERROR(error, "Wake Indy Module");

    printf("Successfully woke Indy Module\n");
    printf("Performing Inventory to check for full functionality\n");

    /* Reset the timeout to it's default value */
    error = ipj_set_receive_timeout_ms(&iri_device, IPJ_DEFAULT_RECEIVE_TIMEOUT_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_receive_timeout_ms");

    /* Perform second inventory */
    error = ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_perform_inventory");

    printf("Inventory Successful, putting device into sleep mode\n");
    error = ipj_start(&iri_device, E_IPJ_ACTION_SLEEP);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_start E_IPJ_ACTION_SLEEP");

    printf("Successfully put device into sleep.  To wake:\n");
    printf("Jump WKUP to VCC -or- press the reset button\n");

    /* Disconnect IRI device & close serial port */
    error = ipj_disconnect(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_disconnect");

    /* Deinitialize IRI device */
    error = ipj_deinitialize_iri_device(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_deinitialize_iri_device");

    return error;
}

IRI_Select Example

The IRI_Select example demonstrates how to use the Select tag operation to inventory only tags with a certain TID.

This example can be easily modified to select based on EPC by changing the E_IPJ_KEY_SELECT_MEM_BANK and E_IPJ_KEY_SELECT_POINTER keys.

The following keys are used to configure the select operation:

IRI_Select - Source Code

IRI_Select source code is provided in IRI_Select.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"

/* PURPOSE: This example illustrates the use of Gen2 Select operation. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 250

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

/* This select command will cause only tags with a TID starting with
 * 0xe280 to set their select flags  */
static ipj_error setup_select_1(ipj_iri_device* iri_device)
{
    ipj_error error = E_IPJ_ERROR_SUCCESS;

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_ENABLE, 0, 0, true);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_TARGET, 0, 0,
    E_IPJ_SELECT_TARGET_SL_FLAG);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_ACTION, 0, 0,
    E_IPJ_SELECT_ACTION_ASLINVA_DSLINVB);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_MEM_BANK, 0, 0,
    E_IPJ_MEM_BANK_TID);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_POINTER, 0, 0, 0x0);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_MASK_LENGTH, 0, 0, 16);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_MASK_VALUE, 0, 0, 0xE280);

    return error;
}

/* This select command will cause only tags with 1 at bit 19
 to maintain their select flag, else their SL flag will de-assert.
 This causes and AND effect with the first select.
 The 2 selects combined will select Monza4/5 tags*/
static ipj_error setup_select_2(ipj_iri_device* iri_device)
{
    ipj_error error = E_IPJ_ERROR_SUCCESS;

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_ENABLE, 1, 0, true);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_TARGET, 1, 0,
    E_IPJ_SELECT_TARGET_SL_FLAG);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_ACTION, 1, 0,
    E_IPJ_SELECT_ACTION_NOTHING_DSLINVB);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_MEM_BANK, 1, 0,
    E_IPJ_MEM_BANK_TID);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_POINTER, 1, 0, 19);

    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_MASK_LENGTH, 1, 0, 1);

    /* Note: When the mod of the length is less than 16, the MSBs
     of the mask are used.  So for 1 bit length, the msb of the
     mask (bit 15) is the mask and the LSBs are ignored. */
    error |= ipj_set(iri_device,
    E_IPJ_KEY_SELECT_MASK_VALUE, 1, 0, 0x8000);

    return error;
}

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    printf("Sending Select Command for Monza4/5 tags (TID = 0xE280.1xxx)\n");
    /* Send Select Command */
    error = setup_select_1(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "setup_select_1");

    error = setup_select_2(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "setup_select_2");

    /*
     * NOTE: In this example, we target the SL flag, hence setting it
     * here.  Your Select use case may or may not require this.
     * Please refer to the GEN2 spec for details
     */
    error = ipj_set_value(&iri_device, E_IPJ_KEY_INVENTORY_SELECT_FLAG, E_IPJ_INVENTORY_SELECT_FLAG_SL);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_value E_IPJ_KEY_INVENTORY_SELECT_FLAG");

    error = ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, 0);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_set_value E_IPJ_KEY_TAG_OPERATION");

    /* Perform inventory to see results of EPC write */
    ipj_util_perform_inventory(&iri_device, IPJ_EXAMPLE_DURATION_MS);

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return 0;
}

IRI_Test_CW_PRBS Example

The IRI_Test_CW_PRBS example demonstrates how to use some of the IRI host library test commands, such as CW (Carrier Wave) and PRBS (Pseudo-Random Bitstream). The test commands are configured using the ipj_util_test_command() API in the ipj_util example source code.

IRI_Test_CW_PRBS - Source Code

IRI_Test_CW_PRBS source code is provided in IRI_Test_CW_PRBS.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"
#include "platform.h"

/* PURPOSE: This example illustrates the use of the test commands to control
   the CW (Continuous Wave) and PRBS (Pseudo-Random Bit Sequence) functions. */

/* Parameters */
#define IPJ_EXAMPLE_DURATION_MS 10000

/* Allocate memory for iri device */
static ipj_iri_device iri_device = { 0 };

/* Main */
int main(int argc, char* argv[])
{
    /* Define error code */
    ipj_error error;

    IPJ_UTIL_CHECK_USER_INPUT_FOR_COM_PORT_RETURN_ON_ERROR()

    /* Common example setup */
    error = ipj_util_setup(&iri_device, argv[1]);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    /* Set frequency to 912.25 MHz (specified in kHz)*/
    ipj_util_test_command(&iri_device, E_IPJ_TEST_ID_SET_FREQUENCY, 912250, 0, 0, 0);

    /* Enable CW */
    ipj_util_test_command(&iri_device, E_IPJ_TEST_ID_CW_CONTROL, 1, 0, 0, 0);

    /* Leave CW on for 1 second */
    platform_sleep_ms_handler(1000);

    /* Disable CW */
    ipj_util_test_command(&iri_device, E_IPJ_TEST_ID_CW_CONTROL, 0, 0, 0, 0);

    /* Set frequency to 912.75 MHz (specified in kHz)*/
    ipj_util_test_command(&iri_device, E_IPJ_TEST_ID_SET_FREQUENCY, 912750, 0, 0, 0);

    /* Enable PRBS */
    ipj_util_test_command(&iri_device, E_IPJ_TEST_ID_PRBS_CONTROL, 1, 0, 0, 0);

    /* Leave PRBS on for 1 second */
    platform_sleep_ms_handler(1000);

    /* Disable PRBS */
    ipj_util_test_command(&iri_device, E_IPJ_TEST_ID_PRBS_CONTROL, 0, 0, 0, 0);

    /* Common example cleanup */
    error = ipj_util_cleanup(&iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return 0;
}

Platform Port Examples

The example platform source code is common between all of the examples, although it differs for each host platform. Platform source code interfaces with the peripherals required to implement IRI communication. This includes UART communication, timing, and host memory configuration.

Example platform source code is provided in the platform_*.c files.

For example, here is platform_win32.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/

#include <windows.h>
#include <stdint.h>
#include <stdio.h>
#include "platform.h"
#include "iri.h"

/* PLATFORM_OPEN_PORT_HANDLER */
uint32_t platform_open_port_handler(IPJ_READER_CONTEXT* reader_context,
                                    IPJ_READER_IDENTIFIER reader_identifier,
                                    ipj_connection_type connection_type,
                                    ipj_connection_params* params)
{
    HANDLE h_port;
    DCB dcb;
    COMMTIMEOUTS commtimeouts;

    uint32_t result;
    char port_name[30];

    /* we currently only support serial */
    (void)connection_type;

    /* Map reader_identifier to COM port name */
#if defined(__GNUC__)
    strcpy(port_name, "\\\\.\\");
    strcat(port_name, (char*)reader_identifier);
#else /* Visual Studio/Intel/etc */
    strcpy_s(port_name, sizeof(port_name), "\\\\.\\");
    strcat_s(port_name, sizeof(port_name), (char*)reader_identifier);
#endif

    /* Open serial port */
    h_port = CreateFileA(port_name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    /* Return error if invalid handle */
    if ((h_port == INVALID_HANDLE_VALUE))
    {
        return 0;
    }

    /* Get default serial port parameters */
    dcb.DCBlength = sizeof(dcb);
    result = GetCommState(h_port, &dcb);

    /* Return error if unsuccessful getting serial port parameters */
    if (!result)
    {
        return 0;
    }

    /* Modify serial port parameters */
    if(!params)
    {
        return 0;
    }
    else
    {
        dcb.BaudRate = params->serial.baudrate;
        switch(params->serial.parity)
        {
            case E_IPJ_PARITY_PODD:
            {
                dcb.Parity = ODDPARITY;
                break;
            }
            case E_IPJ_PARITY_PEVEN:
            {
                dcb.Parity = EVENPARITY;
                break;
            }
            default: /* Fall through */
            case E_IPJ_PARITY_PNONE:
            {
                dcb.Parity = NOPARITY;
                break;
            }
        }
    }
    dcb.ByteSize = 8;
    dcb.StopBits = ONESTOPBIT;
    dcb.fParity  = false;
    dcb.fOutX    = false;
    dcb.fInX     = false;
    dcb.fNull    = false;
    dcb.fDtrControl = DTR_CONTROL_ENABLE;
    dcb.fRtsControl = RTS_CONTROL_ENABLE;

    /* Set serial port parameters */
    result = SetCommState(h_port, &dcb);

    /* Return error if unsuccessful setting serial port parameters */
    if (!result)
    {
        return 0;
    }

    /* Get timeout values */
    result = GetCommTimeouts(h_port, &commtimeouts);

    // Return error if unsuccessful getting serial port timeout parameters */
    if (!result)
    {
        return 0;
    }

    /* Modify timeout values */
    commtimeouts.ReadIntervalTimeout         = 0;
    commtimeouts.ReadTotalTimeoutConstant    = PLATOFRM_DEFAULT_READ_TIMEOUT_MS;
    commtimeouts.ReadTotalTimeoutMultiplier  = 0;
    commtimeouts.WriteTotalTimeoutConstant   = PLATFORM_DEFAULT_WRITE_TIMEOUT_MS;
    commtimeouts.WriteTotalTimeoutMultiplier = 0;

    /* Set timeout values */
    result = SetCommTimeouts(h_port, &commtimeouts);

    if(!result)
    {
        return 0;
    }

    /* Assign serial port handle to reader context */
    *reader_context = (IPJ_READER_CONTEXT)h_port;
    return 1;
}

/* PLATFORM_CLOSE_PORT_HANDLER */
uint32_t platform_close_port_handler(IPJ_READER_CONTEXT reader_context)
{
    uint32_t result;

    /* Close reader handle */
    result = CloseHandle((HANDLE)reader_context);

    if(!result)
    {
        return 0;
    }

    return 1;
}

/*
 * PLATFORM_TRANSMIT_HANDLER
 *
 * Return: 1: Success, 0:Fail
 */
uint32_t platform_transmit_handler(IPJ_READER_CONTEXT reader_context, uint8_t* message_buffer, uint16_t  buffer_size,
                                   uint16_t* number_bytes_transmitted)
{
    uint32_t result;
    DWORD dw_bytes_written = 0;

    /* Write serial port */
    result = WriteFile((HANDLE)reader_context, message_buffer, buffer_size, &dw_bytes_written, NULL);
    if (!result)
    {
        /* Fail */
        return 0;
    }
    else
    {
        /* Success */
        /* Assign number of bytes transmitted */
        *number_bytes_transmitted = (uint16_t)dw_bytes_written;
        return 1;
    }
}

/* PLATFORM_RECEIVE_HANDLER */
uint32_t platform_receive_handler(IPJ_READER_CONTEXT reader_context, uint8_t* message_buffer, uint16_t buffer_size,
                                  uint16_t* number_bytes_received, uint16_t timeout_ms)
{
    uint32_t result;
    DWORD dw_bytes_received = 0;
    COMMTIMEOUTS commtimeouts;

    /* Get timeout values */
    result = GetCommTimeouts((HANDLE)reader_context, &commtimeouts);

    /* Return error if unsuccessful getting serial port timeout parameters */
    if (!result)
    {
        return 0;
    }

    /* Modify timeout values */
    if (timeout_ms == 0)
    {
        commtimeouts.ReadIntervalTimeout = MAXDWORD;
        commtimeouts.ReadTotalTimeoutConstant = 1;
    }
    else
    {
        commtimeouts.ReadIntervalTimeout = timeout_ms;
        commtimeouts.ReadTotalTimeoutConstant = 1;
    }

    /* Set timeout values */
    result = SetCommTimeouts((HANDLE)reader_context, &commtimeouts);

    /* Return if error if unsuccessful setting timeout parameters */
    if(!result)
    {
        return 0;
    }

    /* Read serial port */
    result = ReadFile((HANDLE)reader_context, message_buffer, buffer_size, &dw_bytes_received, NULL);
    if (result)
    {
        /* Assign bytes received */
        *number_bytes_received = (uint16_t)dw_bytes_received;
         return 1;
    }
    else
    {
        return 0;
    }
}

/* PLATFORM_TIMESTAMP_HANDLER */
uint32_t platform_timestamp_ms_handler()
{
    DWORD timestamp_ms = timeGetTime();

    return (uint32_t)timestamp_ms;
}

void platform_sleep_ms_handler(uint32_t milliseconds)
{
    Sleep(milliseconds);
}

uint32_t platform_flush_port_handler(IPJ_READER_CONTEXT reader_context)
{
    int result;

    result = PurgeComm((HANDLE)reader_context, PURGE_RXCLEAR | PURGE_TXCLEAR);

    return result == 0 ? 1 : 0;
}

uint32_t platform_reset_pin_handler(IPJ_READER_CONTEXT reader_context,
                                    bool enable)
{
    int action = enable ? SETDTR : CLRDTR;
    int result = EscapeCommFunction((HANDLE)reader_context, action);
    return result == 0 ? 1 : 0;
}

uint32_t platform_wakeup_pin_handler(IPJ_READER_CONTEXT reader_context,
                                     bool enable)
{
    int action = enable ? SETRTS : CLRRTS;
    int result = EscapeCommFunction((HANDLE)reader_context, action);
    return result == 0 ? 1 : 0;
}


uint32_t platform_modify_connection_handler(IPJ_READER_CONTEXT reader_context,
                                            ipj_connection_type connection_type,
                                            ipj_connection_params* params)
{
    DCB dcb;
    int result;

    switch(connection_type)
    {
        /* For all serial operations */
        case E_IPJ_CONNECTION_TYPE_SERIAL:
        {
            /* Get serial port parameters */
            result = GetCommState((HANDLE)reader_context, &dcb);
            if (!result)
            {
                return 1;
            }
            /* Set the new baudrate */
            dcb.BaudRate = (DWORD)params->serial.baudrate;

            switch(params->serial.parity)
            {
                case E_IPJ_PARITY_PODD:
                {
                    dcb.Parity = ODDPARITY;
                    break;
                }
                case E_IPJ_PARITY_PEVEN:
                {
                    dcb.Parity = EVENPARITY;
                    break;
                }
                default: /* Fall through */
                case E_IPJ_PARITY_PNONE:
                {
                    dcb.Parity = NOPARITY;
                    break;
                }
            }

            result = SetCommState((HANDLE)reader_context, &dcb);
            if (!result)
            {
                return 1;
            }
            return 0;
        }
        default:
        {
            return 0;
        }
    }
}

ipj_util example

In addition to the IRI source libraries and platform port code, more code is required to interface with the reader modules more generally. This functionality can be implemented in many different forms, but in the code examples included in this SDK, it is contained within the ipj_util.c source code. This code includes inventory functions, report handler functions, test command functions, and many more.

For examples on how to use the ipj_util.c functionality in this example code, see the Configuration Examples.

Here is the example code implementation of ipj_util.c :

/*
 *****************************************************************************
 * Copyright 2016-2017 Impinj, Inc.                                          *
 *                                                                           *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ipj_util.h"
#include "iri.h"
#include "platform.h"

static uint32_t ipj_stopped_flag;

static struct ipj_handler event_handlers[] =
{
    { E_IPJ_HANDLER_TYPE_PLATFORM_OPEN_PORT,        &platform_open_port_handler },
    { E_IPJ_HANDLER_TYPE_PLATFORM_CLOSE_PORT,       &platform_close_port_handler },
    { E_IPJ_HANDLER_TYPE_PLATFORM_TRANSMIT,         &platform_transmit_handler },
    { E_IPJ_HANDLER_TYPE_PLATFORM_RECEIVE,          &platform_receive_handler },
    { E_IPJ_HANDLER_TYPE_PLATFORM_TIMESTAMP,        &platform_timestamp_ms_handler },
    { E_IPJ_HANDLER_TYPE_PLATFORM_SLEEP_MS,         &platform_sleep_ms_handler },
    { E_IPJ_HANDLER_TYPE_PLATFORM_MODIFY_CONNECTION,&platform_modify_connection_handler },
    { E_IPJ_HANDLER_TYPE_PLATFORM_FLUSH_PORT,       &platform_flush_port_handler },
    { E_IPJ_HANDLER_TYPE_REPORT,                    &ipj_util_report_handler },
    { E_IPJ_HANDLER_TYPE_DIAGNOSTIC,                &ipj_util_diagnostic_handler }
};

ipj_error ipj_util_setup(ipj_iri_device* iri_device, char* reader_identifier)
{
    ipj_error error;

    /* Initialize iri_device structure */
    error = ipj_initialize_iri_device(iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_initialize_iri_device");

    /* Register all handlers */
    error = ipj_util_register_handlers(iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_register_handlers");

    /* Connect to iri device - open serial port */
    error = ipj_connect(
            iri_device,
            reader_identifier,
            E_IPJ_CONNECTION_TYPE_SERIAL,
            NULL);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_connect");

    return error;
}

ipj_error ipj_util_cleanup(ipj_iri_device* iri_device)
{
    ipj_error error;

    /* Reset the IRI device */
    error = ipj_reset(iri_device, E_IPJ_RESET_TYPE_SOFT);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_reset E_IPJ_RESET_TYPE_SOFT");

    /* Disconnect IRI device & close serial port */
    error = ipj_disconnect(iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_disconnect");

    /* Deinitialize IRI device */
    error = ipj_deinitialize_iri_device(iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_deinitialize_iri_device");

    return error;
}

void ipj_util_print_epc(uint16_t* epc, int len, bool little_endian)
{
    int i;
    for (i = 0; i < len; i++)
    {
        /* Print hyphen every two bytes */
        if (i % 1 == 0 && i > 0)
        {
            printf("-");
        }
        /* Print one byte at a time */
        if (little_endian)
        {
            printf("%04X", (((epc[i] & 0xFF00) >> 8) | ((epc[i] & 0xFF) << 8)));
        }
        else
        {
            printf("%04X", epc[i]);
        }
    }
    printf("\n");
}

void ipj_util_print_divider(char symbol, int width)
{
    int i;
    printf("\n");
    for (i = 0; i < width; i++)
    {
        printf("%c", symbol);
    }
    printf("\n");
}

ipj_error ipj_util_register_handlers(ipj_iri_device* iri_device)
{
    ipj_error error;
    unsigned int i;
    for (i = 0; i < (sizeof(event_handlers) / sizeof(event_handlers[0])); i++)
    {
        error = ipj_register_handler(
                iri_device,
                event_handlers[i].type,
                event_handlers[i].handler);
        if (error)
        {
            return error;
        }
    }
    return E_IPJ_ERROR_SUCCESS;
}

/*Code copied from IRI_Loader.c*/
ipj_error ipj_util_flash_image(const char * image_name, char * com_port, ipj_iri_device * iri_device)
{
    /* Define error code */
    ipj_error error;

    /* Storage buffer for device read */
    uint8_t file_buf[300];
    FILE* image_file_handle;
    int chunk_size;

    /*Setup Device*/
    error = ipj_util_setup(iri_device, com_port);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_setup");

    /* Put the device in bootloader mode */
    error = ipj_reset(iri_device, E_IPJ_RESET_TYPE_TO_BOOTLOADER);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_reset E_IPJ_RESET_TYPE_TO_BOOTLOADER");

#if defined(__GNUC__)
    image_file_handle = fopen(image_name, "rb");
#else
    fopen_s(&image_file_handle, image_name, "rb");
#endif

    if (image_file_handle == NULL)
    {
        printf("Unable to open image file\n");
        return -1;
    }

    /* Get the image chunk size.  This is stored in the first 32 bits
     * of the upgrade image */
    if (fread(file_buf, 4, 1, image_file_handle) == 0)
    {
        printf("Unable to determine chunk size\n");
        return -1;
    }

    chunk_size = (file_buf[0] & 0xff) | (file_buf[1] << 8) | (file_buf[2] << 16)
            | (file_buf[3] << 24);

    printf("Image chunk size: %d\n", chunk_size);
    printf(
            "(%d bytes header | %d bytes payload | 2 bytes CRC)\n",
            12,
            (chunk_size - 2) - 12);

    if (chunk_size < 22 || chunk_size > 270)
    {
        printf("Invalid chunk size\n");
        return -1;
    }

    /* For each chunk in the image file, write it to the device */
    while (fread(file_buf, chunk_size, 1, image_file_handle) > 0)
    {
        error = ipj_flash_handle_loader_block(iri_device, chunk_size, file_buf);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_flash_handle_loader_block");
    }

    /* Deregister Handlers, Cleanup IRI_Device and Reset */
    error = ipj_util_cleanup(iri_device);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_util_cleanup");

    return error;
}

/*Util function to wait for receives or until stop handler triggered*/
ipj_error ipj_util_wait_for_receive(ipj_iri_device * iri_device, uint32_t timeout_time_ms)
{
    ipj_error error;
    ipj_stopped_flag = 0;

    /*  Perform receive until end time reached or stop received */
    while (!ipj_stopped_flag && (platform_timestamp_ms_handler() < timeout_time_ms))
    {
        error = ipj_receive(iri_device);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_receive");
    }
    return error;
}

ipj_error ipj_util_perform_inventory(ipj_iri_device* iri_device, uint32_t timeout_ms)
{
    uint32_t end_time_ms;
    ipj_error error;

    /* Clear the stopped flag */
    ipj_stopped_flag = 0;

    error = ipj_start(iri_device, E_IPJ_ACTION_INVENTORY);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_start E_IPJ_ACTION_INVENTORY");

    /* Set end time */
    end_time_ms = platform_timestamp_ms_handler() + timeout_ms;

    /*  Perform receive until end time reached or stop received */
    while (!ipj_stopped_flag && platform_timestamp_ms_handler() < end_time_ms)
    {
        /* Call ipj_receive to process tag reports  */
        error = ipj_receive(iri_device);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_receive");
    }

    /* Stop inventory if it is still running */
    if (!ipj_stopped_flag)
    {
        error = ipj_stop(iri_device, E_IPJ_ACTION_INVENTORY);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_stop");
    }

    /* Set stop end time */
    end_time_ms = platform_timestamp_ms_handler() + timeout_ms;

    /*  Collect the last few tags and look for the stop report */
    while (!ipj_stopped_flag && platform_timestamp_ms_handler() < end_time_ms)
    {
        /* Call ipj_receive to process tag reports  */
        error = ipj_receive(iri_device);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_receive");
    }

    return E_IPJ_ERROR_SUCCESS;
}

ipj_error ipj_util_test_command(ipj_iri_device* iri_device, ipj_test_id test_id,
                                uint32_t param0, uint32_t param1, uint32_t param2, uint32_t param3)
{
    ipj_error error;
    uint32_t end_time_ms;
    uint32_t timeout_ms = 5000;
    ipj_key_value key_value[16];
    uint32_t key_value_count;
    ipj_key_list key_list;
    uint32_t key_list_count;

    memset(key_value, 0, sizeof(key_value));
    memset(&key_list, 0, sizeof(key_list));

    key_value_count = 1;
    key_value[0].key = E_IPJ_KEY_TEST_ID;
    key_value[0].value = test_id;

    key_list_count = 1;
    key_list.list_count = 4;
    key_list.key = E_IPJ_KEY_TEST_PARAMETERS;
    key_list.list[0] = param0;
    key_list.list[1] = param1;
    key_list.list[2] = param2;
    key_list.list[3] = param3;

    error = ipj_bulk_set(iri_device, &key_value[0], key_value_count, &key_list, key_list_count);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_bulk_set");

    ipj_stopped_flag = 0;

    /* Activate test parameters */
    error = ipj_start(iri_device, E_IPJ_ACTION_TEST);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_start E_IPJ_ACTION_TEST");

    /* Set end time */
    end_time_ms = platform_timestamp_ms_handler() + timeout_ms;

    /* Clear the stopped flag */
    ipj_stopped_flag = 0;

    /*  Perform receive until end time reached or stop received */
    while (!ipj_stopped_flag && platform_timestamp_ms_handler() < end_time_ms)
    {
        /* Call ipj_receive to process tag reports  */
        error = ipj_receive(iri_device);
        IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_receive");
    }

    key_value_count = 1;
    key_value[0].key = E_IPJ_KEY_TEST_ID;
    key_value[0].value = 0;

    key_list_count = 1;
    key_list.list_count = 4;
    key_list.key = E_IPJ_KEY_TEST_PARAMETERS;
    key_list.list[0] = 0;
    key_list.list[1] = 0;
    key_list.list[2] = 0;
    key_list.list[3] = 0;

    error = ipj_bulk_set(iri_device, &key_value[0], key_value_count, &key_list, key_list_count);
    IPJ_UTIL_RETURN_ON_ERROR(error, "ipj_bulk_set");

    return error;
}


/* Report handler processes asynchronous reports */
ipj_error ipj_util_report_handler(
        ipj_iri_device* iri_device,
        ipj_report_id report_id,
        void* report)
{
    ipj_error error = E_IPJ_ERROR_SUCCESS;
    /* Case statement for each report type */
    switch (report_id)
    {
        case E_IPJ_REPORT_ID_TAG_OPERATION_REPORT:
            error = ipj_util_tag_operation_report_handler(
                    iri_device,
                    (ipj_tag_operation_report*) report);
            break;
        case E_IPJ_REPORT_ID_STOP_REPORT:
            error = ipj_util_stop_report_handler(
                    iri_device,
                    (ipj_stop_report*) report);
            break;
        case E_IPJ_REPORT_ID_GPIO_REPORT:
            error = ipj_util_gpio_report_handler(
                    iri_device,
                    (ipj_gpio_report*) report);
            break;
        case E_IPJ_REPORT_ID_ERROR_REPORT:
            error = ipj_util_error_report_handler(
                    iri_device,
                    (ipj_error_report*) report);
            break;
        case E_IPJ_REPORT_ID_STATUS_REPORT:
            error = ipj_util_status_report_handler(
                    iri_device,
                    (ipj_status_report*) report);
            break;
        case E_IPJ_REPORT_ID_TEST_REPORT:
            error = ipj_util_test_report_handler(
                    iri_device,
                    (ipj_test_report*) report);
            break;
        default:
            printf(
                    "%s: REPORT ID: %d NOT HANDLED\n",
                    (char*) iri_device->reader_identifier,
                    report_id);
            error = E_IPJ_ERROR_GENERAL_ERROR;
            break;
    }
    return error;
}

/* Tag report handler processes asynchronous reports */
ipj_error ipj_util_tag_operation_report_handler(
        ipj_iri_device* iri_device,
        ipj_tag_operation_report* tag_operation_report)
{
    uint32_t i;

    if (tag_operation_report->has_error && tag_operation_report->error > 0)
    {
        IPJ_UTIL_PRINT_ERROR(tag_operation_report->error,"tag_operation_report");
    }

    /* If tag report has epc, print epc */
    if (tag_operation_report->tag.has_epc)
    {
        /* Print reader identifier */
        printf("%s: EPC = ", (char*) iri_device->reader_identifier);

        ipj_util_print_epc(
                (uint16_t*) tag_operation_report->tag.epc.bytes,
                (int) tag_operation_report->tag.epc.size / 2,
                true);
    }
	
    /* If tag report has antenna, print antenna */
	if (tag_operation_report->tag.has_antenna)
	{
		/* Print antenna */
		printf("%s: Antenna = ", (char*)iri_device->reader_identifier);

		printf("%d\r\n", tag_operation_report->tag.antenna);
	}

    if (tag_operation_report->has_diagnostic)
    {
        printf("Diagnostic = 0x%08X\n", tag_operation_report->diagnostic);
    }

    if (tag_operation_report->has_tag_operation_type)
    {
        printf("Tag operation: ");
        switch (tag_operation_report->tag_operation_type)
        {
            case E_IPJ_TAG_OPERATION_TYPE_READ:
            {
                printf("READ\n");
                break;
            }
            case E_IPJ_TAG_OPERATION_TYPE_WRITE:
            {
                printf("WRITE\n");
                break;
            }
            case E_IPJ_TAG_OPERATION_TYPE_LOCK:
            {
                printf("LOCK\n");
                break;
            }
            case E_IPJ_TAG_OPERATION_TYPE_KILL:
            {
                printf("KILL\n");
                break;
            }
            case E_IPJ_TAG_OPERATION_TYPE_BLOCKPERMALOCK:
            {
                printf("BLOCK PERMALOCK\n");
                break;
            }
            case E_IPJ_TAG_OPERATION_TYPE_WRITE_EPC:
            {
                printf("WRITE EPC\n");
                break;
            }
            case E_IPJ_TAG_OPERATION_TYPE_QT:
            {
                printf("QT\n");
                break;
            }
            default:
            {
                printf("TYPE=%d\n", tag_operation_report->tag_operation_type);
            }
        }

        if (tag_operation_report->has_tag_operation_data)
        {
            printf(
                    "Report contains data: %d bytes\n",
                    (int) tag_operation_report->tag_operation_data.size);
            for (i = 0; i < tag_operation_report->tag_operation_data.size; i += 2)
            {
                if (i % (2 * 6) == 0 && i > 0)
                {
                    printf("\n");
                }
                printf(
                        "0x%04x|",
                        tag_operation_report->tag_operation_data.bytes[i] << 8
                                | tag_operation_report->tag_operation_data.bytes[i
                                        + 1]);
            }
        }
        printf("\n");

    }

    ipj_util_print_divider('-', 80);
    return E_IPJ_ERROR_SUCCESS;
}

/* Stop report handler processes asynchronous reports */
ipj_error ipj_util_stop_report_handler(
        ipj_iri_device* iri_device,
        ipj_stop_report* ipj_stop_report)
{
    if (ipj_stop_report->error == E_IPJ_ERROR_SUCCESS)
    {
        /* Print reader identifier */
        printf("%s: STOPPED\n", (char*) iri_device->reader_identifier);

        /* Set the stopped flag, the stop report does not have any fields that
         * need to be checked */
        ipj_stopped_flag = 1;
    }
    else
    {
        IPJ_UTIL_PRINT_ERROR(ipj_stop_report->error,"stop_report");
    }
    return ipj_stop_report->error;
}

/* GPIO handler processes asynchronous GPIO event reports */
ipj_error ipj_util_gpio_report_handler(
        ipj_iri_device* iri_device,
        ipj_gpio_report* gpio_report)
{
    unsigned int i;
    for (i = 0; i < 40; i++)
        printf("*");

    printf("\n%s: GPIO Report\n", (char*) iri_device->reader_identifier);

    printf("GPIO Modes:  ");
    for (i = 1; i < gpio_report->gpio_modes_count; i++)
    {
        switch (gpio_report->gpio_modes[i])
        {
            case E_IPJ_GPIO_MODE_DISABLED:
            {
                printf("D  ");
                break;
            }
            case E_IPJ_GPIO_MODE_INPUT:
            {
                printf("I  ");
                break;
            }
            case E_IPJ_GPIO_MODE_OUTPUT:
            {
                printf("O  ");
                break;
            }
            case E_IPJ_GPIO_MODE_OUTPUT_PULSE:
            {
                printf("OP ");
                break;
            }
            case E_IPJ_GPIO_MODE_INPUT_ACTION:
            {
                printf("IA ");
                break;
            }
            case E_IPJ_GPIO_MODE_OUTPUT_ACTION:
            {
                printf("OA ");
                break;
            }
            case E_IPJ_GPIO_MODE_OUTPUT_PULSE_ACTION:
            {
                printf("OPA");
                break;
            }
        }

        if (i < gpio_report->gpio_modes_count - 1)
            printf("|");
    }
    printf("\nGPIO States: ");

    for (i = 1; i < gpio_report->gpio_states_count; i++)
    {
        switch (gpio_report->gpio_states[i])
        {
            case E_IPJ_GPIO_STATE_LO:
            case E_IPJ_GPIO_STATE_FLOAT:
            {
                printf("0  ");
                break;
            }
            case E_IPJ_GPIO_STATE_HI:
            {
                printf("1  ");
                break;
            }
        }

        if (i < gpio_report->gpio_states_count - 1)
            printf("|");
    }
    printf("\n");

    for (i = 0; i < 40; i++)
        printf("*");

    printf("\n");

    return E_IPJ_ERROR_SUCCESS;
}

ipj_error ipj_util_error_report_handler(
        ipj_iri_device* iri_device,
        ipj_error_report* error_report)
{
    printf("Error Report\n");
    printf("Error:  0x%X, %d\n", error_report->error, error_report->error);
    printf("Param1: 0x%X, %d\n", error_report->param1, error_report->param1);
    printf("Param2: 0x%X, %d\n", error_report->param2, error_report->param2);
    printf("Param3: 0x%X, %d\n", error_report->param3, error_report->param3);
    printf("Param4: 0x%X, %d\n", error_report->param4, error_report->param4);
    return E_IPJ_ERROR_SUCCESS;
}

ipj_error ipj_util_status_report_handler(
        ipj_iri_device* iri_device,
        ipj_status_report* status_report)
{
    uint32_t i;
    printf("Status Report\n");
    printf("status_flag:  0x%X, %d\n", status_report->status_flag, status_report->status_flag);
    printf("status_1: 0x%X, %d\n",     status_report->status_1, status_report->status_1);
    printf("status_2: 0x%X, %d\n",     status_report->status_2, status_report->status_2);
    printf("status_3: 0x%X, %d\n",     status_report->status_3, status_report->status_3);

    printf("Additional Data:\n");
    for (i = 0; i < status_report->data_count; i++)
    {
        printf("[%d] 0x%X, %d\n", i, status_report->data[i], status_report->data[i]);
    }

    return E_IPJ_ERROR_SUCCESS;
}

ipj_error ipj_util_test_report_handler(
        ipj_iri_device* iri_device,
        ipj_test_report* test_report)
{
    uint32_t i;
    if (test_report->error != E_IPJ_ERROR_SUCCESS)
    {
        IPJ_UTIL_PRINT_ERROR(test_report->error, "test");
    }

    printf("\n*** %s Test Report ***\n", (char*) iri_device->reader_identifier);
    printf("Test ID: %d\n", test_report->test_id);
    printf("Test Results (optional):\n");
    printf("Result 1: 0x%X, %d\n", test_report->result_1, test_report->result_1);
    printf("Result 2: 0x%X, %d\n", test_report->result_2, test_report->result_2);
    printf("Result 3: 0x%X, %d\n", test_report->result_3, test_report->result_3);
    printf("Additional Data:\n");

    for (i = 0; i < test_report->data_count; i++)
    {
        printf("[%d] 0x%X, %d\n", i, test_report->data[i], test_report->data[i]);
    }

    return E_IPJ_ERROR_SUCCESS;
}

void ipj_util_diagnostic_handler(ipj_iri_device* iri_device, ipj_error error)
{
    switch (error)
    {
        case E_IPJ_ERROR_IRI_FRAME_DROPPED:
        {
            printf("%s Dropped IRI Frame!\n", (char*) iri_device->reader_identifier);
            break;
        }
        default:
        {
            break;
        }
    }
}