Phase 2 - Add Card Reader Device
In phase 1, the scenarios presented a breakdown of the various modes, events, and services that are working together within the Automated Checkout reference implementation. Everything in phase 1 was simulated and all interactions were done via REST API calls.
Phase 2 will be mostly the same, except there will now be a physical card reader device. This device is actually just a keyboard that types 10 digits and then presses enter, which is what a common RFID card reader also might do.
Setup
If the Automated Checkout services are still running from phase 1, the services can stay running. The only service that will be terminated and re-created is ds-card-reader
(which will be done as part of this guide).
Start by removing the ds-card-reader
service. In order to do this, first identify the container's name using this command:
docker ps | grep -i ds-card-reader
Use the output of that command to stop the container for ds-card-reader
- replace container_name_or_id_from_previous_command
with the output from above:
docker rm -f container_name_or_id_from_previous_command
Note
If you encounter any issues with the ds-card-reader
later in this guide, consider cleaning up all of the Automated Checkout services. The best way to guarantee a clean run through of this phase is to tear down any existing Automated Checkout environment and start from fresh. This can be accomplished by running the following steps.
Navigate to the root of this repository - this can vary based on where you chose to clone the repository:
cd <repository_root>
Run the following commands to clean things up:
make down && make clean-docker
This will destroy any existing ledger entries, audit log entries, inventory changes, and EdgeX event readings and data associated with Automated Checkout. However, this will not alter any other non-Automated Checkout Docker images, containers, or volumes. The scope of the above command is limited to only Automated Checkout.
Plug in the card reader device
The first step is to simply plug in the card reader device. This can be a regular USB keyboard or a dedicated RFID card reader, or any other HID keyboard-like input device that works with evdev
and can be identified via the Linux command lsusb
.
Note
If you are going to use a keyboard as a card reader device, we suggest plugging in a second keyboard for this purpose.
Once it's plugged in, proceed to identify the device by running the command:
lsusb
The output may look like this (this is the output from a virtual machine):
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID ffff:0035
Bus 001 Device 002: ID 80ee:0021 VirtualBox USB Tablet
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
The particular vendor ID and product ID are spelled out clearly for each USB device. The card reader input device itself has been plugged in and has the vendor ID ffff
and the product ID 0035
.
Note
The VID and PID values are hexadecimal, base 16. A value of ffff
is equal to 65535
in decimal, base 10, and 0035
in base 16 is equal to 53
in base 10. The configuration files in the Automated Checkout reference implementation device services may require some conversion between the two. If needed, consider searching online for a hexadecimal to decimal conversion calculator to make the process easier.
Once the VID and PID have been identified, the next step is to configure the ds-card-reader
device service to grab that device and listen for input events.
Configure the ds-card-reader
service to use the card reader device
From the root of this repository, with the card reader device plugged in and its VID and PID identified, navigate to the ds-card-reader/res/docker
directory:
cd <repository_root>
Then, modify the docker-compose.physical.card-reader.yml
file in your text editor of choice:
nano docker-compose.physical.card-reader.yml
In this file, you'll see a section that looks like this:
ds-card-reader:
user: "0:0"
devices:
- /dev/input:/dev/input
environment:
DRIVERCONFIG_SIMULATEDEVICE: "false"
We will be adding three environment variables to this service:
DeviceSearchPath
- the path to search forevdev
input devicesVID
- the base-10 value of the vendor ID associated with the input devicePID
- the base-10 value of the product ID associated with the input device
First, verify that the default value of DeviceSearchPath="/dev/input/event*"
corresponds to an actual path on your Linux system - the vast majority of Linux systems should automatically handle everything in this directory, but it helps to check.
ls -al /dev/input/event
(Click to Expand) Example Output
The output of ls -al /dev/input/event
may look like this:
crw-rw---- 1 root input 13, 64 Apr 9 09:10 /dev/input/event0
crw-rw---- 1 root input 13, 65 Apr 9 09:10 /dev/input/event1
crw-rw---- 1 root input 13, 66 Apr 9 09:10 /dev/input/event2
crw-rw---- 1 root input 13, 67 Apr 9 09:10 /dev/input/event3
crw-rw---- 1 root input 13, 68 Apr 9 09:10 /dev/input/event4
crw-rw---- 1 root input 13, 69 Apr 9 09:10 /dev/input/event5
crw-rw---- 1 root input 13, 70 Apr 9 09:10 /dev/input/event6
crw-rw---- 1 root input 13, 71 Apr 9 09:58 /dev/input/event7
If you do not see input devices under this path, your Linux kernel or operating system may be configured differently. Consult your operating system's documentation for information regarding the behavior of input devices if possible.
The resulting section in the configuration file will look something like this:
ds-card-reader:
user: "0:0"
devices:
- /dev/input:/dev/input
environment:
DRIVERCONFIG_SIMULATEDEVICE: "false"
DRIVERCONFIG_DEVICESEARCHPATH: "/dev/input/event*"
DRIVERCONFIG_VID: 65535 # 0xFFFF
DRIVERCONFIG_PID: 53 # 0x0035
Run the Automated Checkout reference implementation
Run the Automated Checkout reference implementation with the physical card reader component included:
make run-physical-card-reader
After about a minute or so, the card reader device service (ds-card-reader) will be configured to accept inputs from an external card reader device. Follow the steps outlined in phase 1 again, except instead of performing REST API calls to simulate badge swipe events, replace them with a keyboard inputs that correspond to the same cards ID, press enter
, and then continue forward with the REST API calls that simulate door open/closure events, temperature changes, etc.
Note
You do not need to type the card ID number anywhere specifically. The card reader device service is configured in such a way that it will listen to any inputs from the keyboard at any time.
The input device is globally grabbed using evdev's GrabDevice
mechanism, summarized here:
GrabDevice: ... Doing so will ensure that no other driver can initialise the same device and it will also stop the device from sending events to /dev/kbd or /dev/input/mice. Events from this device will not be sent to virtual devices (e.g. rfkill or the Macintosh mouse button emulation).
For example, in phase 1, the card number for the stocker role is 0003293374
. This card number can be simulated by typing the digits and pressing the enter key, if you're using a keyboard as your input device.
Dive deeper
Now that the card reader is working with a physical device, it may be time to make some changes to the underlying authentication data to allow your own cards to authenticate. The following sections illustrate the steps needed in order to extend the Automated Checkout reference implementation to work with your cards.
Extending the card reader
If the behavior of your particular card reader device's cards does not match the behavior that's been incorporated into this service, you'll need to get your hands dirty with the source code of the ds-card-reader
device service.
In the service, take a look at the file ds-card-reader/device/physical.go
. This file contains this function:
func (reader *CardReaderPhysical) Listen() {
// ...
reader.processDevReadEvents(events)
// ...
}
Listen
is a Go routine that loops and processes evdev
events as they come in from the physical input device. Carefully inspect this section of code as well as the functions called within this Go routine in order to gain an understanding of how to change the behavior of the card reader device service.
Warning
Changing the source code may break unit tests and other functionality across services. Ensure that the software development processes used to make code changes include updating unit and integration tests to work with new changes.
Adding new cards
The ms-authentication
microservice contains an index of all cards, accounts, and authorized individuals (people). To add a new card, person, or account, follow these steps.
First, navigate to the ms-authentication
directory in the root of the repository. These three .json
files dictate the ms-authentication
service's behavior:
In this case, we're only going to add a new card and associate it with the person with ID 1. A typical card will look like this:
{
"cardId": "0003621892",
"roleId": 1,
"isValid": true,
"personId": 3,
"createdAt": "1560815799",
"updatedAt": "1560815799"
}
Let's add a new card to the cards.json
file - replace 1234567899
with a 10-digit card that corresponds to one of your cards:
...,
{
"cardId": "1234567899",
"roleId": 1,
"isValid": true,
"personId": 3,
"createdAt": "1560815799",
"updatedAt": "1560815799"
}
...
Info
The createdAt
and updatedAt
dates do not particularly matter, but should be kept as a Unix timestamp.
Now that we've added the card to the cards.json
file, the service's Docker image must be rebuilt. Navigate to the root of this repository, which should be up a single directory:
cd ..
Then, use the Makefile
to build the ds-card-reader
image:
make ds-card-reader
Info
At this time, the three .json
files are built in to the Docker image for the ms-authentication
service. They are not mounted at runtime. This is why image rebuilding is necessary.
Running the updated service
If the Automated Checkout services are already running, the best way to update the running ms-authentication
service is to remove the ms-authentication
container and then re-run the command to bring up the whole stack.
First, remove the ms-authentication
container:
docker ps -a | grep -i ms-authentication
Use the output of the last command to delete the ms-authentication
container. Replace container_name
in the below command with the name from the output from the above command to delete it:
docker rm -f container_name
Then, bring up the services using the same command from before:
make run-physical-card-reader
Note
If this fails to properly update the image, it may be worth running
make down
And then re-running
make run-physical-card-reader
If there are still issues, consider completely cleaning the Automated Checkout containers and volumes by running
make down && make clean-docker
And then running
make run-physical-card-reader
The ds-card-reader
service should be listening for input events. If your card reader device is a proper RFID USB card reader, swipe the card that corresponds to the card we added, or if it's a USB keyboard, type out the keys and press enter when done, and follow the steps in phase 1 while replacing card reader badge-in events with this method.
Info
For more generalized information on modifying source code, please review the Modifying source code page.
Summary
The usage of a physical card reader device only requires a few changes from the simulated mode. In the ds-card-reader
device service, the device's VID and PID are configured, the service's image gets rebuilt, and the service itself gets updated to use the new image. The device's interactions are captured by Go routines running in the device service itself, and EdgeX event readings are propagated throughout a handful of services to ensure a smooth Automated Checkout workflow.