Skip to content

Commit ab003c6

Browse files
committed
Implement FbMem and LCD classes
FbMem provides generic framebuffer info and also maps framebuffer memory. The implementation is adopted from https://github.com/LinkCareServices/cairotft/blob/master/cairotft/linuxfb.py (also see @dlech's comment here: ev3dev/ev3dev#404 (comment)) LCD is a convenience class that wraps FbMem and provides drawing functions from the Python Imaging Library (PIL).
1 parent 5442a28 commit ab003c6

File tree

1 file changed

+215
-0
lines changed

1 file changed

+215
-0
lines changed

ev3dev.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,16 @@
2727

2828
#~autogen
2929

30+
import os
3031
import os.path
3132
import fnmatch
3233
import numbers
3334
import platform
3435
import fcntl
3536
import array
37+
import mmap
38+
import ctypes
39+
from PIL import Image, ImageDraw
3640

3741
#------------------------------------------------------------------------------
3842
# Guess platform we are running on
@@ -1987,3 +1991,214 @@ def status(self):
19871991

19881992
#~autogen
19891993

1994+
class FbMem(object):
1995+
1996+
"""The framebuffer memory object.
1997+
1998+
Made of:
1999+
- the framebuffer file descriptor
2000+
- the fix screen info struct
2001+
- the var screen info struct
2002+
- the mapped memory
2003+
"""
2004+
2005+
#-------------------------------------------------------------------
2006+
# The code is adapted from
2007+
# https://github.com/LinkCareServices/cairotft/blob/master/cairotft/linuxfb.py
2008+
#
2009+
# The original code came with the following license:
2010+
#-------------------------------------------------------------------
2011+
# Copyright (c) 2012 Kurichan
2012+
#
2013+
# This program is free software. It comes without any warranty, to
2014+
# the extent permitted by applicable law. You can redistribute it
2015+
# and/or modify it under the terms of the Do What The Fuck You Want
2016+
# To Public License, Version 2, as published by Sam Hocevar. See
2017+
# http://sam.zoy.org/wtfpl/COPYING for more details.
2018+
#-------------------------------------------------------------------
2019+
2020+
2021+
__slots__ = ('fid', 'fix_info', 'var_info', 'mmap')
2022+
2023+
FBIOGET_VSCREENINFO = 0x4600
2024+
FBIOGET_FSCREENINFO = 0x4602
2025+
2026+
class FixScreenInfo(ctypes.Structure):
2027+
2028+
"""The fb_fix_screeninfo from fb.h."""
2029+
2030+
_fields_ = [
2031+
('id_name', ctypes.c_char * 16),
2032+
('smem_start', ctypes.c_ulong),
2033+
('smem_len', ctypes.c_uint32),
2034+
('type', ctypes.c_uint32),
2035+
('type_aux', ctypes.c_uint32),
2036+
('visual', ctypes.c_uint32),
2037+
('xpanstep', ctypes.c_uint16),
2038+
('ypanstep', ctypes.c_uint16),
2039+
('ywrapstep', ctypes.c_uint16),
2040+
('line_length', ctypes.c_uint32),
2041+
('mmio_start', ctypes.c_ulong),
2042+
('mmio_len', ctypes.c_uint32),
2043+
('accel', ctypes.c_uint32),
2044+
('reserved', ctypes.c_uint16 * 3),
2045+
]
2046+
2047+
2048+
class VarScreenInfo(ctypes.Structure):
2049+
2050+
class FbBitField(ctypes.Structure):
2051+
2052+
"""The fb_bitfield struct from fb.h."""
2053+
2054+
_fields_ = [
2055+
('offset', ctypes.c_uint32),
2056+
('length', ctypes.c_uint32),
2057+
('msb_right', ctypes.c_uint32),
2058+
]
2059+
2060+
2061+
"""The fb_var_screeninfo struct from fb.h."""
2062+
2063+
_fields_ = [
2064+
('xres', ctypes.c_uint32),
2065+
('yres', ctypes.c_uint32),
2066+
('xres_virtual', ctypes.c_uint32),
2067+
('yres_virtual', ctypes.c_uint32),
2068+
('xoffset', ctypes.c_uint32),
2069+
('yoffset', ctypes.c_uint32),
2070+
2071+
('bits_per_pixel', ctypes.c_uint32),
2072+
('grayscale', ctypes.c_uint32),
2073+
2074+
('red', FbBitField),
2075+
('green', FbBitField),
2076+
('blue', FbBitField),
2077+
('transp', FbBitField),
2078+
]
2079+
2080+
2081+
def __init__(self, fbdev=None):
2082+
"""Create the FbMem framebuffer memory object."""
2083+
fid = FbMem._open_fbdev(fbdev)
2084+
fix_info = FbMem._get_fix_info(fid)
2085+
fbmmap = FbMem._map_fb_memory(fid, fix_info)
2086+
self.fid = fid
2087+
self.fix_info = fix_info
2088+
self.var_info = FbMem._get_var_info(fid)
2089+
self.mmap = fbmmap
2090+
2091+
2092+
def __del__(self):
2093+
"""Close the FbMem framebuffer memory object."""
2094+
self.mmap.close()
2095+
FbMem._close_fbdev(self.fid)
2096+
2097+
2098+
@staticmethod
2099+
def _open_fbdev(fbdev=None):
2100+
"""Return the framebuffer file descriptor.
2101+
2102+
Try to use the FRAMEBUFFER
2103+
environment variable if fbdev is not given. Use '/dev/fb0' by
2104+
default.
2105+
"""
2106+
dev = fbdev or os.getenv('FRAMEBUFFER', '/dev/fb0')
2107+
fbfid = os.open(dev, os.O_RDWR)
2108+
return fbfid
2109+
2110+
2111+
@staticmethod
2112+
def _close_fbdev(fbfid):
2113+
"""Close the framebuffer file descriptor."""
2114+
os.close(fbfid)
2115+
2116+
2117+
@staticmethod
2118+
def _get_fix_info(fbfid):
2119+
"""Return the fix screen info from the framebuffer file descriptor."""
2120+
fix_info = FbMem.FixScreenInfo()
2121+
fcntl.ioctl(fbfid, FbMem.FBIOGET_FSCREENINFO, fix_info)
2122+
return fix_info
2123+
2124+
2125+
@staticmethod
2126+
def _get_var_info(fbfid):
2127+
"""Return the var screen info from the framebuffer file descriptor."""
2128+
var_info = FbMem.VarScreenInfo()
2129+
fcntl.ioctl(fbfid, FbMem.FBIOGET_VSCREENINFO, var_info)
2130+
return var_info
2131+
2132+
2133+
@staticmethod
2134+
def _map_fb_memory(fbfid, fix_info):
2135+
"""Map the framebuffer memory."""
2136+
return mmap.mmap(
2137+
fbfid,
2138+
fix_info.smem_len,
2139+
mmap.MAP_SHARED,
2140+
mmap.PROT_READ | mmap.PROT_WRITE,
2141+
offset=0
2142+
)
2143+
2144+
class LCD(FbMem):
2145+
"""
2146+
A convenience wrapper for the FbMem class.
2147+
Provides drawing functions from the python imaging library (PIL).
2148+
"""
2149+
2150+
def __init__(self):
2151+
FbMem.__init__(self)
2152+
2153+
def alignup(n, m):
2154+
r = n % m
2155+
if r == 0: return n
2156+
return n - r + m
2157+
2158+
self._img = Image.new("1", (alignup(self.xres, 32), self.yres), "white")
2159+
2160+
self.draw = ImageDraw.Draw(self._img)
2161+
2162+
@property
2163+
def xres(self):
2164+
"""
2165+
Horizontal LCD screen resolution
2166+
"""
2167+
return self.var_info.xres
2168+
2169+
@property
2170+
def yres(self):
2171+
"""
2172+
Vertical LCD screen resolution
2173+
"""
2174+
return self.var_info.yres
2175+
2176+
@property
2177+
def shape(self):
2178+
"""
2179+
Dimensions of the LCD screen.
2180+
"""
2181+
return (self.xres, self.yres)
2182+
2183+
@property
2184+
def draw(self):
2185+
"""
2186+
Returns a handle to PIL.ImageDraw.Draw class associated with LCD.
2187+
Example::
2188+
lcd.draw.rectangle((10,10,60,20), fill='black')
2189+
"""
2190+
return self.draw
2191+
2192+
def clear(self):
2193+
"""
2194+
Clears the LCD screen
2195+
"""
2196+
self.draw.rectangle(((0,0), self.shape), fill="white")
2197+
2198+
def update(self):
2199+
"""
2200+
Applies pending changes to the LCD.
2201+
Nothing will be drawn on the screen until this function is called.
2202+
"""
2203+
self.mmap[:] = self._img.tobytes("raw", "1;IR")
2204+

0 commit comments

Comments
 (0)