-
HaLiTerm mini
08/08/2024 at 20:26 • 0 commentsI have been busy trying to shrink the Handheld Linux Terminal. Beepy by SQFMI was the main inspiration. Here is the result.
-
Displaying images on the terminal
10/18/2023 at 17:57 • 0 commentsThis is a crude and very slow solution to show images on the Terminal from within the Linux command line using a custom escape code and a simple Python program.
// Usage
path/to/primg.py -[options] path/to/image.jpg Options: -w horizontal size (default 300) -h vertical size (default 200) -s max. 100x100 pixel -l max. 600x400 pixel
// primg.py (requires the pillow library)
#!/bin/python3 from sys import argv from PIL import Image screen_x = 300 screen_y = 200 # get arguments def get_args(): global screen_x global screen_y for i in range(1, len(argv)): if argv[i] == "-w": w = int(argv[i+1]) if w <= 600 and w > 0: screen_x = w elif argv[i] == "-h": h = int(argv[i+1]) if h <= 400 and h > 0: screen_y = h elif argv[i] == "-s": screen_x = 100 screen_y = 100 elif argv[i] == "-l": screen_x = 600 screen_y = 400 return argv[-1] # print pixel data to stdout def rgb_to_stdout(image): # img = image.convert(mode="RGBA") img_x, img_y = img.size print("{0}[{1};{2}z".format(chr(27), img_x, img_y), end="") for y in range(0, img_y): for x in range(0, img_x): r, g, b = img.getpixel((x, y)) r = r // 8 if r == 10: r = 11 g = g // 4 if g == 10: g = 11 b = b // 8 if b == 10: b = 11 print("{0}{1}{2}".format(chr(r), chr(g), chr(b)), end="") # rotate image if necessary def check_rotation(img): x, y = img.size if ((screen_x > screen_y) and (y > x)) or ((screen_x < screen_y) and (y < x)): return img.rotate(90, expand=True) else: return img # scale image def rescale(img): x, y = img.size scale_x = x / screen_x scale_y = y / screen_y if scale_x > scale_y: return img.resize((screen_x, int(y / scale_x))) else: return img.resize((int(x / scale_y), screen_y)) # program entry path = get_args() img = Image.open(path, "r") img = check_rotation(img) img = rescale(img) rgb_to_stdout(img)
// Details
Three weeks ago the idea struck me, that I could try to send pixel values over UART from the NanoPi to the Pico and write them directly to the DDRAM of the RA8875. This solution involves a custom escape code (ESC [ (size_x ); (size_y) z) and printing the pixel RGB565 values as characters to stdout. The terminal expects exactly three times the number of pixels as characters after the escape code and keeps writing the values to the DDRAM of the RA8875 until all pixels are received. Printing values over 127 as character to stdout results in an UTF-8 encoding. Because of this, the RGB values are converted to 565 bit format before using the chr() function. After some trial and error I figured out, that print(chr(10)) didn't work, so I simply change the channel value to 11 if it would be 10.
-
Setting TERM in .bashrc and using tmux
08/26/2023 at 12:01 • 0 commentsSetting the TERM variable or the terminal size in .bashrc leads to some issues in tmux. By default, TERM is "vt220" in DietPi while using UART. This is a possible workaround that can be added to .bashrc:
if [ $TERM = vt220 ]; then TERM=linux stty cols 100 rows 30 fi
This way TERM doesn't change if it was set by tmux (in my case it is "tmux-color256"). This can also be used to add lines that shouldn't be executed every time you open a new window in tmux.
-
Prototyping addon
08/10/2023 at 12:56 • 0 commentsI am still looking for inspiration for possible extension modules for this project. In the meantime I started to design a prototyping addon.
-
Getting WiringNP to work in DietPi
08/02/2023 at 11:16 • 0 commentsFreindlyElec has its own WiringPi based library called WiringNP. It compiles with several warning massages. Trying to execute "gpio readall" in DietPi returns an error massage:
piBoardRev: Unable to determine board revision from /proc/cpuinfo -> Is not NanoPi based board. -> You may want to check: -> http://www.lemaker.org/ open /sys/class/sunxi_info/sys_info failed
While /proc/cpuinfo looks good in DietPi, sys/class/sunxi_info/sys_info doesn't exist. According to this workaround, you can redirect WiringNP to /etc/sys_info by editing WiringNP/wiringPi/boardtype_friendlyelec.c before executing ./build.
Original:
if (!(f = fopen("/sys/class/sunxi_info/sys_info", "r"))) { LOGE("open /sys/class/sunxi_info/sys_info failed."); return -1; }
Modified:
if (!(f = fopen("/sys/class/sunxi_info/sys_info", "r"))) { if (!(f = fopen("/etc/sys_info", "r"))) { LOGE("open /sys/class/sunxi_info/sys_info failed."); return -1; } }
In FriendlyCore for the NanoPi NEO Air sys_info looks like this:
sunxi_platform : sun8iw7p1 sunxi_secure : normal sunxi_chipid : unsupported sunxi_chiptype : unsupported sunxi_batchno : unsupported sunxi_board_id : 2(0) board_manufacturer: FriendlyElec board_name : FriendlyElec Nanopi-NEO-Air
With this workaround "gpio readall" returns the expected output:
+-----+-----+----------+------+---+-NanoPi-NEO-Air--+------+----------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+ | | | 3.3V | | | 1 || 2 | | | 5V | | | | 12 | 8 | GPIOA12 | ALT5 | 0 | 3 || 4 | | | 5V | | | | 11 | 9 | GPIOA11 | ALT5 | 0 | 5 || 6 | | | 0v | | | | 203 | 7 | GPIOG11 | OFF | 0 | 7 || 8 | 0 | OFF | GPIOG6 | 15 | 198 | | | | 0v | | | 9 || 10 | 0 | OFF | GPIOG7 | 16 | 199 | | 0 | 0 | GPIOA0 | OFF | 0 | 11 || 12 | 0 | OFF | GPIOA6 | 1 | 6 | | 2 | 2 | GPIOA2 | OFF | 0 | 13 || 14 | | | 0v | | | | 3 | 3 | GPIOA3 | OFF | 0 | 15 || 16 | 0 | OFF | GPIOG8 | 4 | 200 | | | | 3.3v | | | 17 || 18 | 0 | OFF | GPIOG9 | 5 | 201 | | 64 | 12 | GPIOC0 | OFF | 0 | 19 || 20 | | | 0v | | | | 65 | 13 | GPIOC1 | OFF | 0 | 21 || 22 | 0 | OFF | GPIOA1 | 6 | 1 | | 66 | 14 | GPIOC2 | OFF | 0 | 23 || 24 | 0 | OFF | GPIOC3 | 10 | 67 | +-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+----------+------+---+-NanoPi-NEO-Air--+------+----------+-----+-----+ +-----+----NanoPi-NEO-Air USB/Audio-+----+ | BCM | wPi | Name | Mode | V | Ph | +-----+-----+----------+------+---+----+ | | | 5V | | | 25 | | | | USB-DP1 | | | 26 | | | | USB-DM1 | | | 27 | | | | USB-DP2 | | | 28 | | | | USB-DM2 | | | 29 | | | | IR-RX | | | 30 | | 17 | 19 | GPIOA17 | OFF | 0 | 31 | | | | PCM/I2C | | | 32 | | | | PCM/I2C | | | 33 | | | | PCM/I2C | | | 34 | | | | PCM/I2C | | | 35 | | | | 0V | | | 36 | +-----+-----+----------+------+---+----+ +-----+----NanoPi-NEO-Air Debug UART-+----+ | BCM | wPi | Name | Mode | V | Ph | +-----+-----+----------+------+---+----+ | 4 | 17 | GPIOA4 | ALT5 | 0 | 37 | | 5 | 18 | GPIOA5 | ALT5 | 0 | 38 | +-----+-----+----------+------+---+----+
I was surprised to see, that in FriendlyCore the DS3231 RTC was automatically assigned to /dev/rtc1. I still had to manually sync the system time to it.