Page 1 of 2

Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Mon Feb 29, 2016 7:21 pm
by ropod7
Hello,
How can I realize that feature without double step slicing? Have you in TODO list full slicing realization in future?

I am working with ILI9341 (240x320) TFT LCD and for BMP image rendering I must have something fast as it.

I am changing now step by step MSB to LSB by f.read(1) function - it is too slow.

Code: Select all

with open(path + filename, 'rb') as f:
        f.seek(138)	# start colormap byte in BMP image
        while True:
            MSB = ord(f.read(1))
            LSB = ord(f.read(1))
            data = struct.pack('BB', LSB, MSB)
            lcd_write_data(data)
rendered.png
rendered.png (192.33 KiB) Viewed 34246 times

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Mon Feb 29, 2016 9:15 pm
by ropod7
It is solved by my self.

Code: Select all

with open(path + filename, 'rb') as f:
        f.seek(138)
        while True:
            try:
                data = f.read(500)
                data = struct.unpack('<{0}H'.format(len(data)//2), data)
                data = struct.pack('>{0}H'.format(len(data)), *data)
                lcd_write_data(data)
            except OSError: break
I am still working on it.
[youtube]kFkMaDZJvlA[/youtube]

https://www.youtube.com/watch?v=kFkMaDZJvlA

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Tue Mar 01, 2016 7:07 am
by pythoncoder
Ingenious! You might like to try this, which might be faster:

Code: Select all

@micropython.asm_thumb
def reverse(r0, r1):               # bytearray, len(bytearray)
    add(r4, r0, r1)
    sub(r4, 1) # end address
    label(LOOP)
    ldrb(r5, [r0, 0])
    ldrb(r6, [r4, 0])
    strb(r6, [r0, 0])
    strb(r5, [r4, 0])
    add(r0, 1)
    sub(r4, 1)
    cmp(r4, r0)
    bpl(LOOP)
   
def test():
    a = bytearray([0, 1, 2, 3]) # even length
    reverse(a, len(a))
    print(a)
    a = bytearray([0, 1, 2, 3, 4]) # odd length
    reverse(a, len(a))
    print(a)

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Tue Mar 01, 2016 8:12 am
by ropod7
Thanks!
I will try it this evening.

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Tue Mar 01, 2016 10:48 am
by Roberthh
Hello all. The code provided by @pythoncoder seems to reverse the whole string, which is what the title seems to request. But I guess, that a pairwise swap was needed to cater the arrangements of color bits of the display vs. data file. That's what the first post did. The usual small/big endian problem. I ran into than problem once. Nevertheless, this reverse should work if the buffer length is equal to twice the display width. In that case, the whole picture will be mirrored with the right colors.
But as a side effect, it's a good hint that a BMP in 16 bit color mode contains 565 encoded raw data starting at position 138.

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Tue Mar 01, 2016 3:04 pm
by SpotlightKid
On CPython you could also use the array module:

Code: Select all

>>> import array
>>> a = array.array('H', [1,2,3])
>>> a.tobytes()
b'\x01\x00\x02\x00\x03\x00'
>>> a.byteswap()
>>> a.tobytes()
b'\x00\x01\x00\x02\x00\x03'
Unfortunately, byteswap isn't implemented on MicroPython:

Code: Select all

>>> import array
>>> a = array.array('H', [1,2,3])
>>> dir(a)
['append', 'extend']

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Tue Mar 01, 2016 10:57 pm
by ropod7
pythoncoder
It is working well in test function, but for close realization at image rendering I must understand ASM. :( I wish to understand.
I am tryed to play with "end address", code gave me some acceleration, but bitmap renders too bad and colormap was not as in image.
I will try to find some assembler theory.

SpotlightKid
a = array.array('H', [1,2,3])
that's good idea, it gave me few hundered millis per image.

Thank you all!

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Wed Mar 02, 2016 6:19 am
by Roberthh
Hello ropod7, in your main program, you should try a read of 480 instead of 500, or 640, depending which way the image is built up. As mentioned above, the assembler function reverses the whole buffer, not each byte pair in the buffer, while leaving the sequences intact.
Alternatively, try this version of reverse. In my test, it worked with a bmp file and a TFT display

Code: Select all

@micropython.asm_thumb
def reverse(r0, r1):               # bytearray, len(bytearray)

    b(loopend)

    label(loopstart)
    ldrb(r2, [r0, 0])
    ldrb(r3, [r0, 1])
    strb(r3, [r0, 0])
    strb(r2, [r0, 1])
    add(r0, 2)

    label(loopend)
    sub (r1, 2)  # End of loop?
    bpl(loopstart)
Looking at your video, I guess that most of the time is needed for sending the data to the display, assuming that you are using the serial interface.

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Wed Mar 02, 2016 6:32 am
by pythoncoder
OK, try this:

Code: Select all

@micropython.asm_thumb
def byteswap(r0, r1):               # bytearray, len(bytearray)
    mov(r3, 2)
    lsr(r1, r3) # divide len by 4
    mov(r4, r0)
    add(r4, 1) # dest address
    label(LOOP)
    ldrb(r5, [r0, 0])
    ldrb(r6, [r4, 0])
    strb(r6, [r0, 0])
    strb(r5, [r4, 0])
    add(r0, 2)
    add(r4, 2)
    sub(r1, 1)
    bpl(LOOP)
   
def test():
    a = bytearray([0, 1, 2, 3]) # even length
    byteswap(a, len(a))
    print(a)
    a = bytearray([0, 1, 2, 3, 4]) # odd length (to prove it doesn't do anything daft)
    byteswap(a, len(a))
    print(a)
If you want to learn Assembler - and it's good for display code where speed is vital - it is documented here http://docs.micropython.org/en/latest/p ... mbler.html and here http://docs.micropython.org/en/latest/r ... index.html

Re: Revers strings in micropython (NotImplementedError with slices as [::-1])

Posted: Wed Mar 02, 2016 8:04 am
by Roberthh
Hi @pythoncoder, besides the fact, that I should have called my function byteswap, like you did, it seems to me that your code is wrong. You increment the data pointers by two in each loop, but divide the buffer length value by 4, which means that only half of the buffer is processed.
Robert (alias Statler)