Skip to content

Instantly share code, notes, and snippets.

@owulveryck
Last active December 24, 2020 13:23
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save owulveryck/4007cbf14e0028f373e4294f66c4ad07 to your computer and use it in GitHub Desktop.
Save owulveryck/4007cbf14e0028f373e4294f66c4ad07 to your computer and use it in GitHub Desktop.
Screenshot on the remarkable

Compile the executable:

GOOS=linux GOARCH=arm GOARM=7 go build -o test.arm

Send it to the remarkable

Execute it:

reMarkable: ~/ ./test.arm /proc/$(pidof xochitl)/mem

Those informations are a collection of the elements from issue #28 of the reStream project

Remarkable version

reMarkable: ~/ cat /usr/share/remarkable/update.conf
[General]
#REMARKABLE_RELEASE_APPID={98DA7DF2-4E3E-4744-9DE6-EC931886ABAB}
#SERVER=https://get-updates.cloud.remarkable.engineering/service/update2
#GROUP=Prod
#PLATFORM=reMarkable2
REMARKABLE_RELEASE_VERSION=2.5.0.27

Locating the global framebuffer

reMarkable: ~/ strace xochitl
...
563 openat(AT_FDCWD, "/dev/fb0", O_RDWR)    = 5
564 ioctl(5, FBIOGET_FSCREENINFO, 0x7ee9d5f4) = 0
565 ioctl(5, FBIOGET_VSCREENINFO, 0x42f0ec) = 0
566 ioctl(5, FBIOPUT_VSCREENINFO, 0x42f0ec) = 0

Global framebuffer is located at 0x42f0ec-4 =0x42f0e8 (4387048 in decimal)

Now get a picture:

#!/bin/sh
pid=`pidof xochitl`
addr=`dd if=/proc/$pid/mem bs=1 count=4 skip=4387048  2>/dev/null | hexdump | awk '{print $3$2}'`
skipbytes=`printf "%d" $((16#$addr))`
dd if=/proc/$pid/mem bs=1 count=2628288 skip=$skipbytes > out.data

Note: 2628288 = 1404*1872 (the number of pixel in the screen of the remarkable)

Get the picture back on my laptop and convert it:

convert -depth 8 -size 1872x1404+0 gray:out.data out.png

which gives: out

package main
import (
"encoding/binary"
"image"
"image/png"
"io"
"log"
"os"
)
const (
screenWidth = 1872
screenHeight = 1404
fbAddress = 4387048
)
func main() {
file, err := os.OpenFile(os.Args[1], os.O_RDONLY, os.ModeDevice)
if err != nil {
log.Fatal("cannot open file: ", err)
}
defer file.Close()
addr, err := getPointer(file, fbAddress)
if err != nil {
log.Fatal(err)
}
log.Println("Address is: ", addr)
img, err := getImage(file, addr)
f, err := os.Create("image.png")
if err != nil {
log.Fatal(err)
}
if err := png.Encode(f, img); err != nil {
f.Close()
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}
func getPointer(r io.ReaderAt, offset int64) (int64, error) {
pointer := make([]byte, 4)
_, err := r.ReadAt(pointer, offset)
if err != nil {
return 0, err
}
return int64(binary.LittleEndian.Uint32(pointer)), nil
}
func getImage(r io.ReaderAt, offset int64) (image.Image, error) {
pixels := make([]byte, screenHeight*screenWidth)
_, err := r.ReadAt(pixels, offset)
if err != nil {
return nil, err
}
img := &image.Gray{
Pix: pixels,
Stride: screenWidth,
Rect: image.Rect(0, 0, screenWidth, screenHeight),
}
return img, nil
}
@gianpaj
Copy link

gianpaj commented Dec 24, 2020

thanks! I created a little bash script from this to take a screenshot and transfer it back:
takeScreenshot.sh

DATE=$(date -u +%FT%TZ)
FILEPATH="$HOME/Desktop/remarkable-$DATE.png"
ssh root@10.11.99.1 './test.arm /proc/$(pidof xochitl)/mem' && \
scp root@10.11.99.1:/home/root/image.png "$FILEPATH" && \
open -a Preview "$FILEPATH"

PS: the last command is for Mac only

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment