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

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
ropod7
Posts: 6
Joined: Mon Feb 29, 2016 7:01 pm

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

Post by ropod7 » Mon Feb 29, 2016 7:21 pm

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 34015 times

ropod7
Posts: 6
Joined: Mon Feb 29, 2016 7:01 pm

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

Post by ropod7 » Mon Feb 29, 2016 9:15 pm

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

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

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

Post by pythoncoder » Tue Mar 01, 2016 7:07 am

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)
Peter Hinch
Index to my micropython libraries.

ropod7
Posts: 6
Joined: Mon Feb 29, 2016 7:01 pm

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

Post by ropod7 » Tue Mar 01, 2016 8:12 am

Thanks!
I will try it this evening.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

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

Post by Roberthh » Tue Mar 01, 2016 10:48 am

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.

SpotlightKid
Posts: 463
Joined: Wed Apr 08, 2015 5:19 am

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

Post by SpotlightKid » Tue Mar 01, 2016 3:04 pm

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']

ropod7
Posts: 6
Joined: Mon Feb 29, 2016 7:01 pm

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

Post by ropod7 » Tue Mar 01, 2016 10:57 pm

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!

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

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

Post by Roberthh » Wed Mar 02, 2016 6:19 am

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.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

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

Post by pythoncoder » Wed Mar 02, 2016 6:32 am

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
Peter Hinch
Index to my micropython libraries.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

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

Post by Roberthh » Wed Mar 02, 2016 8:04 am

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)

Post Reply