Impinj Radio Interface Toolkit LT for C (ITK-LT-C)

The ITK-C host library is designed to be run in embedded systems. Embedded systems cover a wide range of platforms and, as such, have a wide variety of system resources available. In some memory constrained applications the system ROM and RAM requirements of the ITK-C may prove to be too great.

To address these applications, the ITK-LT-C has been designed with a subset of the IRI API and features. The result is a small host library with a reduced RAM and ROM footprint with reader functionality that can enable many applications.

For more details on the differences between the ITK-C and ITK-LT-C, see the ITK Differences section of the FAQ.

Important

ITK-LT-C should only be used if the the standard ITK-C can not be used due to host memory constraints. The ITK-C is extensible and enables future advanced features.

As a general rule all documentation for the ITK-C applies to ITK-LT-C. The differences are detailed in the sections below.

ITK-LT-C Memory Usage

The following table lists verified ITK-LT-C host platforms and corresponding library sizes.

Notes:

  • These results come from library version 1.1.2.240
  • All config.h compile time switches were disabled
    • The ENABLE_FW_UPDATES compile time switch increases the library sizes reported below by approximately 750 bytes
  • The ITK-C library is comprised of multiple files
  • The ITK-LT-C library has been reduced to one file
  • Linux, Windows, and OSX ports are available now
  • Embedded MCU ports will be included in a future version of the ITK

If you have questions please submit a support ticket at support.impinj.com .

Library Sizes
Library Build Machine Target Platform Target Architecture Target Processor Toolchain Optimizations Library Contents Size (Bytes)
ITK-LT-C Windows 7 + Cygwin Windows 32-bit x86 GCC 4.5.3 For size (-Os) iri_lt.o 1,412
ITK-LT-C CentOS 6.5 Linux 32-bit x86 GCC 4.4.7 For size (-Os) iri_lt.o 1,248
ITK-LT-C Apple Mac 10.9.2 OSX 32-bit x86 GCC (Apple LLVM 5.1 - Clang 503.0.40) For size (-Os) iri_lt.o 1,362
ITK-LT-C Windows 7 + GCC ARM Embedded for Windows STM32F0DISCOVERY Board 32-bit ARM Cortex-M0 (STM32F051) GCC ARM Embedded 4.8.3 For size (-Os) iri_lt.o 1,016
ITK-LT-C Windows 7 + Code Composer Studio 6 MSP430FG4618/F2013 Experimenter’s Board 16-bit TI MSP430 (MSP430FG4618) TI Compiler 4.3.1 Level 4, for size iri_lt.obj 1,508
ITK-LT-C Windows 7 + AtmelStudio 6.1 AVR XMEGA-A1 Xplained 8-bit Atmel AVR (ATxmega128A1) AVR/GNU C Compiler 4.7.3 For size (-Os) iri_lt.o 2,229

Source Code

Source code is provided for the ITK-LT-C library and example applications. This will enable users to port the IRI library as needed and to get a jump start on writing code for their own specific applications.

Notes on the Library

  • New projects need to include all of the *.h and *.c files located within Library sub-directory
  • As an exception to the rule above, only one platform_*.c need be included
  • A PORTING.txt file has been provided with brief porting instructions
  • A platform_empty.c file has been provided with a stubbed out API to quickly enable a porting effort

Library Source Code Contents

ITK_LT_C\Library\config.h
ITK_LT_C\Library\iri_lt.c
ITK_LT_C\Library\iri_lt.h
ITK_LT_C\Library\platform.h
ITK_LT_C\Library\platform_empty.c
ITK_LT_C\Library\platform_linux.c
ITK_LT_C\Library\platform_osx.c
ITK_LT_C\Library\platform_win32.c
ITK_LT_C\Library\PORTING.txt
ITK_LT_C\Library\version.h

Notes on the Examples

  • Example applications (all IRI_LT_*.c files) are provided with build systems for the following environments:
    • Makefile for GNU based systems (Linux, Cygwin, etc.)
  • Each example contains a comment block near the top of the file explaining the examples purpose
  • An ipj_util_lt file is provided that contains functions common across the examples

Examples Source Code Contents

ITK_LT_C\Examples\ipj_util_lt.c
ITK_LT_C\Examples\ipj_util_lt.h
ITK_LT_C\Examples\IRI_LT_Access.c
ITK_LT_C\Examples\IRI_LT_Empty.c
ITK_LT_C\Examples\IRI_LT_GPIO.c
ITK_LT_C\Examples\IRI_LT_Intro.c
ITK_LT_C\Examples\IRI_LT_Loader.c
ITK_LT_C\Examples\IRI_LT_Multiple_Readers.c
ITK_LT_C\Examples\IRI_LT_Power_Management.c
ITK_LT_C\Examples\IRI_LT_RxOnly.c
ITK_LT_C\Examples\IRI_LT_Select.c
ITK_LT_C\Examples\IRI_LT_Test_CW_PRBS.c
ITK_LT_C\Examples\Makefile

API

The lists below provide links to all ITK-C API calls that are supported in ITK-LT-C.

Device Management:

Operational Commands:

Notes on ipj_flash_handle_loader_block

This API is disabled by default in order to keep the ITK-LT-C library size to a minimum.

It can be enabled via an ENABLE_FW_UPDATES compile time switch in config.h, at the cost of an increased library size.

See the IRI_LT_Loader example program for details on how to use this API to update firmware on the device.

Limitations

The lists below provide links to all ITK-C API calls that are not supported in ITK-LT-C.

Device Management:

Operational Commands:

In addition to API limitations, there is also no individual Response or Report timestamping. The Tag Operation Report however still has a configurable timestamp field.

Notes on Limitations

The sections below provide further explanations on a few specific API limitations.

ipj_register_handler

The Platform Interface remains identical to ITK-C, however without the dynamic handler registration provided by ipj_register_handler the platform function names must be exactly as defined in Platform.h.

This is already the case for the provided platform_*.c files, so if they are used then no modification is needed.

Note

In addition to platform handlers, there is also an externed function defined in iri_lt.h for ipj_report_handler which needs to be implemented in user code. This allows users to trim down the report handler to only what is needed for a specific application. An example of ipj_report_handler can be found in ipj_util_lt.c.

ipj_modify_connection

This function enabled dynamically changing the baudrate of the device on the fly. That is not possible with ITK-LT-C, however Stored Settings and the Indy Demo Tool can be used to configure a non-default baudrate which can then be passed into ipj_connect. In this way the ITK-LT-C can support alternate baudrates.

ipj_suppress_set_responses

This function enabled dynamically suppressing set responses. This is not possible with ITK-LT-C, however a compile time switch has been provided in config.h to SUPPRESS_SET_RESPONSES. If this switch is enabled then any Set command will not send a response, thereby cutting down on the IRI traffic over the wire.

The risk with this option is to miss some possible errors that could occur with the command. Therefore it is recommended that SUPPRESS_SET_RESPONSES be disabled during development and only enabled when the host application is ready for production.

Reports

Reports are defined differently in ITK-LT-C. All of them are simple c structs with each parameter defined as a fixed width uint32_t.

The exception to this rule is the Tag Operation Report, which is encoded as a series of simple field blocks separated by a 32-bit header (16-bits FIELD_ID and 16-bits FIELD_LENGTH). This allows users to trim down the report handler to only what is needed for a specific application. The desired report fields can be enabled or disabled through E_IPJ_KEY_REPORT_CONTROL_TAG.

Source code for both report types is provided below.

Definitions

Here is the definition of the report structs and the Tag Operation Report field IDs from iri_lt.h:

// *****************************************************************************
{%- for r in reports%}
{{r}}
{%-endfor%}
// *****************************************************************************
// IRI API - LT Defines
// *****************************************************************************
{{flex_reports}}

Here are some macros for helping decode the Tag Operation Report:

/* Report Decoding */
#define REPORT_FIELD_ID(x)          ((x >> 16) & 0xFFFF)
#define REPORT_FIELD_LENGTH(x)      (x & 0xFFFF)
#define ROUNDED_COUNT_32(x)         (((x + sizeof(uint32_t) - 1) & 0xFFFFFFFC) / sizeof(uint32_t))

Decoders

Here are example report decoders, including the Tag Operation Report, as defined in ipj_util_lt.c:

ipj_error ipj_util_tag_operation_report_handler(
        ipj_iri_device* iri_device,
        uint32_t report_count_32,
        uint32_t* tag_operation_report)
{
    uint32_t index = 0;
    while (index < report_count_32)
    {
        uint32_t field_header = tag_operation_report[index++];
        switch (REPORT_FIELD_ID(field_header))
        {
            case E_IPJ_TAG_OPERATION_REPORT_ERROR:
            {
                IPJ_UTIL_PRINT_ERROR(tag_operation_report[index], "tag_operation_report");
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_PC:
            {
                printf("PC: %04X\n", tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_XPC:
            {
                printf("XPC: %04X\n", tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_CRC:
            {
                printf("CRC: %04X\n", tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_RSSI:
            {
                printf("RSSI: %d\n", (int)tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_PHASE:
            {
                printf("PHASE: %d\n", (int)tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_CHANNEL:
            {
                printf("CHANNEL: %d\n", tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_ANTENNA:
            {
                printf("ANTENNA: %d\n", tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_TAG_OPERATION_TYPE:
            {
                printf("Tag operation: ");
                switch (tag_operation_report[index])
                {
                    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[index]);
                    }
                }
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_RETRIES:
            {
                printf("RETRIES: %d\n", tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_DIAGNOSTIC:
            {
                printf("DIAGNOSTIC: %X\n", tag_operation_report[index]);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_TIMESTAMP:
            {
                printf(
                        "TIMESTAMP: %I64d\n",
                        (uint64_t) tag_operation_report[index]
                                | ((uint64_t) (tag_operation_report[index + 1]) << 32));
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_EPC:
            {
                printf("EPC: ");
                ipj_util_print_epc(
                        (uint16_t*) &tag_operation_report[index],
                        REPORT_FIELD_LENGTH(field_header) / sizeof(uint16_t),
                        true);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_TID:
            {
                printf("TID: ");
                /* Reuse the print epc method */
                ipj_util_print_epc(
                        (uint16_t*) &tag_operation_report[index],
                        REPORT_FIELD_LENGTH(field_header) / sizeof(uint16_t),
                        true);
                break;
            }
            case E_IPJ_TAG_OPERATION_REPORT_TAG_OPERATION_DATA:
            {
                printf("Report contains data: %d bytes\n", REPORT_FIELD_LENGTH(field_header));
                /* Reuse the print epc method */
                ipj_util_print_epc(
                        (uint16_t*) &tag_operation_report[index],
                        REPORT_FIELD_LENGTH(field_header) / sizeof(uint16_t),
                        true);
                break;
            }
        }

        index += ROUNDED_COUNT_32(REPORT_FIELD_LENGTH(field_header));

    }

    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 < ARRAY_SIZE(gpio_report->gpio_modes); 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 < ARRAY_SIZE(gpio_report->gpio_modes) - 1)
            printf("|");
    }
    printf("\nGPIO States: ");

    for (i = 1; i < ARRAY_SIZE(gpio_report->gpio_states); 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 < ARRAY_SIZE(gpio_report->gpio_states) - 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 < ARRAY_SIZE(status_report->data); 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 < ARRAY_SIZE(test_report->data); i++)
    {
        printf("[%d] 0x%X, %d\n", i, test_report->data[i], test_report->data[i]);
    }

    return E_IPJ_ERROR_SUCCESS;
}