Configure the Indy SiP using ipj_set, ipj_set_value, or ipj_bulk_set. The ipj_set, ipj_set_value, and ipj_bulk_set functions allow the user to write data to keys, or registers, within the Indy SiP. See the Key Codes section for a complete list of keys.
The ipj_set, ipj_set_value, and ipj_bulk_set functions write configuration data to the Indy SiP. The Indy SiP applies the configuration settings when the ipj_start function is called.
Current settings may be read from the Indy SiP by using ipj_get, ipj_get_value, or ipj_bulk_get.
Warning
Setting keys will persist their value until they are changed or the device is reset. It is important to explictly configure keys for each operation in a manner which are deterministic. For example, if a Tag operation is enabled the device will perform the configured tag operation on each start command until disabled.
Configure the regulatory region using the E_IPJ_KEY_REGION_ID key.
Note
The RS500 GX SKUs supports regions in the 902-928 MHz frequency range, including the FCC. The RS500 EU SKUs supports regions in the 865-868 MHz frequency range, including ETSI. Each RS2000 SKU supports 2 different frequency ranges, specified in the device datasheet.
The following code snippet sets the regulatory region to ETSI EN 302 208 v1.4.1:
ipj_set_value(&iri_device, E_IPJ_KEY_REGION_ID, E_IPJ_REGION_ETSI_EN_302_208_V1_4_1);
Configure the transmit power using the E_IPJ_KEY_ANTENNA_TX_POWER key.
The following code snippet sets the transmit power to 20.00 dBm:
ipj_set_value(&iri_device, E_IPJ_KEY_ANTENNA_TX_POWER, 2000);
Configure the RF Mode using the E_IPJ_KEY_RF_MODE key.
The following code snippet sets the RF Mode to 3:
ipj_set_value(&iri_device, E_IPJ_KEY_RF_MODE, 3);
Configure the antenna switching sequence using the E_IPJ_KEY_ANTENNA_SEQUENCE key.
The following code snippet sets the antenna switching sequence to 1,2,4,3,2:
ipj_key_list key_list;
uint32_t key_list_count;
memset(&key_list, 0, sizeof(key_list));
key_list_count = 1;
key_list.key = E_IPJ_KEY_ANTENNA_SEQUENCE;
key_list.list_count = 16;
key_list.list[0] = 1;
key_list.list[1] = 2;
key_list.list[2] = 4;
key_list.list[3] = 3;
key_list.list[4] = 2;
// All other list items initialized to 0 by memset
ipj_bulk_set(&iri_device, 0, 0, &key_list, key_list_count);
Indy SiPs manage Tag populations using three basic operations:
Details of the Select, Inventory, and Access operations may be found in the UHF Gen2 specification: GS1/EPCglobal Radio-Frequency Identity Protocol Generation-2 UHF RFID Protocol for Communications at 860 MHz - 960 MHz. Version 1.20
Users configure the Select, Inventory, and Access parameters prior to calling the ipj_start function. In response to the ipj_start function, the Indy SiP will transmit the appropriate Select, Inventory, and Access commands. Results of Inventory and Access operations are reported in Tag Operation Reports.
The Select operation is optional.
Configure Select operation using the following keys (see the UHF Gen2 specification for details about the Select command):
Warning
Setting the enable to true will persist until changed. If no longer desired, the user must configure the enable back to false.
ipj_set_value(&iri_device, E_IPJ_KEY_SELECT_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_SELECT_TARGET, E_IPJ_SELECT_TARGET_SL_FLAG);
ipj_set_value(&iri_device, E_IPJ_KEY_SELECT_ACTION, E_IPJ_SELECT_ACTION_ASLINVA_DSLINVB);
ipj_set_value(&iri_device, E_IPJ_KEY_SELECT_MEM_BANK, E_IPJ_MEM_BANK_EPC);
ipj_set_value(&iri_device, E_IPJ_KEY_SELECT_POINTER, 0x20);
ipj_set_value(&iri_device, E_IPJ_KEY_SELECT_MASK_LENGTH, 96);
ipj_set(&iri_device, E_IPJ_KEY_SELECT_MASK_VALUE, 0, 0, 0x0123);
ipj_set(&iri_device, E_IPJ_KEY_SELECT_MASK_VALUE, 0, 1, 0x4567);
ipj_set(&iri_device, E_IPJ_KEY_SELECT_MASK_VALUE, 0, 2, 0x89AB);
ipj_set(&iri_device, E_IPJ_KEY_SELECT_MASK_VALUE, 0, 3, 0xCDEF);
ipj_set(&iri_device, E_IPJ_KEY_SELECT_MASK_VALUE, 0, 4, 0xFFFF);
ipj_set(&iri_device, E_IPJ_KEY_SELECT_MASK_VALUE, 0, 5, 0x0001);
Enabling the Select operation results in the Indy SiP sending Select command before each Inventory round. It is also necessary to configure Inventory to identify and report selected tags (based on the use case and select target selected in the Select Command):
ipj_set_value(&iri_device, E_IPJ_KEY_INVENTORY_SELECT_FLAG, E_IPJ_INVENTORY_SELECT_FLAG_SL);
After the Indy SiP is configured:
Configuration of the Inventory parameters is not required. The Indy SiP defaults to a standard Inventory configuration. Recommend users configure Inventory parameters for specific applications.
The following keys control the Inventory operation (see the UHF Gen2 specification for details):
ipj_set_value(&iri_device, E_IPJ_KEY_INVENTORY_TAG_POPULATION, 10);
ipj_set_value(&iri_device, E_IPJ_KEY_INVENTORY_SELECT_FLAG, E_IPJ_INVENTORY_SELECT_FLAG_ALL_SL);
ipj_set_value(&iri_device, E_IPJ_KEY_INVENTORY_SESSION, 2);
ipj_set_value(&iri_device, E_IPJ_KEY_INVENTORY_SEARCH_MODE, E_IPJ_INVENTORY_SEARCH_MODE_DUAL_TARGET);
The following keys enable Impinj Inventory extensions:
ipj_set_value(&iri_device, E_IPJ_KEY_FAST_ID_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_FOCUS_ENABLE, true);
After the Indy SiP is configured:
Access operations enable users to read Tag memory, write Tag memory, lock Tag memory and kill a Tag.
Users configure the Indy SiP for the desired read, write, lock, blockpermalock, or kill operation. The Indy SiP will perform the desired Access operation on each Tag that is inventoried. The results are provided in the Tag Operation Reports.
Warning
Setting the enable to true will persist until changed. If no longer desired, the user must configure the enable back to false.
The following keys enable Read operation (see the UHF Gen2 specification for details about the Read command):
Example Read configuration:
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_READ);
ipj_set_value(&iri_device, E_IPJ_KEY_READ_MEM_BANK, E_IPJ_MEM_BANK_TID);
ipj_set_value(&iri_device, E_IPJ_KEY_READ_WORD_POINTER, 0x00);
ipj_set_value(&iri_device, E_IPJ_KEY_READ_WORD_COUNT, 2);
After the Indy SiP is configured:
The following keys enable Write operation (see the UHF Gen2 specification for details about the Write command):
Example Write configuration:
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_WRITE);
ipj_set_value(&iri_device, E_IPJ_KEY_WRITE_MEM_BANK, E_IPJ_MEM_BANK_EPC);
ipj_set_value(&iri_device, E_IPJ_KEY_WRITE_WORD_POINTER, 0x01);
ipj_set_value(&iri_device, E_IPJ_KEY_WRITE_WORD_COUNT, 7);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 0, 0x3000);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 1, 0xAAAA);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 2, 0x5555);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 3, 0x0123);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 4, 0x4567);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 5, 0x89AB);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 6, 0xCDEF);
Alternatively, ipj_bulk_set can be used to configure the Indy SiP to write tag memory with a single function call
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 = 5;
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;
key_list.list[1] = 0xAAAA;
key_list.list[2] = 0x5555;
key_list.list[3] = 0x0123;
key_list.list[4] = 0x4567;
key_list.list[5] = 0x89AB;
key_list.list[6] = 0xCDEF;
ipj_bulk_set(&iri_device, &key_value[0], key_value_count, &key_list, key_list_count);
After the Indy SiP is configured:
The Write EPC operation writes Tag EPC memory and optionally updates the PC word. When the Write EPC operation is selected, the Indy SiP automatically selects the EPC memory bank and EPC word pointer. Additionally, the Indy SiP updates the PC word according to the ...EPC_LENGTH_CONTROL and ...AFI_CONTROL key values. The following keys enable Write EPC operation (see the UHF Gen2 specification for details):
Example Write EPC configuration:
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_WRITE_EPC);
ipj_set_value(&iri_device, E_IPJ_KEY_WRITE_EPC_LENGTH_CONTROL, E_IPJ_WRITE_EPC_LENGTH_CONTROL_AUTO);
ipj_set_value(&iri_device, E_IPJ_KEY_WRITE_EPC_AFI_CONTROL, 0);
ipj_set_value(&iri_device, E_IPJ_KEY_WRITE_EPC_AFI_VALUE, 0);
ipj_set_value(&iri_device, E_IPJ_KEY_WRITE_WORD_COUNT, 6);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 0, 0xAAAA);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 1, 0x5555);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 2, 0x0123);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 3, 0x4567);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 4, 0x89AB);
ipj_set(&iri_device, E_IPJ_KEY_WRITE_DATA, 0, 5, 0xCDEF);
After the Indy SiP is configured:
The following keys enable the Lock operation (see the UHF Gen2 specification for details about the Lock command):
Example Lock configuration:
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_LOCK);
ipj_set_value(&iri_device, E_IPJ_KEY_LOCK_PAYLOAD, 0xFFFFF);
After the Indy SiP is configured:
The following keys enable the Blockpermalock operation (see the UHF Gen2 specification for details about the Blockpermalock command):
Example Blockpermalock configuration:
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_BLOCKPERMALOCK);
ipj_set_value(&iri_device, E_IPJ_KEY_BLOCKPERMALOCK_ACTION, E_IPJ_BLOCKPERMALOCK_ACTION_PERMALOCK);
ipj_set_value(&iri_device, E_IPJ_KEY_BLOCKPERMALOCK_MEM_BANK, E_IPJ_MEM_BANK_USER);
ipj_set_value(&iri_device, E_IPJ_KEY_BLOCKPERMALOCK_BLOCK_POINTER, 0x00);
ipj_set_value(&iri_device, E_IPJ_KEY_BLOCKPERMALOCK_BLOCK_RANGE, 1);
ipj_set_value(&iri_device, E_IPJ_KEY_BLOCKPERMALOCK_MASK, 0x1);
After the Indy SiP is configured:
The following keys enable the Kill operation (see the UHF Gen2 specification for details about the Kill procedure):
Example Kill configuration:
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_KILL);
ipj_set_value(&iri_device, E_IPJ_KEY_KILL_PASSWORD, 0x01234567);
After the Indy SiP is configured:
The following keys enable the QT operation:
Example QT configuration:
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_QT);
ipj_set_value(&iri_device, E_IPJ_KEY_QT_ACTION, E_IPJ_QT_ACTION_READ);
After the Indy SiP is configured:
Example QT configuration to read public EPC:
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION_ENABLE, true);
ipj_set_value(&iri_device, E_IPJ_KEY_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_QT);
ipj_set_value(&iri_device, E_IPJ_KEY_QT_ACTION, E_IPJ_QT_ACTION_WRITE);
ipj_set_value(&iri_device, E_IPJ_KEY_QT_PERSISTENCE, E_IPJ_QT_PERSISTENCE_TEMPORARY);
ipj_set_value(&iri_device, E_IPJ_KEY_QT_DATA_PROFILE, E_IPJ_QT_DATA_PROFILE_PUBLIC);
ipj_set_value(&iri_device, E_IPJ_KEY_QT_ACCESS_RANGE, E_IPJ_QT_ACCESS_RANGE_NORMAL);
ipj_set_value(&iri_device, E_IPJ_KEY_QT_TAG_OPERATION, E_IPJ_TAG_OPERATION_TYPE_READ);
ipj_set_value(&iri_device, E_IPJ_KEY_READ_MEM_BANK, E_IPJ_MEM_BANK_EPC);
ipj_set_value(&iri_device, E_IPJ_KEY_READ_WORD_POINTER, 2);
ipj_set_value(&iri_device, E_IPJ_KEY_READ_WORD_COUNT, 6);
After the Indy SiP is configured:
The Access Retry feature is enabled using the E_IPJ_KEY_TAG_OPERATION_RETRIES key. The Access operation is retried up to maximum number of retries specified by the key. A retry is not attempted if the Tag returns a Memory Overrun or Memory Locked error condition. The number of attempted retries is reported in the Tag Operation Report
The Indy SiP possesses 4 user controllable GPIO pins which can be configured as general purpose outputs, inputs, or action-attached inputs. Outputs can be driven either high or low. Inputs exist in either a high-impedance, pulled up, or pulled down state.
Note
The Default state for all GPIO pins is high-impedance input.
The following keys enable the GPIO operation:
Note
GPIO_PULSE is not yet supported
Each key is banked and therefore requires the use of an index value corresponding to the appropriate GPIO (1-4). Index 0 Is reserved for future functionality.
Once all appropriate keys are set, the GPIO configuration is initialized by sending the Indy SiP a ipj_start command with the action argument E_IPJ_ACTION_GPIO.
To configure GPIO 1 as an output and set it’s state to logic high (+3v3):
ipj_set(&iri_device, E_IPJ_KEY_GPIO_MODE, 1, 0, E_IPJ_GPIO_MODE_OUTPUT);
ipj_set(&iri_device, E_IPJ_KEY_GPIO_STATE, 1, 0, E_IPJ_GPIO_STATE_HI);
ipj_start(&iri_device, E_IPJ_ACTION_GPIO);
ipj_stop(&iri_device, E_IPJ_ACTION_GPIO);
To configure GPIO 1 as an input with an internal pull-down (0v):
ipj_set(&iri_device, E_IPJ_KEY_GPIO_MODE, 1, 0, E_IPJ_GPIO_MODE_INPUT);
ipj_set(&iri_device, E_IPJ_KEY_GPIO_STATE, 1, 0, E_IPJ_GPIO_STATE_HI);
ipj_start(&iri_device, E_IPJ_ACTION_GPIO);
/* At this point, the user should call ipj_receive and handle any
* incoming GPIO reports. When the desired amount of reports have
* been collected, the user should call ipj_stop and poll for the gpio
* stop report */
ipj_stop(&iri_device, E_IPJ_ACTION_GPIO);
To configure GPIO 1 as a floating input that will start inventory when it is pulled high (+3v3):
ipj_set(&iri_device, E_IPJ_KEY_GPIO_MODE, 1, 0, E_IPJ_GPIO_MODE_INPUT_ACTION);
ipj_set(&iri_device, E_IPJ_KEY_GPIO_STATE, 1, 0, E_IPJ_GPIO_STATE_FLOAT);
ipj_set(&iri_device, E_IPJ_KEY_GPIO_HI_ACTION, 1, 0, E_IPJ_GPI_ACTION_START_INVENTORY);
ipj_start(&iri_device, E_IPJ_ACTION_GPIO);
/* At this point, the user should begin calling ipj_receive(). When
* there is a logic-high event on the selected pin, the user will
* receive a GPIO report, followed by tag reports as tags come into
* the field. When the user has received the desired number of tag
* reports, they should:
* 1. issue an ipj_stop(&iri_device, E_IPJ_ACTION_INVENTORY) command
* 2. call ipj_receive until they receive an inventory stop report.
* 3. issue an ipj_stop(&iri_device, E_IPJ_ACTION_GPIO) command
* 4. call ipj_receive until they receive a gpio stop report
*/
ipj_stop(&iri_device, E_IPJ_ACTION_GPIO);
It is currently only possible to start and stop inventory via an input pin. Please see ipj_gpi_action for more info
The GPIO input logic allows for a user programmable debounce period to be set in increments of 1 ms. If the debounce period is set to 0 (default), any input events will be reported and (if appropriately configured) acted upon. If it is set to > 0, the firmware will suppress any events that fall short of fulfilling this lockout period.
Furthermore, the internal GPI control is handled via polling, and the debounce timer has a tickrate of 100 us. As a result, the best-case response time will be debounce_time +/-100 us. The user should therefore not set the debounce time too close to the total expected period of the input trigger signal.
Debounce period is set to 9 ms. The target GPI is held high for exactly 9 ms. Due to the resolution of the debounce timer, the debounce clock expires at 9.09 ms, and the event is missed.
For the Above scenario to function as intended, either the debounce rate would need to be reduced to 8 ms, or the GPI hold time would need to be extended.
Setting the debounce key:
/* Set the Debounce rate for GPIO 1 to 8ms */
ipj_set(&iri_device, E_IPJ_KEY_GPIO_DEBOUNCE_MS, 1, 0, 8);
For evaluation purposes, the Indy SiP can be configured to transmit CW on a fixed frequency.
The following code snippet sets the test frequency to 912.25 MHz:
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_ID, E_IPJ_TEST_ID_SET_FREQUENCY);
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_PARAMETERS, 912250);
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_PARAMETERS, 0);
ipj_stopped_flag = 0;
ipj_start(&iri_device, E_IPJ_ACTION_TEST);
while (!ipj_stopped_flag)
{
ipj_receive(&iri_device); /* Report handler to set ipj_stopped_flag=1 on stop_report */
}
The following code snippet turns on CW:
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_ID, E_IPJ_TEST_ID_CW_CONTROL);
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_PARAMETERS, 1);
ipj_stopped_flag = 0;
ipj_start(&iri_device, E_IPJ_ACTION_TEST);
while (!ipj_stopped_flag)
{
ipj_receive(&iri_device); /* Report handler to set ipj_stopped_flag=1 on stop_report */
}
The following code snippet turns off CW:
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_ID, E_IPJ_TEST_ID_CW_CONTROL);
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_PARAMETERS, 0);
ipj_stopped_flag = 0;
ipj_start(&iri_device, E_IPJ_ACTION_TEST);
while (!ipj_stopped_flag)
{
ipj_receive(&iri_device); /* Report handler to set ipj_stopped_flag=1 on stop_report */
}
For evaluation purposes, the Indy SiP can be configured to transmit random data (PRBS) on a fixed frequency.
The following code snippet sets test frequency to 912.25 MHz:
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_ID, E_IPJ_TEST_ID_SET_FREQUENCY);
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_PARAMETERS, 912250);
ipj_stopped_flag = 0;
ipj_start(&iri_device, E_IPJ_ACTION_TEST);
while (!ipj_stopped_flag)
{
ipj_receive(&iri_device); /* Report handler to set ipj_stopped_flag=1 on stop_report */
}
The following code snippet turns on random data:
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_ID, E_IPJ_TEST_ID_PRBS_CONTROL);
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_PARAMETERS, 1);
ipj_stopped_flag = 0;
ipj_start(&iri_device, E_IPJ_ACTION_TEST);
while (!ipj_stopped_flag)
{
ipj_receive(&iri_device); /* Report handler to set ipj_stopped_flag=1 on stop_report */
}
The following code snippet turns off random data:
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_ID, E_IPJ_TEST_ID_PRBS_CONTROL);
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_PARAMETERS, 0);
ipj_stopped_flag = 0;
ipj_start(&iri_device, E_IPJ_ACTION_TEST);
while (!ipj_stopped_flag)
{
ipj_receive(&iri_device); /* Report handler to set ipj_stopped_flag=1 on stop_report */
}
The following code snippet gets the current internal and external temperature. The test report includes the same temperature data as the ...TEST_RESULT keys. The temperature values represent degrees C. The values represented by each of the test result keys are shown in the table below.
Temperature test results Key Value represented E_IPJ_KEY_TEST_RESULT_1 SiP internal controller temperature E_IPJ_KEY_TEST_RESULT_2 SiP external estimated temperature E_IPJ_KEY_TEST_RESULT_3 SiP PA temperature (RS2000 only)
uint32_t internal_temperature;
uint32_t external_temperature;
uint32_t pa_temperature;
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_ID, E_IPJ_TEST_ID_TEMPERATURE_CONTROL);
ipj_set_value(&iri_device, E_IPJ_KEY_TEST_PARAMETERS, 1);
ipj_stopped_flag = 0;
ipj_start(&iri_device, E_IPJ_ACTION_TEST);
while (!ipj_stopped_flag)
{
ipj_receive(&iri_device); /* Report handler to set ipj_stopped_flag=1 on stop_report */
}
error = ipj_get_value(&iri_device, E_IPJ_KEY_TEST_RESULT_1, &internal_temperature);
error = ipj_get_value(&iri_device, E_IPJ_KEY_TEST_RESULT_2, &external_temperature);
error = ipj_get_value(&iri_device, E_IPJ_KEY_TEST_RESULT_3, &pa_temperature);
The Indy SiPs generate Tag Operation Reports when tags are inventoried. Tag Operation Reports include the ipj_tag_operation_report structure. The ipj_tag_operation_report structure includes the ipj_tag structure. The fields within the ipj_tag structure are optional. Only the EPC, TID (when FastId is enabled) and Timestamp fields are enabled by default.
Configure report fields using the following key:
Example report configuration:
ipj_set_value(
&iri_device,
E_IPJ_KEY_REPORT_CONTROL_TAG,
E_IPJ_TAG_FLAG_BIT_EPC | E_IPJ_TAG_FLAG_BIT_TID |
E_IPJ_TAG_FLAG_BIT_TIMESTAMP | E_IPJ_TAG_FLAG_BIT_CHANNEL);
The Indy SiPs support a broad range of regulatory regions. The regulatory regions are listed here.
Users can create a custom region by configuring an Indy SiP appropriately. Configure an Indy SiP for custom region using the following keys:
Change the region to E_IPJ_REGION_CUSTOM after configuring the first 8 keys and before configuring the channel table and channel table size. Custom region settings are applied when the E_IPJ_KEY_REGION_ID is set for E_IPJ_REGION_CUSTOM. If subsequent changes are required, change the region to another region and set back to E_IPJ_REGION_CUSTOM to apply the settings.
E_IPJ_KEY_REGION_INDY_PLL_R_DIVIDER controls the frequency resolution of the RF carrier. RF carrier frequency equals (6*N/R) MHz, where N is an integer. The RF carrier frequency is limited to a given range for each Indy SiP SKU. Set the Indy PLL R Divider according the following table.
Indy Pll R Divider Divider Frequency Resolution (or Frequency Step Size) Example Region 24 250 kHz E_IPJ_REGION_FCC_PART_15_247 30 200 kHz E_IPJ_REGION_SOUTH_AFRICA_915_919_MHZ 48 125 kHz E_IPJ_REGION_CHINA_920_925_MHZ 60 100 kHz E_IPJ_REGION_ETSI_EN_302_208_V1_4_1
Note
Custom region keys are only applied after the E_IPJ_KEY_REGION_ID is changed to E_IPJ_REGION_CUSTOM.
Example FCC configuration:
ipj_error setup_custom_region_fcc(ipj_iri_device* iri_device)
{
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;
/*
* 1. Setup Custom Region
*/
key_value_count = 9;
memset(key_value, 0, sizeof(key_value));
memset(&key_list, 0, sizeof(key_list));
key_value[0].key = E_IPJ_KEY_REGION_ON_TIME_NOMINAL;
key_value[0].value = 200;
key_value[1].key = E_IPJ_KEY_REGION_ON_TIME_ACCESS;
key_value[1].value = 400;
key_value[2].key = E_IPJ_KEY_REGION_OFF_TIME;
key_value[2].value = 0;
key_value[3].key = E_IPJ_KEY_REGION_OFF_TIME_SAME_CHANNEL;
key_value[3].value = 0;
key_value[4].key = E_IPJ_KEY_REGION_START_FREQUENCY_KHZ;
key_value[4].value = 902750;
key_value[5].key = E_IPJ_KEY_REGION_CHANNEL_SPACING_KHZ;
key_value[5].value = 500;
key_value[6].key = E_IPJ_KEY_REGION_RANDOM_HOP;
key_value[6].value = 1;
key_value[7].key = E_IPJ_KEY_REGION_INDY_PLL_R_DIVIDER;
key_value[7].value = 24;
key_value[8].key = E_IPJ_KEY_REGION_RF_FILTER;
key_value[8].value = 0;
error = ipj_bulk_set(iri_device, &key_value[0], key_value_count, NULL, 0);
if (error)
{
printf("ERROR: IPJ_BULK_SET FAILED - ERROR CODE: %d\n\n", error);
return error;
}
/*
* 2. Change Region
* Note: Custom region params are only applied once and cannot be updated on the fly. Further
* they are only applied if the region changes. Force the region to something non-custom,
* then change to custom so the settings are applied.
*/
error = ipj_set_value(iri_device, E_IPJ_KEY_REGION_ID, E_IPJ_REGION_FCC_PART_15_247);
if (error)
{
printf("ERROR: Set E_IPJ_KEY_REGION_ID FAILED - ERROR CODE: %d\n\n", error);
return error;
}
error = ipj_set_value(iri_device, E_IPJ_KEY_REGION_ID, E_IPJ_REGION_CUSTOM);
if (error)
{
printf("ERROR: Set E_IPJ_KEY_REGION_ID FAILED - ERROR CODE: %d\n\n", error);
return error;
}
/*
* 3. Setup Channel Table
*/
key_list_count = 1;
key_list.key = E_IPJ_KEY_REGION_CHANNEL_TABLE;
key_list.list_count = 32; /* Max size for key_list */
key_list.has_value_index = true;
key_list.value_index = 0;
/* Set the first part of the channel table*/
for (i = 0; i < key_list.list_count; i++)
{
/* Channels are one based */
key_list.list[i] = i + 1;
}
error = ipj_bulk_set(iri_device, NULL, 0, &key_list, key_list_count);
if (error)
{
printf("ERROR: IPJ_BULK_SET FAILED - ERROR CODE: %d\n\n", error);
return error;
}
/* The rest of the channels */
key_list.list_count = 18;
key_list.has_value_index = true;
key_list.value_index = 32;
/* Set the first part of the channel table*/
for (i = 0; i < key_list.list_count; i++)
{
/* Channels are one based, pick up where we left off */
key_list.list[i] = i + 32 + 1;
}
error = ipj_bulk_set(iri_device, NULL, 0, &key_list, key_list_count);
if (error)
{
printf("ERROR: IPJ_BULK_SET FAILED - ERROR CODE: %d\n\n", error);
return error;
}
error = ipj_set_value(iri_device, E_IPJ_KEY_REGION_CHANNEL_TABLE_SIZE, 50);
if (error)
{
printf("ERROR: Set E_IPJ_KEY_REGION_CHANNEL_TABLE_SIZE FAILED - ERROR CODE: %d\n\n", error);
return error;
}
return E_IPJ_ERROR_SUCCESS;
}
Example ETSI configuration:
ipj_error setup_custom_region_etsi(ipj_iri_device* iri_device)
{
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;
/*
* 1. Setup Custom Region
*/
key_value_count = 8;
memset(key_value, 0, sizeof(key_value));
memset(&key_list, 0, sizeof(key_list));
key_value[0].key = E_IPJ_KEY_REGION_ON_TIME_NOMINAL;
key_value[0].value = 3800;
key_value[1].key = E_IPJ_KEY_REGION_ON_TIME_ACCESS;
key_value[1].value = 4000;
key_value[2].key = E_IPJ_KEY_REGION_OFF_TIME;
key_value[2].value = 0;
key_value[3].key = E_IPJ_KEY_REGION_OFF_TIME_SAME_CHANNEL;
key_value[3].value = 100;
key_value[4].key = E_IPJ_KEY_REGION_START_FREQUENCY_KHZ;
key_value[4].value = 865100;
key_value[5].key = E_IPJ_KEY_REGION_CHANNEL_SPACING_KHZ;
key_value[5].value = 200;
key_value[6].key = E_IPJ_KEY_REGION_RANDOM_HOP;
key_value[6].value = 0;
key_value[7].key = E_IPJ_KEY_REGION_INDY_PLL_R_DIVIDER;
key_value[7].value = 60;
error = ipj_bulk_set(iri_device, &key_value[0], key_value_count, NULL, 0);
if (error)
{
printf("ERROR: IPJ_BULK_SET FAILED - ERROR CODE: %d\n\n", error);
return error;
}
/*
* 2. Change Region
* Note: Custom region params are only applied once and cannot be updated on the fly. Further
* they are only applied if the region changes. Force the region to something non-custom,
* then change to custom so the settings are applied.
*/
error = ipj_set_value(iri_device, E_IPJ_KEY_REGION_ID, E_IPJ_REGION_FCC_PART_15_247);
if (error)
{
printf("ERROR: Set E_IPJ_KEY_REGION_ID FAILED - ERROR CODE: %d\n\n", error);
return error;
}
error = ipj_set_value(iri_device, E_IPJ_KEY_REGION_ID, E_IPJ_REGION_CUSTOM);
if (error)
{
printf("ERROR: Set E_IPJ_KEY_REGION_ID FAILED - ERROR CODE: %d\n\n", error);
return error;
}
/*
* 3. Setup Channel Table
*/
key_list_count = 1;
key_list.key = E_IPJ_KEY_REGION_CHANNEL_TABLE;
key_list.list_count = 4;
key_list.list[0] = 4;
key_list.list[1] = 7;
key_list.list[2] = 10;
key_list.list[3] = 13;
error = ipj_bulk_set(iri_device, NULL, 0, &key_list, key_list_count);
if (error)
{
printf("ERROR: IPJ_BULK_SET FAILED - ERROR CODE: %d\n\n", error);
return error;
}
error = ipj_set_value(iri_device, E_IPJ_KEY_REGION_CHANNEL_TABLE_SIZE, key_list.list_count);
if (error)
{
printf("ERROR: Set E_IPJ_KEY_REGION_CHANNEL_TABLE_SIZE FAILED - ERROR CODE: %d\n\n", error);
return error;
}
return E_IPJ_ERROR_SUCCESS;
}
The Indy SiP serial interface operates at 115,200 Baud unless configured otherwise, either by setting the key at run-time or using the Stored Settings functionality.
The ipj_modify_connection function allows the user to change the UART Baud rate.
The following code snippet changes serial interface to 57,600 Baud:
ipj_connection_params connection_params;
connection_params.serial.baudrate = E_IPJ_BAUD_RATE_BR57600;
error = ipj_modify_connection(&iri_device, E_IPJ_CONNECTION_TYPE_SERIAL, &connection_params);
Updates to the application portion of the firmware (also known as bootloads) are handled via the IRI Protocol using a specially prepared binary image.
There is a full example of how to update the Indy SiP application image in the IRI example IRI Loader Example.
Note
If the wrong image file is used for application update, the firmware onboard the SiP can be damaged, possibly preventing future updates. Care should be taken when updating to select the correct image.
The format of the image is as follows:
Chunk Size (4 bytes) |
---|
Erase Block (chunk_size) |
Load Block 1 |
Load Block 2 |
... |
Load Block n |
Example to update the device:
int chunk_size;
FILE* image_file_handle;
uint8_t file_buf[256];
/* Put the device in recovery mode */
error = ipj_reset(&iri_device, E_IPJ_RESET_TYPE_TO_BOOTLOADER);
if(error)
{
return error;
}
image_file_handle = fopen("<path_to_image>", "rb");
if(image_file_handle == NULL)
{
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)
{
return -1;
}
chunk_size = (file_buf[0] & 0xff) | (file_buf[1] << 8) |
(file_buf[2] << 16) | (file_buf[3] << 24);
if(chunk_size < 22 || chunk_size > 270)
{
return -1;
}
/* For each chunk in the image file, write it to the RS500 */
while(fread(file_buf, chunk_size, 1, image_file_handle) > 0)
{
error = ipj_flash_handle_loader_block(&iri_device, chunk_size, file_buf);
if (error)
{
return error;
}
}
/* Reset the device to resume operation */
error = ipj_reset(&iri_device, E_IPJ_RESET_TYPE_SOFT);
if(error)
{
printf("Unable to reset\n");
return error;
}
}
Note
This example demonstrates how to update the image from a host using POSIX functions like fread. Your method for reading/streaming the data may vary.
The Indy SiP error handling scheme consists of 2 components:
Error Keys are set any time an error occurs.
There are 3 user readable keys:
All of these keys can be read at any time and contain the error ID as well as up to 4 parameters detailing the specifics of the error (these parameters can be found in the error codes documentation). Additionally, First Error can be cleared by issuing an ipj_start command with a CLEAR_ERROR action.
Note
Only first error can be user cleared. Last and System errors can only be cleared by a power cycle.
ipj_key_list key_list;
memset(&key_list, 0, sizeof(key_list));
key_list.key = E_IPJ_KEY_FIRST_ERROR;
key_list.list_count = 5;
error = ipj_bulk_get(&iri_device, NULL, 0, &key_list, 1);
if (error)
{
printf("ERROR: IPJ_BULK_GET FAILED - ERROR CODE: %d\n\n", error);
return error;
}
error = ipj_start(&iri_device, E_IPJ_ACTION_CLEAR_ERROR);
if (error)
{
printf("ERROR: IPJ_START FAILED - ERROR CODE: %d\n\n", error);
return error;
}
Note
The device will automatically send a stop report once the error is clear, no other action is necessary. Attempting to send ipj_stop with a CLEAR_ERROR action will result in an error.
Error Reports are generated any time an error is detected and the host happens to be listening for incoming data (i.e. after a start inventory command has been issued). An error report contains the same information as an error key: Error ID + up to 4 parameters.
Note
Error reports will only be generated once per error to avoid the host from being flooded with reports should the same error occur multiple times in rapid succession.
The Indy SiP has 5 operating states:
There are two idle modes, Low Latency and Standard.
/* Sets the idle power mode to standard. This automatically takes effect */
ipj_set_value(&iri_device, E_IPJ_KEY_DEVICE_IDLE_POWER_MODE,
E_IPJ_IDLE_POWER_MODE_STANDARD);
/* Sets the idle power mode to low-latency. This automatically takes effect */
ipj_set_value(&iri_device, E_IPJ_KEY_DEVICE_IDLE_POWER_MODE,
E_IPJ_IDLE_POWER_MODE_LOW_LATENCY);
There are two low power modes, Standby and Sleep.
/* Put the device into standby mode */
error = ipj_start(&iri_device, E_IPJ_ACTION_STANDBY);
if (error)
{
printf("ERROR: STANDBY FAILED - ERROR CODE: %x\n\n", error);
return error;
}
printf("Attempting to wake RS500\n");
/* Set the receive timeout MS to a lower number (100ms) */
error = ipj_set_receive_timeout_ms(&iri_device, 100);
if (error)
{
printf("ERROR: SET RX TIMEOUT FAILED - ERROR CODE: %x\n\n", error);
return error;
}
/* Spin on IPJ_GET_VALUE (any key will do) until the device responds */
do
{
error = ipj_get_value(&iri_device, E_IPJ_KEY_APPLICATION_VERSION, &value);
}
while (error && retries--);
if (error)
{
printf("ERROR: Failed to wake RS500 device - ERROR CODE: %x\n\n", error);
return error;
}
/* At this point, the device is active and can perform RFID operations */
/* Now put the device in sleep mode */
error = ipj_start(&iri_device, E_IPJ_ACTION_SLEEP);
if (error)
{
printf("ERROR: STANDBY FAILED - ERROR CODE: %x\n\n", error);
return error;
}
/* The host application must toggle either the RESET or WKUP pins to
* bring the device out of sleep */
It is possible to use IRI to query the Indy SiP about the keys it contains.
The ipj_get_info function allows the user to detect the size of the data that the key contains (uint8/uint32/etc) as well as the number of banks (count), the number of values (length), and any read/write permissions that may be set on the key.
Please note that the information contained in the ipj_key_info struct refers to maximums, i.e. just because a key claims to have a length of 50 doesn’t necessarily mean that all 50 values are used.
The following code snippet gets the ipj_key_info for the E_IPJ_KEY_REGION_CHANNEL_TABLE key and prints out the value contained within for each possible value_index:
ipj_key_info keyinfo;
uint32_t i;
uint32_t result;
IPJ_CLEAR_STRUCT(keyinfo);
/* Get keyinfo for region channel table */
error = ipj_get_info(&iri_device, E_IPJ_KEY_REGION_CHANNEL_TABLE, &keyinfo);
if (error)
{
printf("Error getting channel table. Error: %x\n\n", error);
return error;
}
/* Loop through the channel table and print the contents */
for(i = 0; i < keyinfo.length; i++)
{
error = ipj_get(&iri_device, E_IPJ_KEY_REGION_CHANNEL_TABLE,
0, /* Bank_index of 0 since only one exists */
i, /* Value_index of i as we're looping through all */
&result);
if (error)
{
printf("Error getting channel value. Error: %x\n\n", error);
}
printf("Found Channel %d at value_index %d\n", result, i);
}