Skip to content

Screen class not working on ev3dev stretch #423

Closed

Description

@ddemidov

I am getting the following error with the recently released stretch package:

>>> import ev3dev.ev3 as ev3
>>> s = ev3.Screen()
>>> s.clear()
>>> s.update()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3/dist-packages/ev3dev/core.py", line 3320, in update
    self.mmap[:] = self._img.tobytes("raw", "1;IR")
IndexError: mmap slice assignment is wrong size

It seems the same error prevents openrobertalab service from working:

$ journalctl -n 100
Oct 28 10:08:34 ev3dev openrobertalab[1992]: INFO:roberta:--- starting ---
Oct 28 10:08:34 ev3dev openrobertalab[1992]: INFO:roberta.lab:python path: /usr/bin:/usr/lib/python35.zip:/usr/lib/python3.5:/usr/lib/python3.5/plat-arm-linux-gnueabi:/usr/lib/python3.5/lib-
Oct 28 10:08:34 ev3dev openrobertalab[1992]: INFO:roberta.lab:status changed: disconnected
Oct 28 10:08:38 ev3dev openrobertalab[1992]: Traceback (most recent call last):
Oct 28 10:08:38 ev3dev openrobertalab[1992]:   File "/usr/bin/openrobertalab", line 41, in <module>
Oct 28 10:08:38 ev3dev openrobertalab[1992]:     main()
Oct 28 10:08:38 ev3dev openrobertalab[1992]:   File "/usr/bin/openrobertalab", line 36, in main
Oct 28 10:08:38 ev3dev openrobertalab[1992]:     service = Service('/org/openroberta/Lab1')
Oct 28 10:08:38 ev3dev openrobertalab[1992]:   File "/usr/lib/python3/dist-packages/roberta/lab.py", line 88, in __init__
Oct 28 10:08:38 ev3dev openrobertalab[1992]:     self.hal.clearDisplay()
Oct 28 10:08:38 ev3dev openrobertalab[1992]:   File "/usr/lib/python3/dist-packages/roberta/ev3.py", line 179, in clearDisplay
Oct 28 10:08:38 ev3dev openrobertalab[1992]:     self.lcd.update()
Oct 28 10:08:38 ev3dev openrobertalab[1992]:   File "/usr/lib/python3/dist-packages/ev3dev/core.py", line 3320, in update
Oct 28 10:08:38 ev3dev openrobertalab[1992]:     self.mmap[:] = self._img.tobytes("raw", "1;IR")
Oct 28 10:08:38 ev3dev openrobertalab[1992]: IndexError: mmap slice assignment is wrong size
Oct 28 10:08:38 ev3dev openrobertalab[1992]: INFO:roberta:--- done ---

This is on the latest snapshot (snapshot-ev3dev-stretch-ev3-generic-2017-10-24.img.xz). The stretch-compatible ev3dev version is there, since leds are working:

>>> import ev3dev.ev3 as ev3
>>> ev3.Leds.all_off()

Activity

  1. ddemidov commented on Oct 28, 2017

    @ddemidov
    MemberAuthor

    @dlech, were there any changes in framebuffer on stretch? For reference, here is what we currently do:

    class FbMem(object):
    """The framebuffer memory object.
    Made of:
    - the framebuffer file descriptor
    - the fix screen info struct
    - the var screen info struct
    - the mapped memory
    """
    # ------------------------------------------------------------------
    # The code is adapted from
    # https://github.com/LinkCareServices/cairotft/blob/master/cairotft/linuxfb.py
    #
    # The original code came with the following license:
    # ------------------------------------------------------------------
    # Copyright (c) 2012 Kurichan
    #
    # This program is free software. It comes without any warranty, to
    # the extent permitted by applicable law. You can redistribute it
    # and/or modify it under the terms of the Do What The Fuck You Want
    # To Public License, Version 2, as published by Sam Hocevar. See
    # http://sam.zoy.org/wtfpl/COPYING for more details.
    # ------------------------------------------------------------------
    __slots__ = ('fid', 'fix_info', 'var_info', 'mmap')
    FBIOGET_VSCREENINFO = 0x4600
    FBIOGET_FSCREENINFO = 0x4602
    FB_VISUAL_MONO01 = 0
    FB_VISUAL_MONO10 = 1
    class FixScreenInfo(ctypes.Structure):
    """The fb_fix_screeninfo from fb.h."""
    _fields_ = [
    ('id_name', ctypes.c_char * 16),
    ('smem_start', ctypes.c_ulong),
    ('smem_len', ctypes.c_uint32),
    ('type', ctypes.c_uint32),
    ('type_aux', ctypes.c_uint32),
    ('visual', ctypes.c_uint32),
    ('xpanstep', ctypes.c_uint16),
    ('ypanstep', ctypes.c_uint16),
    ('ywrapstep', ctypes.c_uint16),
    ('line_length', ctypes.c_uint32),
    ('mmio_start', ctypes.c_ulong),
    ('mmio_len', ctypes.c_uint32),
    ('accel', ctypes.c_uint32),
    ('reserved', ctypes.c_uint16 * 3),
    ]
    class VarScreenInfo(ctypes.Structure):
    class FbBitField(ctypes.Structure):
    """The fb_bitfield struct from fb.h."""
    _fields_ = [
    ('offset', ctypes.c_uint32),
    ('length', ctypes.c_uint32),
    ('msb_right', ctypes.c_uint32),
    ]
    """The fb_var_screeninfo struct from fb.h."""
    _fields_ = [
    ('xres', ctypes.c_uint32),
    ('yres', ctypes.c_uint32),
    ('xres_virtual', ctypes.c_uint32),
    ('yres_virtual', ctypes.c_uint32),
    ('xoffset', ctypes.c_uint32),
    ('yoffset', ctypes.c_uint32),
    ('bits_per_pixel', ctypes.c_uint32),
    ('grayscale', ctypes.c_uint32),
    ('red', FbBitField),
    ('green', FbBitField),
    ('blue', FbBitField),
    ('transp', FbBitField),
    ]
    def __init__(self, fbdev=None):
    """Create the FbMem framebuffer memory object."""
    fid = FbMem._open_fbdev(fbdev)
    fix_info = FbMem._get_fix_info(fid)
    fbmmap = FbMem._map_fb_memory(fid, fix_info)
    self.fid = fid
    self.fix_info = fix_info
    self.var_info = FbMem._get_var_info(fid)
    self.mmap = fbmmap
    def __del__(self):
    """Close the FbMem framebuffer memory object."""
    self.mmap.close()
    FbMem._close_fbdev(self.fid)
    @staticmethod
    def _open_fbdev(fbdev=None):
    """Return the framebuffer file descriptor.
    Try to use the FRAMEBUFFER
    environment variable if fbdev is not given. Use '/dev/fb0' by
    default.
    """
    dev = fbdev or os.getenv('FRAMEBUFFER', '/dev/fb0')
    fbfid = os.open(dev, os.O_RDWR)
    return fbfid
    @staticmethod
    def _close_fbdev(fbfid):
    """Close the framebuffer file descriptor."""
    os.close(fbfid)
    @staticmethod
    def _get_fix_info(fbfid):
    """Return the fix screen info from the framebuffer file descriptor."""
    fix_info = FbMem.FixScreenInfo()
    fcntl.ioctl(fbfid, FbMem.FBIOGET_FSCREENINFO, fix_info)
    return fix_info
    @staticmethod
    def _get_var_info(fbfid):
    """Return the var screen info from the framebuffer file descriptor."""
    var_info = FbMem.VarScreenInfo()
    fcntl.ioctl(fbfid, FbMem.FBIOGET_VSCREENINFO, var_info)
    return var_info
    @staticmethod
    def _map_fb_memory(fbfid, fix_info):
    """Map the framebuffer memory."""
    return mmap.mmap(
    fbfid,
    fix_info.smem_len,
    mmap.MAP_SHARED,
    mmap.PROT_READ | mmap.PROT_WRITE,
    offset=0
    )

  2. dlech commented on Oct 28, 2017

    @dlech
    Member

    There is now 2bpp support in the driver, so fix_info.smem_len is probably twice as big as it was previously.

    Could you change

    self.mmap[:] = self._img.tobytes("raw", "1;IR")
    

    to

    b = self._img.tobytes("raw", "1;IR")
    self.mmap[:len(b)] = b
    

    ?

  3. ddemidov commented on Oct 28, 2017

    @ddemidov
    MemberAuthor

    That works, although I had to invert the image (or rather stop inverting it, by using "1;R" instead of "1;IR").
    The following patch works for me:

    diff --git a/ev3dev/core.py b/ev3dev/core.py
    index 0dd29ca..72d0f41 100644
    --- a/ev3dev/core.py
    +++ b/ev3dev/core.py
    @@ -3317,7 +3317,8 @@ class Screen(FbMem):
             Nothing will be drawn on the screen until this function is called.
             """
             if self.var_info.bits_per_pixel == 1:
    -            self.mmap[:] = self._img.tobytes("raw", "1;IR")
    +            b = self._img.tobytes("raw", "1;R")
    +            self.mmap[:len(b)] = b
             elif self.var_info.bits_per_pixel == 16:
                 self.mmap[:] = self._img_to_rgb565_bytes()
             else:

    I am bit surprised by the result though. tobytes("raw", "1;R") should give us raw 1-bit-per-pixel image. Why assigning the result to a 2-bit-per-pixel framebuffer works?

  4. dlech commented on Oct 28, 2017

    @dlech
    Member

    The fbdev device has two modes of operation, 1bpp and 2bpp. Be default, it still operates in 1bpp mode. The memory allocated has to be big enough for both modes, so the 1bpp mode only uses 1/2 of the allocated memory.

  5. ddemidov commented on Oct 28, 2017

    @ddemidov
    MemberAuthor

    Ok, that makes sense. I'll create PRs for stretch-stable and develop then.

  6. dlech commented on Oct 28, 2017

    @dlech
    Member

    I'm wondering about the inversion though. I don't recall switching from FB_VISUAL_MONO10 to FB_VISUAL_MONO01 but maybe I did.

  7. ddemidov commented on Oct 28, 2017

    @ddemidov
    MemberAuthor

    Do you need more info from me on this? The EV3 is next to me right now.

  8. dlech commented on Oct 28, 2017

    @dlech
    Member

    The driver still says FB_VISUAL_MONO10, so I would expect that the inversion is still needed.

    https://github.com/ev3dev/lego-linux-drivers/blob/ev3dev-stretch/linux/fbdev/st7586fb.c#L483

  9. ddemidov commented on Oct 28, 2017

    @ddemidov
    MemberAuthor

    Well, without the inversion s.clear() gives me black screen, and s.draw.rectangle((10,10,168,118)) gives me a white-on-black rectangle.

  10. added a commit that references this issue on Oct 28, 2017
  11. dlech commented on Oct 28, 2017

    @dlech
    Member

    self._draw.rectangle(((0, 0), self.shape), fill="white")

    says clear should fill with white, not black

  12. ddemidov commented on Oct 28, 2017

    @ddemidov
    MemberAuthor

    I believe that is because we had to do inversion.

  13. ddemidov commented on Oct 29, 2017

    @ddemidov
    MemberAuthor

    Fixed by #424 (develop, aka v2) and #425 (stretch-stable, aka v1). Also pushed the updated packages for the stretch-stable version.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions