Turck Vilant Engine

The wonderful jumble of code that does magic things :)

Usage: ./reader [-d #] [-subVw]
  -d   Debuglevel (overrides config, syslog levels)
  -s   Debug output to stdout (overrides config)
  -u   Unbuffered debug output (try this if reader stops at start)
  -b   Daemonize to background
  -w   Write values to config file and exit
  -V   Version info

For example if you want to view logging only locally you can start with -s -d7

In typical setups libraries cannot be copied to system search paths so you much specify LD_LIBRARY_PATH accordingly. For example:

LD_LIBRARY_PATH=/cust /cust/reader

Configuration file path is hardcoded.

Known issues/limitations

Engine common tag data JSON

This is the Engine native tag data representation in JSON format. It is used by many internal functions and also exposed in STORE and MQTT. Empty/default fields are left out from the JSON.

{
  "EPC": "301588F858009D4473D8D797", // Raw EPC hex data as in the tag
  "URI": "urn:epc:id:sgtin:6438422.000629.19123459991", // Decoded URN format
  "userdata": "01234567FFFF", // Results of tag memory read operation. May be TID or User memory
  "direction": "OUT", // Results of direction detection if it was used
  "filterchain": 0, // Engine internal filterchain where this tag was
  "readcount": 1, // How many times the tag was read. Usually 1 since reads are individually processed
  "rssi": -39, // Received signal strength, in dBm
  "min_rssi": -39, // Minimum RSSI if reader supports reporting, in dBm
  "peakrssi": -3900, // Maximum RSSI if supported by hardware, in mBm
  "antenna": 1, // Antenna which read the tag
  "freq": 3, // Hardware dependent, frequency used for tag read (Note: Q180/Q300 report read slot)
  "phase": 3732, // Phase angle if supported by hardware
  "dopplerfreq": 7, // Doppler frequency if supported by hardware
  "readresult": 255, // Internal flag whether tag read operation was successful
  "writeresult": 255, // Internal flag whether tag write operation was successful
  "lockresult": 255, // Internal flag whether tag lock operation was successful
  "timestamp": "2019-09-23T07:40:05.520Z", // Timestamp when tag was seen
  "timestamp_first": "2019-09-23T07:40:05.520Z" //Timestamp when tag was first seen
}

Basic logic

Engine has one customer logic which is suitable for generic operations. It is called “Basic”. In order to enable this you need to specify CUSTOMER=38 in reader.ini file.

Basic logic sends all tags using VVM Asset interface (REST, HTTP POST JSON). Interface specification can be found in Turck Vilant Visibility Manager documentation.

For example, simple data is sent as

{
  "assetOperations": [
    {
      "currentLocation": "TRANSIT",
      "timestamp": "2018-09-19T12:03:21.179Z",
      "id": {
        "primary": "341588F50C470DE4DFC59922"
      },
      "operation": "MOVE",
      "deviceId": "Test1"
    }
  ]
}

If configured with BASIC_SEND_ALL_FIELDS=1 the following output is produced. Note that empty/null tag data fields are not sent.

{ "assetOperations" : [ {
    "currentLocation" : "TRANSIT",
    "timestamp" : "2018-09-19T12:03:54.635Z",
    "id" : {
      "primary" : "341588F50C470DE4DFC59922"
    },
    "operation" : "MOVE",
    "deviceId" : "Test1",
    "custom" : {
      // Contents according to Engine common tag data format
      "antenna" : 1,
      "customdata" : "xxx",
      "direction" : "OUT",
      "dopplerfreq" : 4567,
      "EPC" : "341588F50C6A94D74F4318BA",
      "lockresult" : 3,
      "min_rssi" : 206
      "peakrssi" : 1212,
      "readcount" : 1,
      "readresult" : 1,
      "rssi" : -50,
      "timestamp" : "2017-06-25T23:10:25.123Z",
      "timestamp_first" : "2017-06-25T23:10:25.123Z",
      "userdata" : "01234567FFFF",
      "writeresult" : 2,
    }
}]}

Basic logic HTTP requests

GET /start

GET /start/

GET /stop

Basic logic configuration items

SERVER_URL=

The address where tag reads will be sent, typically VVM. This must include any REST service address so typically you need to add /rest/assets/operations to VVM base URL.

If you need authentication, see section “Sending HTTP requests”.

BASIC_FILTERMAP=

Per antenna tagfilter mapping (antenna:filterchain, comma separated). This config can be used to define logical readers with different filters For example 1:1,2:1,3:1,4:1. If not defined for some antenna then default TAGFILTER chain is used

BASIC_OPERATION=MOVE

Operation name (e.g. CREATE/MOVE/INACTIVATE)

BASIC_SEND_RSSI=0

Whether to send RSSI in custom field

BASIC_SEND_ALL_FIELDS=0

Whether to send all tag data fields to server Value 1 sends fields under custom object (requires custom VVM, not supported on default VVM 8) Value 2 sends fields in additionalInfo field (works with default VVM 8)

ANTENNA_ACTIONS=1:Warehouse,2:Warehouse,3:TRANSIT,4:TRANSIT

or

ANTENNA_ACTIONS=1:LocA,2:Bin1@Loc1@Site1,3:Bin2@Loc1@Site1,4:Loc3@Site1

Mapping of antennas to locations. This is used as currentLocation when sending data and these are also used for direction detection zones. These locations must exist in VVM or else the sending will fail. It’s possible to also define with 3-level location hierarchy, i.e.  NOTE. 3-level location values must follow order @@ or @ or @@

BASIC_TAGS_TO_CSVFILE=0

If set then create tags-yyyy-mm-dd.csv file to SPOOL_PATH. Contains all read data fields: timestamp, timestamp_first, direction/action, readcount, rssi, min_rssi, antenna, freq, PC, epc, userdata, dopplerfreq, peakrssi, readresult, writeresult, lockresult, customdata

BASIC_TRIGGER_PRE_DELAY=0 BASIC_TRIGGER_POST_DELAY=0

If GPI_TRIGGER is on these configs are used to add extra delay before reading starts and before the reading is stopped. Both values are in milliseconds.

OPERATING_MODE=2

When operating mode=2 this reader acts as a slave reader. Only tagfilter processing is done and then all tags are sent to master engine. This slave will not send any tags to VVM.

How to configure multiple readers in master - slave configuration.

SLAVE CONFIGURATION:

SERVER_URL=http://admin:engine@MASTER_READER_IP:8080/inject
OPERATING_MODE=2

MASTER CONFIGURATION as normally in basic operating mode. Note that tag reads from slave readers to master will have same antenna as they have been reading (eg. slave antenna 1 will be mapped to master reader antenna 1 in BASIC_FILTERMAP and ANTENNA_ACTIONS)

Basic logic for shipment creation

‘Basic shipment’, a customer logic that creates shipments on vvm. it uses CUSTOMER=17X (to be changed when released) in reader.ini file.

Basic shipment uses two filterchains. Chain 0 is for asset tags and chain 1 is for shipment tags. Shipment tags are distinguished by parameter

VILANT_SHIPMENT_SHIPMENT_TAGHEADER

which is the case sensitive prefix in upper case of epc in hex format that a shipment tag should be encoded with.

Basic shipment tag reading control

There are 3 modes for start reading tags and 6 modes for stop reading tags, of which not all are combinable.

VILANT_SHIPMENT_STARTMODE > 1 = On ‘Shipment’ prefixed tag (VILANT_SHIPMENT_SHIPMENT_TAGHEADER), > 2 = On gpi input (GPI_TRIGGER), > 3 = On any asset tag

VILANT_SHIPMENT_STOPMODE > 1 = Timeout from last shipment tag, > 2 = Timeout from last start, > 3 = Timeout from last asset tag, > 4 = Timeout from last new tag, > 5 = Timeout from start gpi trigger, > 6 = End on gpi trigger (VILANT_SHIPMENT_STOP_TRIGGER needed)

In stopmode, timeouts from a tag seen cannot be used if startmode is a gpi trigger.

Other parameters used by basic shipment

READ_TIMEOUT > Tells the time to wait for read period to expire, after start is triggered. After READ_TIMEOUT has expired shipment is created at tvvm.

GPI_TRIGGER > Tells the gpi pin to use for start reading if startmode is 2.

VILANT_SHIPMENT_STOP_TRIGGER > Tells the gpi pin to use for stop reading if stopmode is 6.

MY_NAME > ‘sourceLocation’ in shipment creation rest message

SITE > ‘sourceLocationSite’ in shipment creation rest message

VILANT_SHIPMENT_TARGETLOCATION > ‘targetLocation’ in shipment creation rest message

VILANT_SHIPMENT_TARGETBIN > ‘targetLocationBin’ in shipment creation rest message

VILANT_SHIPMENT_TARGETSITE > ‘targetLocationSite’ in shipment creation rest message

Debus passthru mode (Turck Q180/Q300 readers)

Engine software on Turck Q180/Q300 readers have support for a special mode called Debus passhtru mode. In this mode, a debus client can connect to reader using TCP connection. In this case, engine will act as a passhtru proxy forwarding communication between the reader and the client. Connections are made with TCP sockets using the port defined with RFID.DEBUS_PASSHTRU_PORT config parameter.

The mode can be enabled or disabled with a config RFID.DEBUS_PASSHTRU_ENABLED.

Binary arithmetic for antennas

RFID_ENABLED_ANTENNAS config parameter is a bitmask of enabled antennas so one number tells state for all of the antennas.

Lowest bit means antenna 1, second lowest means antenna 2 and so on.

In Q180/Q300 the antennas 1-4 are the external antenna ports. Internal antenna is ports 5-8 with different polarizations: 5 RHCP, 6 LHCP, 7 horizontal, 8 vertical.

Some examples:

Config Antenna numbers
1 1
2 2
3 1, 2
15 1, 2, 3, 4
16 5
240 5, 6, 7, 8
255 1, 2, 3, 4, 5, 6, 7, 8

HTTP server usage

Engine contains internal HTTP server that by default responds in port 8080 and 8081 (ssl). Both are configurable (HTTPD_PORT / HTTPSD_PORT).

In Impinj R700 readers the default ports are 8088 and 8089 (ssl) due to Impinj reserving 8080 for its internal use.

Accessing any url in above ports, except for /rfid/store, requires basic authentication. There is one, hard-coded, user, ‘admin’ and a configurable password, with default value ‘engine’.

GET /gpi/<port>/<state>

Generate internal input_changed event which will trigger in many customer logics

GET /gpo/<port>/<state>

Command reader to change GPO port state accordingly. Note that this doesn’t respect GPO_SINK, e.g. for typical Impinj setup 0 is on

GET /gpo/<device>/<port>/<param>

Command reader to change GPO port state accordingly on a specific IO device. Indexing for IO devices is described in IO Devices section.

Param can be either direction (I or O) or GPO state for pin (1 or 0). Note that this doesn’t respect GPO_SINK, e.g. for typical Impinj setup 0 is on

POST /write/

NOTE: Using write interface will interrupt any operations that customer logic makes. Restoring custom logic operation, engine may need to be restarted.

The write interface have two use cases:

1) EPC writing

{
  "newEpc": "310000000000000000000002",
  // 'oldEpc' is optional, if not given, then reader will target first tag it sees. 
  "oldEpc": "310000000000000000000001", 
}

2) Data writing

{
  "filterMemoryBank": 1,
  "filterAddress": 32,  
  "filterLengthBits": 8,
  "filterData": "31",
  "targetMemoryBank": 3,
  "targetAddress": 0,
  "newData": "ABCD"
}

Response

Example success response:

{
  "success": true,
  "message": "Write OK. Please note that custom logic has been interrupted."
}

Example failure response:

{
  "success": false,
  "message": "Write failed, no tags seen. Please note that custom logic has been interrupted."
}

GET /config/

GET /kill/

POST /inject

Allows you to inject tag reads as if they come from reader normally. Note: Tag is injected to tagfilter so rdr.read() doesn’t work

Use POST with JSON data in Engine common tag data format as described above. Supports both single tag data and array of tags in the message. If timestamp is specified as now it will be replaced with current time when processing

{
  "EPC": "341588F50C6A94D74F4318BA",
  "timestamp":"now",
  "antenna": 3
}

// or

{
  "tags":[
    {
      "readcount":1,
      "EPC":"341588F50C6A94D74F4318BA",
      "timestamp":"now"
    },
    { ... }
  ]
}

Extra fields can be left out, they default to zero. Note that customdata is not free()’d by default and specifying it will typically cause memory leak.

GET /rfid/status

Returns status of antennas and GPIO ports. Antenna state reporting is reader dependent feature and is not reliable. Antenna and GPIO names come from Engine configs.

{
  "antenna": [
    {
      "port": 1,
      "state": 1,
      "name": "IN"
    },
    {
      "port": 2,
      "state": 0,
      "name": "OUT"
    }
  ],
  "gpi": [
    {
      "port": 1,
      "state": 0,
      "name": "Trigger"
    }
  ],
  "gpo": [
    {
      "port": 1,
      "state": 0,
      "name": "Green light"
    }
  ]
}

GET & POST /rfid/config

Generic reader configuration interface. This can be used to change any parameter similarly as in reader.ini file. GET method returns list of all parameters and POSTing same data changes them (only name and value used in POST). New parameters are saved to reader.ini and reader is reconfigured or restarted to apply new configs.

NOTE: When Provisioning (DM) is used it will overwrite these configs after a while.

{
  "configs": [
    {
      "name": "MY_NAME",
      "value": "FORKLIFT",
      "type": "string",
      "description": "Reader name/Location ID"
    },
    {
      "name": "RFID_POWER",
      "value": "1200",
      "type": "string",
      "description": "Transmit power. Either single number in mBm or for each antenna separated with ,"
    }
  ]
}

GET /rfid/store

Returns list of tags currently in STORE filter. This can be used for querying seen tags from Engine. Contents are in Engine common tag data format as described above.

{
   "tags":[
      {
         "EPC":"301588F858009D4473D8D797",
         "URI":"urn:epc:id:sgtin:6438422.000629.19123459991",
         "filterchain":0,
         "readcount":1,
         "rssi":-39,
         "min_rssi":-39,
         "antenna":1,
         "freq":3,
         "phase":3732,
         "dopplerfreq":7,
         "peakrssi":-3900,
         "readresult":255,
         "writeresult":255,
         "lockresult":255,
         "timestamp":"2019-09-23T07:40:05.520Z",
         "timestamp_first":"2019-09-23T07:40:05.520Z"
      }
      ...
   ]
}

MQTT

Engine provides some standard functionality over MQTT that can be further enhanced in customized logics.

MQTT_SERVER is the address where to connect in URL format. For example mqtt://server or mqtts://server:8886. For authentication there is MQTT_USERNAME and MQTT_PASSWORD. If left empty then unauthenticated connection is made.

Topics

<id> in topics is replaced with the ID of the reader. ID is same what is used for license activation

/tvs/<id>/status

Periodically updated with the latest status of the reader and LWT is used to provide status: offline on disconnect.

Example contents:

{
  "name": "RFID_Gate_1",
  "id": "01:02:03:0a:0b:0c",
  "status": "online",
  "application": "Vilant Engine/Turck (38)",
  "version": "2.3.45.0f78ab8",
  "last_updated": "2021-11-27T09:00:00Z",
  "last_tag_read": "2021-11-27T08:55:53Z",
  "components": {
    "DEVICE": "OK",
    "Antenna1": "OK",
    "Antenna2": "Error"
  }
}

/tvs/<id>/reads

Preferred topic for tag reads. It is actually controlled by adding MQTT tagfilter into wanted filterchain with the actual topic. Format is the Engine common tag data format as described above.

/tvs/<id>/gpio

GPIO events for detected inputs and set outputs will be sent here.

{
  "type": "output", // input or output
  "dev": 0, // IO device number. 0 is the device itself
  "pin": 1, // IO pin. Dependss on the hardware
  "state": 1 // 0 OFF, 1 ON
}

/tvs/<id>/config

Receives Engine configurations when requested with cmd/config/get topic, when configs are mass changed, on startup and on few other occasions.

Configurations are as in following example:

{
  "configs": [
    {
      "name": "GENERAL.MY_NAME",
      "shortname": "MY_NAME",
      "value": "RFID_Gate_1",
      "type": "string",
      "description": "Reader name/Location ID"
    },
    {
      "name": "CUSTOM.OPERATING_MODE",
      "shortname": "OPERATING_MODE",
      "value": 4,
      "type": "integer",
      "description": "Operating mode (custom logic dependent)"
    }
  ]
}

/tvs/<id>/cmd/config/get

Will results in configurations being sent to config-topic above.

/tvs/<id>/cmd/config/set

Setting configs can be done with the same data as received from config-topic. If both name and shortname are specified shortname takes precedence.

Note: Reader will immediately take new configs into use and might reboot if required.

/tvs/<id>/cmd/rfid/start

Will start RFID reading. Note: This overrides any functionality in customized logics.

/tvs/<id>/cmd/rfid/stop

Will stop RFID reading. Note: This overrides any functionality in customized logics.

/tvs/<id>/cmd/gpio

Will control GPIO ports. Contents same as in /tvs/<id>/gpio topic. Specifying type: input will generate fake input events.

Tagfilters

All tag reads are piped through tagfilter chain where every filter has chance to inspect, modify and drop/forward tag reads. Same filter can be used multiple times with different configs. Some filter configs can create weird and nonworking results.

Tagfilter configuration is somewhat similar to other configs in reader.ini. There is TAGFILTER-parameter which contains multiple lines. For multiline configs Engine uses heredoc-style format so all between <<END and END are considered to be part of the config parameter.

Inside TAGFILTER parameter you can have multiple tagfilters, each one on its own line. Filters can also be specified multiple times and in any order. (Although having MIN_READCOUNT after DUPLICATE will not produce any reasonable results.)

For example

TAGFILTER=<<END
RSSI=-70
MIN_READCOUNT=10,30000ms
DUPLICATE=60000
LIGHT=1,1000ms,1
END

Means throw away tags with <-70 RSSI, then require at least 10 reads during 30 seconds, filter out duplicates from the rest and blink GPO 1 once on first tag read which goes through duplicate filter.

Tag read timestamp is used for elapsed time calculations

When filterchain contains several filters that store tag reads before passing them on to next filter, the lifetime of tag read must be considered. Each filter examines the read time of the tag. For example in

DIRECTION=5000,10000,MODE1
STORE=3000

no tags will be stored, since their age is already 5000 ms when entering store. Correct filter settings would be

DIRECTION=5000,10000,MODE1
STORE=8000

To store tags for additional 3000 ms in STORE filter.

Antenna

ANTENNA=ant[,ant]
e.g. ANTENNA=3,4

Accepts reads only from given antennas. Discard others

Clone

CLONE=chain
e.g. CLONE=3

Makes a copy of the tag and sends it to specified filterchain

Direction detection

DIRECTION=state,flush,MODE#[,readcount][,USERMEM][,NOEXTRA][,DEBUG]
e.g. DIRECTION=2000,60000,MODE1

Doppler limit

DOPPLER=limit Hz[,limit ...] [,timewindow ms] [,ANTENNA] [,TID] [,NOT] [,LOG]
e.g. DOPPLER=10Hz
e.g. DOPPLER=10Hz,1000ms
e.g. DOPPLER=10Hz,5Hz,5Hz,ANTENNA

Tagdumper filter

DUMPER=filename [,DECODE_6BIT] [,DECODE_VDA5500]
DUMPER=TCP:12345
e.g. DUMPER=/tmp/tags-%Y%m%d.csv

Duplicate filter

DUPLICATE=timewindow[,timewindow...] [,ANTENNA] [,FIRST] [,TID] [,NOLOG] [,COUNT]
e.g. DUPLICATE=60000
e.g. DUPLICATE=5000,FIRST
  Report reads for tags in view every 5 seconds
  (i.e. “Session 1” readcounts even with dual target inventory)
e.g. DUPLICATE=30000,20000,30000,20000,ANTENNA
  Filter tags uniquely on all antennas with 30/20/30/20s timewindows

EPC filter

EPC_HEX=string [,NOT]
e.g. EPC_HEX=1234            i.e. EPC should contain 1234, at any place in the EPC
e.g. EPC_HEX=^34             i.e. EPC should start with 34
e.g. EPC_HEX=000000,NOT      i.e. EPC should not contain 000000
e.g. EPC_HEX=(333|444|555)   i.e. EPC should contain 333 or 444 or 555
e.g. EPC_HEX=^(333|444)      i.e. EPC should start with 333 or 444
e.g. EPC_HEX=^341(333|444)   i.e. EPC should start with 341 which is followed by 333 or 444
e.g. EPC_HEX=(333|444),NOT   i.e. EPC should not contain 333 or 444

Each tag is validated according to the matching EPC, case insensitive. String itself is executed as (posix) regexp so advanced matching features can be used. A nice tuto on regex is http://regexone.com. NOT keyword defines that string must not match

EPC length filter

EPC_LEN=value
e.g. EPC_LEN=96

The tag should have the correct EPC length, in bits, to pass this filter

EPC mangle filter

EPC_MANGLE=mask,replacement
e.g. EPC_MANGLE=00E0,0000      i.e. Change filter to 0
e.g. EPC_MANGLE=FF,30          i.e. Change all tags to be SGTIN-96

This filter modifies tag data during read so that for example further filters will see different tags as same.

LIGHT

LIGHT=gpo,duration,blink
e.g. LIGHT=1,20ms,3
  Will turn ON GPO 1 3 times for 20 milliseconds

All parameters are mandatory.

Log tag reads

LOG=log_header
e.g. LOG=After Doppler filter
  Will display log line such as:
  LOG After Doppler filter EPC: 123456789012345678901234 TID: (null) Ant: 1 RSSI: -55.5dBm Doppler: 0.9Hz

Search keyword: logging

Minimum readcount

MIN_READCOUNT=readcount, timewindow ms [,readcount, timewindow ms] [,ANTENNA] [,TID]
e.g. MIN_READCOUNT=10,30000ms
  Require at least 10 reads within 30 seconds.
e.g. MIN_READCOUNT=10,5,10,3,10000ms,10000ms,10000ms,10000ms,ANTENNA
  Per antenna readcounts. Require 10 tag events from first antenna, 5 from second etc.

Note: Specifying multiple readcounts/timewindows without ANTENNA keyword will result in strange behavior (limit checked by last seen antenna). You must also have same amount of readcounts and timewindows.

MQTT

MQTT=topic
e.g. MQTT=/tvs/<ID>/reads

Pushes all seen tags to MQTT with given topic. The <ID> in topic is replaced with reader ID. Uses Engine common tag data format.

Remap antennas

REMAP_ANTENNA=1:2,2:3,3:10,4:11

Changes antenna to new defined value. Accepts pairs of old:new antenna. This is useful when sending reads to separate engine so it can differentiate incoming reads from local reads.

Note: Maximum antenna number is 32 (hardcoded, TF_MAX_ANTENNAS)

Require usermem

REQUIRE_USERMEM

Only lets tags pass if they contain some read user memory

RSSI

RSSI=limit[,limit...] [,NOLOG] [,MAX]
e.g. RSSI=-90,NOLOG
e.g. RSSI=-50,-60,-70,-50

Requires at least given RSSI value for tags. First value used for unspecified antennas. NOLOG suppresses “tag dropped” messages. MAX reverses comparison and drops tags with too high RSSI.

RSSI_CALC filter

To calculate peak and average RSSI during time window.
Based on DUPLICATE filter, but tags sent when they are getting old, not immediately.
RSSI_CALC=timewindow[,timewindow...] [,ANTENNA] [,FIRST] [,TID] [,NOLOG]
e.g. RSSI_CALC=60000
e.g. RSSI_CALC=5000,FIRST
  Report reads for tags in view every 5 seconds
  (i.e. “Session 1” readcounts even with dual target inventory)
e.g. RSSI_CALC=30000,20000,30000,20000,ANTENNA
  Filter tags uniquely on all antennas with 30/20/30/20s timewindows

RSSI_FLOAT filter

RSSI_FLOAT filter updates accepted RSSI levels based on seen values. This filter dynamically increases RSSI level to exclude weaker reads.

RSSI_FLOAT=lower_threshold,flushtimeout,start_limits... [,ANTENNA] [,NOLOG] 
e.g. RSSI_FLOAT=2,50,-50,-51
e.g. RSSI_FLOAT=5,50,-50,-51,NOLOG
e.g. RSSI_FLOAT=3,50,-60,-70,-50,ANTENNA,NOLOG

Seen/lost filter

SEEN=timewindow
e.g. SEEN=10000 [,ANTENNA]
  Report tag "seen" event immediately when new tag is seen
  After 10 seconds without reads report "lost" event

Store tag reads

STORE=duration [,KEEP] [,COUNT] [,DEBUG]
e.g. STORE=10000
  Will store tag reads for 10s
e.g. STORE=10,COUNT
  Store 10 latest reads
e.g. STORE=10000,KEEP
  Store for 10s and keep in internal buffers for next fetch
e.g. STORE=10000,DEBUG
  Will additionally log more info

DM tag analytics

Collect tag reads per antenna and send it to tag analytics endpoint (usually on DM). Works only when PROVISIONING_URL or TAG_ANALYTICS_URL is set. Place this handler so that you only get relevant tag reads, e.g. it should be first handler for all reads, or last one for sending only processed (passed all handlers) events to DM.

TAG_ANALYTICS=mode [,send interval s] [,LOG]
e.g. TAG_ANALYTICS=RAW,120s
  Will gather tag statistics and send it every 120 seconds with analyticsDataType = RAW
e.g. TAG_ANALYTICS=PROCESSED
  Will gather tag statistics and send it every 60 seconds with analyticsDataType = PROCESSED

Tag movement filter

Accept tags if there are enough reads within timewindow on same antenna and calculated deviations for reads are within configured thresholds for either phase angle, RSSI or both.

TAG_MOVEMENT=readcount,timewindow ms [,PHASE,low,high] [,RSSI,low,high] [,NOLOG]
e.g. TAG_MOVEMENT=10,3000ms,PHASE,0,20,RSSI,0,1
  Allow any tag which was read at least 10 times during last 3 seconds on the same antenna and
  its phase deviation is within [0..20] and RSSI deviation is within [0..1]

Note: Config must contain at least one of PHASE or RSSI keywords. Both thresholds must be supplied. Keeping timewindow too wide may slow down calculation, series limit is 1024 data points per EPC per antenna.

Forklift Move

Read assets on the forklift forks triggered by reading location tags. When specifed amount of different locations(location tags) are passed within the configured time window, the reading is triggered and assets reading events are sent to the VVM. Locations can be downloaded from VVM or the function can be runned as stand-alone. Assets and location tags can have separate tag filters.

Customer logic 175

# Asset tag filter
TAGFILTER=<<END
DUPLICATE=60000
STORE=10000
END
# STORE timeout is the before-trigger read length

# How long to read for tags after trigger
READ_TIMEOUT=1000

# Location tag filter
TAGFILTER1=<<END
ANTENNA=1
DUPLICATE=10000
END

#Note for standalone mode:
# SERVER_URL must be empty
# Add CLONE=1 to TAGFILTER
# Add EPC_HEX to TAGFILTER1 which will match only location tags
# Add inverse EPC_HEX (i.e. with "NOT") to TAGFILTER to filter out location tags

#How often to poll VVM for locations
LOCATION_SYNC_INTERVAL=300

#Minimum amount of different location tag reads to trigger asset reading
LOCATION_TRIGGER_TAG_COUNT=2

#Location trigger tags must be seen within this time, sliding window
LOCATION_TRIGGER_TIME_WINDOW=1000

Basic Modbus device logic

Customer logic 13

This operating logic is used for reading tags and communicating events with modbus slave devices, such as PLCs. Reading is controlled with modbus commands. Supported reading modes are continuous reading or triggered reading with defined time configurable time periods. In this mode, the engine reads commands from the holding registers and writes data into input registers.

How to setup

Configure modbus slave endpoints. Default port is 502 but different ports can be used by defining port in settings

# PLC Gateway IP address / COMMUNICATIONS.GATEWAY_IP
GATEWAY_IP=

# COMMUNICATIONS.GATEWAY_PORT
#GATEWAY_PORT=502

Register setup can be adjusted with following parameters:

#Modbus read start address / CUSTOM.DC_READ_ADDRESS
DC_READ_ADDRESS=0

#Modbus write start address / CUSTOM.DC_WRITE_ADDRESS
DC_WRITE_ADDRESS=0

#1=Read modbus input registers, 0=Read modbus holding registers / CUSTOM.DC_READ_METHOD
DC_READ_METHOD=1

Modbus logic can send asset operation to vvm, provided that SERVER_URL is set and additionally can send variable length data in assetExtrainfo1-field, if operating mode is 1. Also byte endianess of extrainfo modbus registers (words) can be controlled

#0 = Normal operation, 
#1 = Extended operation, where modbus register in index 3 (#4th register) describes how many 
#registers, starting from index 4 (#5th register) are used for extraInfo to be sent to vvm in asset operation / CUSTOM.OPERATING_MODE
OPERATING_MODE = 0

#0 = Host byte order (does ntohs on each extrainfo register), 1 = Network byte order (does not do ntohs on each extrainfo register) / CUSTOM.DC_EXTRAINFO_BYTEORDER 
DC_EXTRAINFO_BYTEORDER = 0

Tagfilterchain should include STORE to capture tag reads from the desired moment:

# Default filter (if no filtermap)
TAGFILTER=<<END
DUPLICATE=60000
STORE=60000
END

Modbus communication protocol is defined in another document. Please request communication protocol documentation from your TVS contact.

Sending HTTP requests (Message queue operation)

Standard sending mechanism uses message queue.

Authentication

HTTP Basic authentication credentials can be defined two ways:

  1. Define HTTP_USERNAME and HTTP_PASSWORD fields under COMMUNICATIONS in Engine configuration. If either username or password field is empty, then basic authentication is not used and request is sent without authentication. Both of the fields need to be defined to use BASIC authentication.
  2. Define HTTP Basic username and password in URL. For instance, https://username:password@example-server.com/path/to/endpoint.

Message queue

The status for the queue is shown in Engine Web UI in page “Send queue”. This allows monitoring what is being sent, how many times requests have failed. Queue can also be cleared from the Web UI.

Configuring message queue

The following configuration parameters are found under COMMUNICATIONS tab.

SENDER_MAX_TRIES controls how many times message is tried to be sent. After exceeding limit, the message is dropped from sender.

STRICT_ORDERING controls if messages are sent in same order as they have been added to queue. Note! Failing messages will block sending next messages.

SENDER_INITIAL_DELAY defines the first resending delay. Resend delay gets doubled after each failed attempt.

IO Devices

Engine has generic support for extra GPIO devices. Actual usage depends on the custom logic but the devices itself are configured in common Engine configuration. Internally device 0 means the reader itself and first device in IO_DEVICES is device 1.

IO_DEVICES=10.6.0.95=TBEN-L5-16DXP,10.6.0.100=TBEN-S2-8DXP

Config parameter contains comma separated list of GPIO-devices. Each device entry contains IP=TYPE config.

Supported types:

Engine IO pins are same as in the device Modbus interface. M12 connector pin 4 is the first IO and pin 2 is the second. For example Engine pin 0 is C0 pin 4, Engine pin 1 is C0 pin 2, Engine pin 2 is C1 pin 4 and so on. More details can be seen in the device manual.

TBEN Vaux pin control is not supported at the moment.

If you want to set initial state of outputs you can use the following config:

IO_INITIAL_OUTPUT=0=000011

This means for device 0 the outputs 0-3 are turned off and 4-5 are turned on. This corresponds to Q180/Q300 having Vaux pins on and other DXP pins off. In this scenario sensors get their power from Vaux and sensor outputs can be seen in input pins.

If you connect traffic lights to reader then you probably want to turn everything off, e.g. IO_INITIAL_OUTPUT=0=000000

Q180/300 IO

Q180 and Q300 have two DXP ports for IO. They are similar to DXP ports in other Turck devices.

NOTE: If PoE power input is used then output will work only from DXP aux pins. Other output pins will toggle just fine but no actual voltage is output. Inputs work just fine.

Pin mapping

Engine Connector M12 Pin Description
0 DXP 0/1 4 DXP 0
1 DXP 0/1 2 DXP 1
2 DXP 2/3 4 DXP 2
3 DXP 2/3 2 DXP 3
4 DXP 0/1 1 Vaux
5 DXP 2/3 1 Vaux

Physical connector DXP 0/1 is mapped to Engine pin numbers 0, 1 and 4

Similarly for DXP 2/3 is mapped to Engine pins 2, 3 and 5. Turck documentation DXP Channels match Engine pin numbers. Vaux pins are added after DXP pins.

Note that input pin 0 might mean “not used” in many custom logics. For example GPI_TRIGGER=0 means triggering is not used

Since DXP pins are both input and output the inputs will “see” output as well. Currently output turning on is masked but when output is turned off it will generate input low event.

DXP ports work simultaneously as input and output ports whereas Vaux ports are output-only.

Engine will also log “DXP chan %d Aux power overcurrent” diagnostic messages. In case aux power is turned off this event is generated by hardware and can be ignored.

Impinj R700 IO

Impinj R700 has documented ports 0-based whereas we have decided to use 1-based indexing in Engine and in Client.

Engine Impinj
1 IN 0
2 IN 1
1 OUT 0
2 OUT 1
3 OUT 2

GPIO websocket

Some GPIO events can be received and sent over a websocket. Websocket path is /gpio (e.g. ws://reader:8080/gpio)

Example output messages:

{ "type":"output", "dev":0, "pin":4, "state":0, "timestamp":"2021-01-13T14:35:46.484Z" }
{ "type":"output", "dev":0, "pin":5, "state":1, "timestamp":"2021-01-13T14:36:51.170Z" }
{ "type":"input", "dev":0, "pin":2, "state":1, "timestamp":"2021-01-13T14:36:56.760Z" }
{ "type":"input", "dev":0, "pin":2, "state":0, "timestamp":"2021-01-13T14:36:57.815Z" }
{ "type":"input", "dev":0, "pin":2, "state":1, "timestamp":"2021-01-13T14:36:59.862Z" }
{ "type":"input", "dev":0, "pin":2, "state":0, "timestamp":"2021-01-13T14:37:00.227Z" }

Sending similarly formatted messages (without timestamp) will cause outputs to be set and fake input messages generated.

Dev refers to IO_DEVICE number. 0 means IO ports integrated to the device.

Basic logic config parameters

Below is a listing of config parameters in Engine with Basic logic. Most of the configs are shared with other customer logics

#Reader configuration file
#Vilant Basic: Constant reading.
# Validated tags are sent to VVM: their currentLocation is set according to the ANTENNA_ACTIONS

#Customer logic ID (38 is Basic (standard logic))
CUSTOMER = 38

#Reader name
MY_NAME = VilantEngineBasic

#Reader site in VVM
SITE = Espoo

#===================
#=== TAG FILTER  ===
#===================

# TAG FILTER Possible values:
# DUPLICATE
# RSSI
# EPC_HEX
# DOPPLER
# MIN_READCOUNT
# DIRECTION
# REQUIRE_USERMEM
# See README for details.

# Default filter (if no filtermap)
TAGFILTER=<<END
RSSI=-50
DUPLICATE=60000
END

# Per antenna tagfilter mapping (antenna:filterchain)
BASIC_FILTERMAP=1:1,2:1,3:2,4:2

TAGFILTER1=<<END
RSSI=-50
DUPLICATE=60000
END

TAGFILTER2=<<END
DOPPLER=0.5Hz
DUPLICATE=10000
END

#Describe VVM currentLocation for antennas, comma separated i.e. 1:IN,2:IN,3:OUT,4:OUT
#It's possible to also define with 3-level location hierarchy, i.e. 1:LocA,2:Bin1@Loc1@Site1,3:Bin2@Loc1@Site1,4:Loc3@Site1
#NOTE. 3-level location values must follow order <bin>@<loc>@<site> or <loc>@<site> or <bin>@<location>@
ANTENNA_ACTIONS = 1:Vilant,2:Vilant,3:TRANSIT,4:TRANSIT

#VVM operation name
BASIC_OPERATION = MOVE

#Whether to send RSSI value as custom parameter
BASIC_SEND_RSSI = 1

#Whether to send all tag data fields as custom parameters (1=send in custom fields, 2=send as additionalInfo)
BASIC_SEND_ALL_FIELDS = 0

#===================
#=== CONNECTION  ===
#===================
#Where data is sent
SERVER_URL=http://demo.vilant.com/visibilitymanager/rest/assets/operations/
HTTP_USERNAME=username
HTTP_PASSWORD=password
PROVISIONING_URL = https://secure.vilant.com/dm/rest/provisioning
PROVISIONING_INTERVAL = 60
PROVISIONING_DEBUG = 0
ALIVEPING_URL = http://secure.vilant.com/I-am-alive/
ALIVE_INTERVAL = 600

#Path to local storage. This is the place where data which was not sent to VVM is saved
# For Impinj without USB: /mnt/ufs/asset
# For Impinj with USB: /mnt/usbfs/usbsda1/asset
# For other readers, check specifications
SPOOL_PATH = /mnt/ufs/asset

#HTTP server port. If 0 then http server is not started
# See README for details
HTTPD_PORT = 8080


#=====================
#=== RFID settings ===
#=====================

#Reader type: LLRP, KBRP, FAKE
RFID_DRIVER = LLRP
#Reader address (ip, hostname, serial port)
RFID_HOST = localhost
# For LLRP: port is 5084
RFID_PORT = 5084

#Transmit power (max 3000 = 30dBm)
# This can be specified per antenna. ALL antennas must be defined if per antenna values are used
RFID_POWER = 2000
#Or RFID_POWER = 2000,1500,3000,2500
#Gen2 session
RFID_SESSION = 2
#Gen2 tag population size (2^q)
RFID_POPULATION = 64

#Read user memory from tag (1=User, 2=TID, 4=XPC)
RFID_MEMORY_READ = 0
#How many words to read from tag memory
RFID_MEMORY_READ_LEN = 0

#Gen2 reader mode
# This differs per reader (see reader specs). When engine starts, the possible values is also printed in logs
RFID_READER_MODE = 5

#Which antenna(s) to use for reading (bitmask, 0=all, 12=4th and 3rd antennas, etc.)
RFID_ENABLED_ANTENNAS = 0

#Gen2 tag (radio)filter length in bits (0 disables the radio filter)
RFID_FILTER_LEN = 0
#Gen2 tag radio filter memory bank (1=EPC, 2=TID, 3=User)
RFID_FILTER_MB = 1
#Gen2 tag filter match position, bits
RFID_FILTER_START_BIT = 16
#Gen2 tag filter mask, hex bytes
RFID_FILTER_MASK =
#LLRP Receive sensitivity
RFID_RECEIVER_SENSITIVITY = 0

#Impinj low duty-cycle empty field timeout (ms), 0 to disable
IMPINJ_LOWDUTY_TIMEOUT = 0
#Impinj low duty-cycle ping interval (ms)
IMPINJ_LOWDUTY_PING = 500
#Impinj inventory search mode (0=reader selects, 1=single, 2=dual, 3=single with suppression)
IMPINJ_INVENTORY = 2

#Thingmagic target strategy (0=A, 1=B, 2=AB, 3=BA)
TM_TARGET = 2
#Thingmagic fast search mode enabled
TM_FASTSEARCH = 0
#Thingmagic antenna detection
TM_ANTENNADETECTION = 0

#======================
#=== DEBUG settings ===
#======================

#Logging output: syslog, stdout, /path/to/file, url
#Also /path/reader_%Y-%m-%d.log for auto rotation
# https://secure.vilant.com/diagnostics
DEBUG_DESTINATION = https://secure.vilant.com/diagnostics

#Debug level (standard syslog levels)
# 3: ERR
# 5: NOTICE
# 6: INFO
# 7: DEBUG
# 8: DEBUG++
DEBUGLEVEL = 7


#=====================
#=== GPIO settings ===
#=====================

#GPI read trigger for start reading.
#For all the time reading, set this to -1
#It activates when GPI is HIGH.
#It stops when level is LOW
GPI_TRIGGER = -1