What is the CardKB ?
The CardKB is a simple and cute keyboard made by M5Stack, owner of modular stackable product development toolkits based on ESP32.
It uses I²C to communicate, wich means it has a clock line and a data line (you can check documentation here). It nearly exactly fits the size of our GameShell, and costs nearly nothing, wich makes it a great choice.
Enabling I²C on the GameShell :
I took many informations to make I²C enabled here. If not precised, execute tasks on any computer. I assume you’re using a Linux distribution (I use Pop!_OS but it should work on any distros, you’ll just need to adapt it to yours ! If you don’t have one installed, consider using WSL).
First of all :
- Download and extract the toolchain which we will use to compile and build our Kernel:
wget https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11/arm-linux-gnueabihf/gcc-linaro-
7.2.1-2017.11-x86_64_arm-linux-gnueabihf.tar.xz
tar xf gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf.tar.xz
- Add it to the PATH :
cd gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/
export PATH=$PATH:$(pwd)
- Download dependencies if required :
apt-get install flex bison libssl-dev u-boot-tools
-
Download Kernel sources (choose depending on your environment). I’ll choose the 5.3.6 as it’s the one I use on my GS.
-
From sources’ root, go to
./arch/arm/boot/dts
and add the following to the end ofsun8i-r16-clockworkpi-cpi3.dts
:
&i2c1 {
status = "okay";
};
- Build the Kernel using this command :
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
- Copy the newly generated .dtb file to your GS :
scp arch/arm/boot/dts/sun8i-r16-clockworkpi-cpi3.dtb cpi@clockworkpi:/home/cpi/
- As a super-user, mount your boot partition on the GS (you can use
ssh cpi@clockworkpi
to access a CLI) :
sudo su
cd /mnt
mkdir boot
mount /dev/mmcblk0p1 /mnt/boot/
- Make a backup as it may break your OS if something goes wrong on the GS :
cp /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb.bak
- Install the new .dtb file by copying it into the boot partition on the GS :
cp /home/cpi/sun8i-r16-clockworkpi-cpi3.dtb /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb
- Reboot and test your installation simply using on the GS :
i2cdetect -y 0
If everything worked as intended it should probe every I²C adresses, showing an array like this :
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Enabling uinput Kernel module :
The keyboard library, wich is the library we will be using in our script , uses uinput to emulate a keyboard. It has not been included in the GS Kernel modules, we will then need to build our own modified Kernel and add it to the GS.
- Fist of all we will need to fix something. In the file
./scripts/dtc/dtc-lexer.l
find :
YYLTYPE yylloc;
- And add
extern
keyword before it :
extern YYLTYPE yylloc;
- Using previously downloaded Kernel sources include
User level driver support
using menuconfig :
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
- You can find it under :
Device Drivers --->
Input Device Support --->
Miscellaneous devices --->
To include it you’ll need to press Y (a *
will appear).
Press exit
or Escape until you’re prompted to save. Save.
- Build the Kernel image :
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
mkimage -A arm -O linux -T kernel -C none -a 0x40008000 -e 0x40008000 -n "Linux Kernel" -d arch/arm/boot/zImage uImage
- On your GS, make a backup file of your uImage (as root):
cd /mnt/boot/
cp uImage uImage.bak
- Replace the
uImage
file and reboot:
cp /home/cpi/uImage ./uImage
reboot
You’re nearly done !
Python script :
To ensure the script will work, you’ll need to download smbus and keyboard Python libraries :
We will use the keyboard library to simulate a keyboard via Python as mentionned earlier. The smbus one will be used to interact with the I²C interface.
- To install those, simply type on the GS :
pip install smbus
pip install keyboard
- Make a file named
<filename>.py
and paste the following code in it :
#importing smbus for i2c, and keyboard for injecting keystrokes.
import smbus,keyboard
#Selecting i2c channel (0 by default for GameShell, may be different for RPi
channel = 0
#CardKB i2c adress to listen on
address = 0x5f
bus = smbus.SMBus(channel)
while True:
# test = ""
# try :
# test = bus.read_byte_data(address, 0)
# except:
# pass
# if test != "":
# print(test)
try :
#reads value passed by the keyboard
msg = bus.read_byte(address)
#ensures no empty messages are passed
if msg != 0 :
#180,181,182,183 prints weird chars instead of what they're meant to : key_up/down/left/right
if msg == 180 :
keyboard.press_and_release("left")
#print(msg)
elif msg == 181:
keyboard.press_and_release("up")
#print(msg)
elif msg == 182:
keyboard.press_and_release("down")
#print(msg)
elif msg == 183:
keyboard.press_and_release("right")
#print(msg)
else:
#print(chr(msg))
#print(msg)
keyboard.press_and_release(chr(msg))
except :
pass
- Connect your CardKB following it’s pinmap and GameShell’s one. Run it. You’re finally done !
Here’s what it looks like :
As you can see it’s absolutely not practical, it still needs a case, and I use some illegal lego techniques. I should also shorten the cables. Feel free to ask questions, share what you did etc… See ya !