Let's develop something close to embedded with TDD ~ Preparation ~

Introduction

I've been studying to do TDD in embedded development. Until now, I've been studying mainly on applications, so I'll try to create something that looks a bit like embedded (assuming embedded Linux). Since it is a close-out departure, the policy may change on the way. You will not know until you actually do it, so please watch with warm eyes.

Feel free to give us your feedback on your opinions and requests! It's very encouraging.

What you are trying to make

Speaking of built-in, it would be L Chika! However, I want to make it easier to try, so I'll make the LED on the keyboard flicker (such as caps lock). It does not use a high-performance library, but manages by manipulating device files.

If it's too easy, it's too easy, and it's not practical, so I'll think about realizing the next function.

Since it is built-in, always consider portability to another hardware.

Development environment

OS Virtual box ubuntu 16.04
compiler gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
Build tool autotools, pkg-config
Library libevdev-1.0
Test framework googletest/googlemock@62ba5d9
Product code C or C++(I am thinking)

Preliminary research

Preliminary research is important for everything you do. For the time being, I will investigate my environment.

Get keyboard event

To get keyboard input events on Linux, monitor the / dev / input / event 〇〇 file. Numbers are entered in the part of 〇〇, but the number of the keyboard changes in the order recognized in the environment and startup (it is possible to fix it with udev, but this time I will leave it for the time being).

Look in / proc / bus / input / devices to find the keyboard. Currently, event2 (input2) supports keyboards.

cat /proc/bus/input/devices
==Omitted on the way==
I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/devices/platform/i8042/serio0/input/input2
U: Uniq=
H: Handlers=sysrq kbd event2 leds
B: PROP=0
B: EV=120013
B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=7
==Omitted below==

For event devices like / dev / input, Linux provides an evdev (Linux Input drivers v1.0) interface. doing. The wrapper library for this evdev is libevdev. This time, we will use this libevdev.

Keyboard LED

Then check the LEDs on your keyboard. Linux provides an LED class, and when Linux recognizes the LED, it will be exported under / sys / class / leds in sysfs. The LEDs for capslock, numlock, and scrolllock are recognized. (My keyboard doesn't have LEDs on the numlock and scrolllock keys ... need to be investigated)

ls /sys/class/leds/
input2::capslock  input2::numlock  input2::scrolllock

Tests for library comprehension

Since we started from the privileged state of having both hardware (keyboard) and library (libevdev), we will write tests to understand the target library. By writing this test, you will test your library comprehension. It seems very good that what you understand remains as a test.

If this can be done on the host machine, you're lucky.

  1. There are many situations where the target board only has the target hardware / library.
  2. It's a common story that even the target doesn't move or there is nothing.

If it is 1, you can proceed while cross-building obediently. In case 2, if you know the API, let's make a mock. When the real thing comes out, you can test whether the usage written in the test is correct. Imagine making a mock if you don't understand the API. Creating a mock without knowing the implementation details also has its advantages, and the API may be reasonably abstracted.

Tests written to understand libevdev

The introduction has become long, but let's take a look at the test I wrote this time. Some code is omitted and posted. If you want to see the whole picture, click here [https://github.com/tomoyuki-nakabayashi/TDDforEmbeddedSystem).

First, get the control data of evdev from the file descriptor. If successful, 0 or more will be returned. Initially, this test failed. Now that we know we need root privileges, we'll make the test name known (add AsRoot). Now you won't be addicted to the same thing at a later date. If you suddenly take over to someone, you'll find that you can't run it without root privileges.

TEST_F(EvdevSampleTest, InputEventFileCanOpenAsRoot) {
  struct libevdev *dev = nullptr;
  int fd = open("/dev/input/event2", O_RDONLY|O_NONBLOCK);
  int rc = libevdev_new_from_fd(fd, &dev);

  EXPECT_GE(rc, 0);
}

Since the control data of evdev has been acquired, confirm that EAGAIN is returned when there is no input. This passed in one shot.

TEST_F(EvdevSampleTest, ReturnsEAGAIN) {
  input_event ev {};
  int actual = libevdev_next_event(evdev_, LIBEVDEV_READ_FLAG_NORMAL, &ev);
  EXPECT_EQ(-EAGAIN, actual);
}

Then press Enter and it will return LIBEVDEV_READ_STATUS_SUCCESS to test that you can get the input_event you expected. After executing the test, the test will stop during the execution of this test, so if you press the Enter key, the test will pass (it is no longer a unit test, but I don't care). By the time we reach the final EXPECT_EQ, we've confirmed that the events we've acquired are as expected, but we don't care for the time being.

TEST_F(EvdevSampleTest, CaptureEnterKeyPress) {
  auto expect = create_key_event(KEY_ENTER, KEY_PRESSED);
  input_event actual {};
  while (true) {
    int rc = libevdev_next_event(evdev_, LIBEVDEV_READ_FLAG_NORMAL, &actual);
    if ((rc == LIBEVDEV_READ_STATUS_SUCCESS) && actual == expect) break;
  }

  EXPECT_EQ(expect, actual);
}

Thinking while making a test

Considering that it can be used with other input devices, it would be nice to have a general-purpose callback interface. libevdev doesn't provide a callback mechanism, so I wonder if I can create a callback mechanism from scratch.

Future plans

Next: Try to develop something close to embedded with TDD ~ Problem raising ~

Recommended Posts

Let's develop something close to embedded with TDD ~ Preparation ~
Let's develop something close to embedded with TDD ~ Intermediate review ~
Let's develop something close to embedded with TDD ~ Problem raising ~
Let's develop something close to embedded with TDD ~ Design pattern ~
Let's develop something close to embedded with TDD ~ file open edition ~
Let's develop something close to embedded with TDD ~ Key input detection version ~
Let's develop something close to embedded with TDD ~ libevdev initialization / termination processing ~
Steps to develop Django with VSCode
[Introduction to WordCloud] Let's play with scraping ♬
[Introduction to Python] Let's use foreach with Python
Develop Windows apps with Python 3 + Tkinter (Preparation)
Let's develop an investment algorithm with Python 1
Convert mp4 to mp3 with ffmpeg (thumbnail embedded version)
How to develop a cart app with Django