1+ # Old (non-viper) e-ink send functions
2+ # Replaced with viper as of 21 Feb 2025
3+
4+ # Send with landscape rotation
5+ # Slow (2.5s) without Viper. Also doesn't support rot3.
6+ def _send_land (self ):
7+
8+ if self .rot == 3 :
9+ raise NotImplementedError ('Rotation #3 not implemented yet' )
10+ return
11+
12+ # Output commands
13+ cmd = bytes ([ 0x10 , 0x13 ])
14+
15+ # Temporary store for byte values. Avoids repeated in-loop memory allocation.
16+ out = bytearray (1 )
17+
18+ # For speed, cache locally all global variables that we'll need in the loop
19+ fb = self .fb .buf
20+ spi_w = self .spi .write
21+
22+ # Input byte width, input height
23+ ibw = self .width // 4
24+ ih = self .height
25+
26+ # Having these as elements of a bytearray makes things worse, for some reason
27+ col = 0
28+ bit = 0
29+
30+ # Set these up ahead of time
31+ rx = range (self .width )
32+ r1 = range (ibw )
33+ r2 = range (4 )
34+ ry = range ( 0 , ih , 8 )
35+
36+ # Do everything once per colour
37+ for c in (0 ,1 ):
38+
39+ # Send data command (black/red)
40+ self ._send_command ( cmd [c ] )
41+
42+ # Prepare for transmission
43+ self .DC (1 )
44+ self .CS (0 )
45+
46+ '''
47+ Input is always in rows of bytes
48+ Each byte is 4 pixels (2 bits per pixel)
49+ 1-byte columns of the input image will be 4 pixels wide
50+ These columns will correspond to rows of the output image
51+ '''
52+
53+ '''
54+ # Go column by column over the source image
55+ for x in rx:
56+
57+ # Split x into the byte-column we're in (col) and the pixel within that (bit)
58+ # col = x // 4
59+ col = x>>2
60+
61+ # Convert bit from pixel position to bit position
62+ # bit = ( (x % 4 ) *2 ) +c
63+ bit = ((x&3)<<1)|c
64+
65+ # Go up the columns, 8 rows at a time
66+ for y in ry:
67+ out[0] = (
68+ ((( fb[ (ibw*(ih-y-1)) + col ] & (1<<bit) ) >> bit )<<7) |
69+ ((( fb[ (ibw*(ih-y-2)) + col ] & (1<<bit) ) >> bit )<<6) |
70+ ((( fb[ (ibw*(ih-y-3)) + col ] & (1<<bit) ) >> bit )<<5) |
71+ ((( fb[ (ibw*(ih-y-4)) + col ] & (1<<bit) ) >> bit )<<4) |
72+ ((( fb[ (ibw*(ih-y-5)) + col ] & (1<<bit) ) >> bit )<<3) |
73+ ((( fb[ (ibw*(ih-y-6)) + col ] & (1<<bit) ) >> bit )<<2) |
74+ ((( fb[ (ibw*(ih-y-7)) + col ] & (1<<bit) ) >> bit )<<1) |
75+ ((( fb[ (ibw*(ih-y-8)) + col ] & (1<<bit) ) >> bit ) )
76+ )
77+ spi_w( out )
78+ '''
79+
80+ # Input image, columns of 4 pixels, aka columns of bytes
81+ for col in r1 :
82+
83+ # Input image, columns of single pixels
84+ for incol in r2 :
85+
86+ # Select which bit from each byte we'll need
87+ #bit = (incol*2) +c
88+ bit = (incol << 1 ) | c
89+
90+ # Input image, every 8th row is the start of an output byte
91+ for y in ry :
92+
93+ # Select from framebuffer:
94+ # ( Input byte width * row of interest ) + column offset
95+ # AND with 2^bit
96+ # RSHIFT back down to zero or 1
97+ # LSHIFT to correct position within output byte
98+ # OR all 8 together
99+ out [0 ] = (
100+ ((( fb [ (ibw * (ih - y - 1 )) + col ] & (1 << bit ) ) >> bit )<< 7 ) |
101+ ((( fb [ (ibw * (ih - y - 2 )) + col ] & (1 << bit ) ) >> bit )<< 6 ) |
102+ ((( fb [ (ibw * (ih - y - 3 )) + col ] & (1 << bit ) ) >> bit )<< 5 ) |
103+ ((( fb [ (ibw * (ih - y - 4 )) + col ] & (1 << bit ) ) >> bit )<< 4 ) |
104+ ((( fb [ (ibw * (ih - y - 5 )) + col ] & (1 << bit ) ) >> bit )<< 3 ) |
105+ ((( fb [ (ibw * (ih - y - 6 )) + col ] & (1 << bit ) ) >> bit )<< 2 ) |
106+ ((( fb [ (ibw * (ih - y - 7 )) + col ] & (1 << bit ) ) >> bit )<< 1 ) |
107+ ((( fb [ (ibw * (ih - y - 8 )) + col ] & (1 << bit ) ) >> bit ) )
108+ )
109+ spi_w ( out )
110+
111+
112+ # End transmission
113+ self .CS (1 )
114+
115+ # Tidy up memory
116+ del cmd , out , fb , spi_w
117+ #del ibw, ih, c, col, incol, bit, row
118+ #del ibw, ih, c, col, x
119+ gc .collect ()
120+
121+ # Send with portrait rotation
122+ @micropython .native
123+ def _send_port (self ):
124+
125+ # How to locate a 2-bit pixel in the buffer for a given rotation
126+ '''
127+ buflen = len(self.fb.buf)
128+ locator = [
129+ # ( self.fb.buf[ (i*2) + (j//4) ] >> ((j%4)*2 ) ) & 3
130+ lambda i, j : ( self.fb.buf[ (i<<1) + (j>>2) ] >> ((j&3)<<1) ) & 3, # Zero rotation (portrait)
131+ lambda i, j : 0,
132+ lambda i, j : ( self.fb.buf[ buflen-(i<<1)-(j>>2)-1 ] >> ((3-(j&3))<<1) ) & 3, # 180,
133+ lambda i, j : 0,
134+ ][self.rot]
135+ '''
136+
137+ # Output commands
138+ cmd = bytes ([ 0x10 , 0x13 ])
139+
140+ # Temporary store for byte values. Avoids repeated in-loop memory allocation.
141+ out = bytearray (1 )
142+
143+ # For speed, cache locally all global variables that we'll need in the loop
144+ fb = self .fb .buf
145+ spi_w = self .spi .write
146+
147+ # Range object and byte decoders for loop
148+ if self .rot == 0 :
149+ r = range ( 0 , self .kr_fb_size * 2 , 2 )
150+ nybble = [
151+ lambda b : (b & 64 )>> 6 | (b & 16 )>> 3 | (b & 4 ) | (b & 1 )<< 3 , # black
152+ lambda b : (b & 128 )>> 7 | (b & 32 )>> 4 | (b & 8 )>> 1 | (b & 2 )<< 2 , # red
153+ ]
154+ ob = lambda i , n : ( n ( fb [i ] ) << 4 ) | ( n ( fb [i + 1 ] ) ) # Output byte
155+ elif self .rot == 2 :
156+ r = range ( self .kr_fb_size * 2 - 1 , - 1 , - 2 )
157+ nybble = [
158+ lambda b : (b & 64 )>> 3 | (b & 16 )>> 2 | (b & 4 )>> 1 | (b & 1 ), # black
159+ lambda b : (b & 128 )>> 4 | (b & 32 )>> 3 | (b & 8 )>> 2 | (b & 2 )>> 1 , # red
160+ ]
161+ ob = lambda i , n : ( n ( fb [i ] ) << 4 ) | ( n ( fb [i - 1 ] ) ) # Output byte
162+ else :
163+ raise NotImplementedError ('Landscape modes not supported yet' )
164+
165+ # Do once per colour
166+ for c in (1 ,2 ):
167+
168+ # Send data command (black/red)
169+ self ._send_command ( cmd [c - 1 ] )
170+
171+ # Prepare for transmission
172+ self .DC (1 )
173+ self .CS (0 )
174+
175+ # Which nybble do we need?
176+ n = nybble [c - 1 ]
177+
178+ # Step through each byte of the (red or black) output
179+ for i in r :
180+
181+ # Get two nybbles and compose them into one byte for monochrome output
182+ #print(
183+ out [0 ] = ob ( i , n )
184+ #print(hex(out[0]))
185+ #print( nybble[1]( self.fb.buf[2*i] ) << 4 )
186+ #print( nybble[1]( self.fb.buf[(2*i)+1] ) )
187+ #return
188+
189+ # Send the byte
190+ spi_w ( out )
191+
192+ # End transmission
193+ self .CS (1 )
194+
0 commit comments