📜 ⬆️ ⬇️

Electronic ink for Wirenboard 5 or paint barcodes on Go

Hi, Habr! In the development process, sometimes you have to reinvent the wheel with tools for testing applications and it happens that some of them can be useful for example in home automation. Here is a case from my personal experience. When developing an application for mobile data collection terminals, there is a need to test laser scanners, without printing bar codes on paper. Unfortunately, these scanners do not know how to read from conventional screens. Give them the paper, but they also really liked the electronic paper.

image

I remembered an article on Habré E-book as a display , it was decided to get an old half-dead reader Sony PRS-505 from the shelf and give it a second life as a screen for an automation controller. But sending pictures through flash memory is a bad idea. It was necessary to learn how to work directly with the RAM of the e-book. This increases display speed and reliability. Let me share the experience of drawing in Go using the example of a barcode generator and displaying on an e-book through the Wirenboar 5 controller.

Tasks


  1. Nothing to break. We are just adding a new feature.
  2. The e-book should be able to listen to the port and display the image within 1 second.
  3. Work only through the buffer in RAM, no flash memory
  4. Test output with the great dd command
  5. Drawing a barcode of the desired size in Go and placing it in the center of the canvas
  6. Image transfer to e-book buffer
  7. Enjoy the result

RAM Drive via USB


There is no wi-fi in the Sony PRS-505 reader, and besides, there is only g_file_storage from the USB Gadget kernel modules, so this is the only way to quickly transfer an image. Fortunately, the PRSPlus firmware can launch any script when the e-book is turned on. All we need is to simply put the necessary files into the directory / database / system / PRSPlus folder and the prsp.sh script will be launched when loading.
')
Flash memory cannot be used as a buffer, so we need a small tmpfs disk in RAM that will be accessible via USB, unload the g_file_storage kernel module and load it with the necessary parameters to publish our newly created RAM disk via USB. Next, we must track the changes in the specified area and display the image on the e-ink display.

prsp.sh
#! / bin / sh
echo $ '\ n ================ \ nSTART SCRYPT \ n' >> / dev / console

#TODO "here need Kernel Event instead
function waitnewdata
{
echo $ '\ n ================ \ nWait new data \ n' >> / dev / console

#Show only modify time the image file
MODIFYTIMEOLD = `ls -l --full-time /tmp/raw.img | awk '{print $ 9}' `
MODIFYTIMENEW = $ MODIFYTIMEOLD

while ["$ MODIFYTIMEOLD" == "$ MODIFYTIMENEW"]
do
MODIFYTIMENEW = `ls -l --full-time /tmp/raw.img | awk '{print $ 9}' `

sleep 0.2
done

if ["$ MODIFYTIMEOLD"! = "$ MODIFYTIMENEW"]
then
showpic
fi
}

function showpic
{
echo $ '\ n ================ \ nNew data received \ n' >> / dev / console

#Generating Back screen for best clear e-ink (optional)
dd if = / dev / zero of = / tmp / img.raw bs = 1k count = 480
/ tmp / showpic /tmp/img.raw

dd if = / tmp / raw.img of = / tmp / img.raw bs = 1k count = 480
/ tmp / showpic /tmp/img.raw

waitnewdata
}

#ldconfig
PATH = "/ usr / local / bin: / usr / bin: / bin: / usr / bin / X11: / usr / games: / usr / local / sony / bin: / usr / sbin: / sbin"
LD_LIBRARY_PATH = "/ Data / opt / sony / ebook / application: / lib: / usr / lib: / usr / local / sony / lib: / opt / sony / ebook / lib"
export PATH LD_LIBRARY_PATH

# set initial date
/ bin / date 0101000007

#Unload kernel module
rmmod g_file_storage

#Create raw file 1Mb
dd if = / dev / zero of = / tmp / raw.img bs = 1k count = 1k

grep Data / proc / mtd> / dev / null
if [$? == 0]; then

NUM = `grep Data / proc / mtd | awk -F: '{print $ 1}' | awk -Fd '{print $ 2}' `
insmod /lib/modules/2.4.17_n12/kernel/drivers/usb/g_file_storage.o file = / dev / mtdblock $ NUM, / dev / sdmscard / r5c807b, / dev / sdmscard / r5c807a, / tmp / raw.img ProductID = $ MODEL VendorSpecific = $ VENDOR sn_select = 0 iSerialNumber = $ ID
else
insmod /lib/modules/2.4.17_n12/kernel/drivers/usb/g_file_storage.o file = / dev / sdmscard / r5c807b, / dev / sdmscard / r5c807a, / tmp / raw.img ProductID = $ MODEL VendorSpecific = $ VENDOR sn_select = 0 iSerialNumber = $ ID
fi

#start kbook application
nohup / opt / sony / ebook / application / tinyhttp> / dev / null &

cp / Data / database / system / PRSPlus / showpic / tmp /

waitnewdata

Highlights of what the psrp.sh script does


Now our e-book is able to listen and at the same time, you can still read books on it. The main thing to keep in mind is that in order for the script to start and we can transfer images, when the e-book is turned on, the USB cable should not be connected. Otherwise, the book will load without our script prsp.sh. That is, first we turn on the booklet, wait for the shell to load, then connect the USB cable. (this feature is by default written in the PRSPlus firmware, if desired, this can also be changed by making your own image)

Check


Press reset on the e-book, waiting for the end of the download, connect the USB cable. For verification, we can send a test image. For example from Ubuntu it can be done like this:

If the script is successfully launched when the reader is loaded, then when connected via USB, we will see a device with a size of 1Mb.

 fdisk -l 

Find the following string:

 Disk /dev/sdx: 1 MB, 1048576 bytes 

Now we know, here it is our piece of RAM of the e-book /dev/sdx .

To convert from jpeg, we need djpeg, install the necessary packages:

 apt-get install libjpeg-turbo-progs 

Next, create a JPEG file in your favorite editor, size 600x800 and send it to the e-book.

 djpeg -pnm -grayscale test.jpg | dd bs=1 skip=15 | dd of=/dev/sdx bs=480k 

In this pipeline, we convert jpeg to monochrome pgm, skip the header, and transfer 480Kb as a single block to the / dev / sdx device. And here we see the result.

Barcode generator and sending it to the device


To draw a barcode in Golang, we need additional libraries:

 go get github.com/boombuler/barcode go get golang.org/x/image/bmp 

main.go
 package main import ( "bytes" "fmt" "image" "log" "os" "image/color" "image/draw" "golang.org/x/image/bmp" "syscall" "github.com/boombuler/barcode" "github.com/boombuler/barcode/ean" "github.com/boombuler/barcode/qr" ) func main() { switch string(os.Args[2]) { case "qr": base64 := os.Args[3] log.Println("Original data:", base64) code1pixel, err := qr.Encode(base64, qr.L, qr.Unicode) if err != nil { log.Fatal(err) } log.Println("Encoded data: ", code1pixel.Content()) if base64 != code1pixel.Content() { log.Fatal("data differs") } log.Println("Encoded data: ", code1pixel.Content()) if base64 != code1pixel.Content() { log.Fatal("data differs") } codeScalled, err := barcode.Scale(code1pixel, 300, 200) if err != nil { log.Fatal(err) } drtest(codeScalled) case "ean": // code, err := ean.Encode("123456789012") code1pixel, err := ean.Encode(os.Args[3]) if err != nil { log.Fatal(err) } log.Println("Encoded data: ", code1pixel.Content()) codeScalled, err := barcode.Scale(code1pixel, 300, 300) if err != nil { log.Fatal(err) } drtest(codeScalled) } } func drtest(imgSrc image.Image) { // create a new Image with the same dimension of image newImg := image.NewGray(image.Rect(0, 0, 600, 800)) // we will use white background to replace background // you can change it to whichever color you want with // a new color.RGBA{} and use image.NewUniform(color.RGBA{<fill in color>}) function draw.Draw(newImg, newImg.Bounds(), &image.Uniform{color.White}, image.Point{}, draw.Src) // paste image OVER to newImage draw.Draw(newImg, newImg.Bounds().Add(image.Point{150, 300}), imgSrc, imgSrc.Bounds().Min, draw.Over) buf := new(bytes.Buffer) err := bmp.Encode(buf, newImg) if err != nil { fmt.Println(err) os.Exit(1) } send_s3 := buf.Bytes() fmt.Println("OK") if os.Args[1] != "false" { devout(send_s3[1078:]) } } func devout(buffer []byte) { // disk := "/dev/sde" disk := os.Args[1] var fd, numread int var err error fd, err = syscall.Open(disk, syscall.O_RDWR, 0777) if err != nil { fmt.Print(err.Error(), "\n") return } //WRITE numread, err = syscall.Write(fd, buffer) if err != nil { fmt.Print(err.Error(), "\n") } fmt.Printf("Numbytes write: %d\n", numread) // fmt.Printf("Buffer: %x\n", buffer[:1000]) err = syscall.Close(fd) if err != nil { fmt.Print(err.Error(), "\n") } } 

Key points in the code:

  1. Using the example of EAN, we first draw a 1 pixel-thick bar code:

     code1pixel, err := ean.Encode(os.Args[3]) 

  2. Stretch it to the desired size:

     codeScalled, err := barcode.Scale(code1pixel, 300, 300) 

  3. Create a 600x800 canvas to fit the screen:

     newImg := image.NewGray(image.Rect(0, 0, 600, 800)) 

  4. Fill it with the desired color:

     draw.Draw(newImg, newImg.Bounds(), &image.Uniform{color.White}, image.Point{}, draw.Src) 

  5. Overlay on our canvas barcode image:

     draw.Draw(newImg, newImg.Bounds().Add(image.Point{150, 300}), imgSrc, imgSrc.Bounds().Min, draw.Over) 

  6. Next, we open the device for recording and send the data there by deleting the BMP header:

     devout(send_s3[1078:]) 

Cross compilation under Wirenboard 5


Wirenboard developers provide us with a very convenient cross-compilation tool based on the Docker container. But in this article we will not consider it. Under ARMv5, our simple application can be assembled as a team.

 GOOS=linux GOARCH=arm GOARM=5 go build main.go 

We transfer everything to Wirenboard 5:

 scp main root@192.168.xx:/tmp 

Go to Wirenboard, look at the device name of 1 MB in size, in my example / dev / sdd.

Run:

 /tmp/main /dev/sdd qr "Privet Habr" 



findings


Using an e-book as a screen is quite real. With its potential, electronic ink technology prompts the use of interior design. E-ink screen will look good especially on a light wall. You can display useful information from the home controller.

Thanks for attention!

PS Sources, you can see here and here . Firmware PRSPlus for e-books here .

Source: https://habr.com/ru/post/321238/


All Articles