27
27
"""
28
28
29
29
import time
30
- import digitalio
30
+ from digitalio import Direction
31
31
import adafruit_framebuf
32
32
from adafruit_epd import mcp_sram
33
33
@@ -50,43 +50,113 @@ def __init__(self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy
50
50
# Setup reset pin, if we have one
51
51
self ._rst = rst_pin
52
52
if rst_pin :
53
- self ._rst .direction = digitalio . Direction .OUTPUT
53
+ self ._rst .direction = Direction .OUTPUT
54
54
55
55
# Setup busy pin, if we have one
56
56
self ._busy = busy_pin
57
57
if busy_pin :
58
- self ._busy .direction = digitalio . Direction .INPUT
58
+ self ._busy .direction = Direction .INPUT
59
59
60
60
# Setup dc pin (required)
61
61
self ._dc = dc_pin
62
- self ._dc .direction = digitalio . Direction .OUTPUT
62
+ self ._dc .direction = Direction .OUTPUT
63
63
self ._dc .value = False
64
64
65
65
# Setup cs pin (required)
66
66
self ._cs = cs_pin
67
- self ._cs .direction = digitalio . Direction .OUTPUT
67
+ self ._cs .direction = Direction .OUTPUT
68
68
self ._cs .value = True
69
69
70
70
# SPI interface (required)
71
71
self .spi_device = spi
72
72
73
+ self .sram = None
73
74
if sramcs_pin :
74
75
self .sram = mcp_sram .Adafruit_MCP_SRAM (sramcs_pin , spi )
76
+
77
+ self ._buffer1_size = self ._buffer2_size = 0
78
+ self ._buffer1 = self ._buffer2 = None
79
+ self .hardware_reset ()
80
+
81
+ def display (self ):
82
+ """show the contents of the display buffer"""
83
+ self .power_up ()
84
+
85
+ self .set_ram_address (0 , 0 )
86
+
87
+ if self .sram :
88
+ while not self .spi_device .try_lock ():
89
+ pass
90
+ self .sram .cs_pin .value = False
91
+ #send read command
92
+ self .spi_device .write (bytearray ([mcp_sram .Adafruit_MCP_SRAM .SRAM_READ ]))
93
+ #send start address
94
+ self .spi_device .write (bytearray ([0x00 , 0x00 ]))
95
+ self .spi_device .unlock ()
96
+
97
+ #first data byte from SRAM will be transfered in at the
98
+ #same time as the EPD command is transferred out
99
+ cmd = self .write_ram (0 )
100
+
101
+ while not self .spi_device .try_lock ():
102
+ pass
103
+ self ._dc .value = True
104
+
105
+ if self .sram :
106
+ xfer = bytearray ([cmd ])
107
+ outbuf = bytearray (1 )
108
+ for _ in range (self ._buffer1_size ):
109
+ outbuf [0 ] = xfer [0 ]
110
+ self .spi_device .write_readinto (outbuf , xfer )
111
+ self .sram .cs_pin .value = True
112
+ else :
113
+ self .spi_device .write (self ._buffer1 )
114
+
115
+ self ._cs .value = True
116
+ self .spi_device .unlock ()
117
+ time .sleep (.002 )
118
+
119
+
120
+ if self .sram :
121
+ while not self .spi_device .try_lock ():
122
+ pass
123
+ self .sram .cs_pin .value = False
124
+ #send read command
125
+ self .spi_device .write (bytearray ([mcp_sram .Adafruit_MCP_SRAM .SRAM_READ ]))
126
+ #send start address
127
+ self .spi_device .write (bytearray ([(self ._buffer1_size >> 8 ), (self ._buffer1_size & 0xFF )]))
128
+ self .spi_device .unlock ()
129
+
130
+ #first data byte from SRAM will be transfered in at the
131
+ #same time as the EPD command is transferred out
132
+ cmd = self .write_ram (1 )
133
+
134
+ while not self .spi_device .try_lock ():
135
+ pass
136
+ self ._dc .value = True
137
+
138
+ if self .sram :
139
+ xfer = bytearray ([cmd ])
140
+ outbuf = bytearray (1 )
141
+ for _ in range (self ._buffer1_size ):
142
+ outbuf [0 ] = xfer [0 ]
143
+ self .spi_device .write_readinto (outbuf , xfer )
144
+ self .sram .cs_pin .value = True
75
145
else :
76
- self .sram = None
77
- self ._bw_buffer = bytearray ((width * height ) // 8 )
78
- self ._red_buffer = bytearray ((width * height ) // 8 )
79
- # since we have *two* framebuffers - one for red and one for black, we dont subclass but manage manually
80
- self ._red_framebuf = adafruit_framebuf .FrameBuffer (self ._red_buffer , width , height , buf_format = adafruit_framebuf .MHMSB )
81
- self ._bw_framebuf = adafruit_framebuf .FrameBuffer (self ._bw_buffer , width , height , buf_format = adafruit_framebuf .MHMSB )
82
-
83
- # if we hav ea reset pin, do a hardware reset
146
+ self .spi_device .write (self ._buffer2 )
147
+
148
+ self ._cs .value = True
149
+ self .spi_device .unlock ()
150
+ self .update ()
151
+
152
+
153
+ def hardware_reset (self ):
154
+ # if we have a reset pin, do a hardware reset
84
155
if self ._rst :
85
156
self ._rst .value = False
86
- time .sleep (.1 )
157
+ time .sleep (0 .1 )
87
158
self ._rst .value = True
88
- time .sleep (.1 )
89
-
159
+ time .sleep (0.1 )
90
160
91
161
def command (self , cmd , data = None , end = True ):
92
162
"""Send command byte to display."""
@@ -100,50 +170,54 @@ def command(self, cmd, data=None, end=True):
100
170
self .spi_device .write_readinto (bytearray ([cmd ]), outbuf )
101
171
102
172
if data is not None :
103
- self .data (data )
104
- else :
105
- self .spi_device .unlock ()
106
-
173
+ self ._dc .value = True
174
+ self .spi_device .write (data )
107
175
if end :
108
176
self ._cs .value = True
177
+ self .spi_device .unlock ()
109
178
110
179
return outbuf [0 ]
111
180
112
- def data (self , dat ):
113
- """Send data to display."""
114
- self ._dc .value = True
115
- self .spi_device .write (dat )
116
- self ._cs .value = True
117
- self .spi_device .unlock ()
181
+
182
+ def pixel (self , x , y , color ):
183
+ """draw a single pixel in the display buffer"""
184
+ self ._framebuf1 .pixel (x , y , (color == Adafruit_EPD .BLACK ) != self .black_invert )
185
+ self ._framebuf2 .pixel (x , y , (color == Adafruit_EPD .RED ) != self .red_invert )
118
186
119
187
def fill (self , color ):
120
- #This should be overridden in the subclass
121
- self ._bw_framebuf .fill ((color == Adafruit_EPD .BLACK ) != self .black_invert )
122
- self ._red_framebuf .fill ((color == Adafruit_EPD .RED ) != self .red_invert )
188
+ """fill the screen with the passed color"""
189
+ red_fill = (color == Adafruit_EPD .RED ) != self .red_invert
190
+ black_fill = (color == Adafruit_EPD .BLACK ) != self .black_invert
191
+ if red_fill :
192
+ red_fill = 0xFF
193
+ if black_fill :
194
+ black_fill = 0xFF
123
195
124
- def pixel (self , x , y , color = None ):
125
- """This should be overridden in the subclass"""
126
- self ._bw_framebuf .pixel (x , y , (color == Adafruit_EPD .BLACK ) != self .black_invert )
127
- self ._red_framebuf .pixel (x , y , (color == Adafruit_EPD .RED ) != self .red_invert )
196
+ if self .sram :
197
+ self .sram .erase (0x00 , self ._buffer1_size , black_fill )
198
+ self .sram .erase (self ._buffer1_size , self ._buffer2_size , red_fill )
199
+ else :
200
+ self ._framebuf1 .fill (black_fill )
201
+ self ._framebuf2 .fill (red_fill )
128
202
129
203
def rect (self , x , y , width , height , color ):
130
204
"""draw a rectangle"""
131
- self ._bw_framebuf .rect (x , y , width , height , (color == Adafruit_EPD .BLACK ) != self .black_invert )
132
- self ._red_framebuf .rect (x , y , width , height , (color == Adafruit_EPD .RED ) != self .red_invert )
205
+ self ._framebuf1 .rect (x , y , width , height , (color == Adafruit_EPD .BLACK ) != self .black_invert )
206
+ self ._framebuf2 .rect (x , y , width , height , (color == Adafruit_EPD .RED ) != self .red_invert )
133
207
134
208
# pylint: disable=too-many-arguments
135
209
def fill_rect (self , x , y , width , height , color ):
136
210
"""fill a rectangle with the passed color"""
137
- self ._bw_framebuf .fill_rect (x , y , width , height , (color == Adafruit_EPD .BLACK ) != self .black_invert )
138
- self ._red_framebuf .fill_rect (x , y , width , height , (color == Adafruit_EPD .RED ) != self .red_invert )
211
+ self ._framebuf1 .fill_rect (x , y , width , height , (color == Adafruit_EPD .BLACK ) != self .black_invert )
212
+ self ._framebuf2 .fill_rect (x , y , width , height , (color == Adafruit_EPD .RED ) != self .red_invert )
139
213
140
214
def line (self , x_0 , y_0 , x_1 , y_1 , color ):
141
- self ._bw_framebuf .line (x_0 , y_0 , x_1 , y_1 , (color == Adafruit_EPD .BLACK ) != self .black_invert )
142
- self ._red_framebuf .line (x_0 , y_0 , x_1 , y_1 , (color == Adafruit_EPD .RED ) != self .red_invert )
215
+ self ._framebuf1 .line (x_0 , y_0 , x_1 , y_1 , (color == Adafruit_EPD .BLACK ) != self .black_invert )
216
+ self ._framebuf2 .line (x_0 , y_0 , x_1 , y_1 , (color == Adafruit_EPD .RED ) != self .red_invert )
143
217
144
218
def text (self , string , x , y , color , * , font_name = "font5x8.bin" ):
145
- self ._bw_framebuf .text (string , x , y , (color == Adafruit_EPD .BLACK ) != self .black_invert , font_name = font_name )
146
- self ._red_framebuf .text (string , x , y , (color == Adafruit_EPD .RED ) != self .red_invert , font_name = font_name )
219
+ self ._framebuf1 .text (string , x , y , (color == Adafruit_EPD .BLACK ) != self .black_invert , font_name = font_name )
220
+ self ._framebuf2 .text (string , x , y , (color == Adafruit_EPD .RED ) != self .red_invert , font_name = font_name )
147
221
148
222
@property
149
223
def width (self ):
@@ -159,12 +233,12 @@ def height(self):
159
233
160
234
@property
161
235
def rotation (self ):
162
- return self ._bw_framebuf ._rotation
236
+ return self ._framebuf1 ._rotation
163
237
164
238
@rotation .setter
165
239
def rotation (self , val ):
166
- self ._bw_framebuf .rotation = val
167
- self ._red_framebuf .rotation = val
240
+ self ._framebuf1 .rotation = val
241
+ self ._framebuf2 .rotation = val
168
242
169
243
def hline (self , x , y , width , color ):
170
244
"""draw a horizontal line"""
@@ -173,3 +247,36 @@ def hline(self, x, y, width, color):
173
247
def vline (self , x , y , height , color ):
174
248
"""draw a vertical line"""
175
249
self .fill_rect (x , y , 1 , height , color )
250
+
251
+
252
+ def image (self , image ):
253
+ """Set buffer to value of Python Imaging Library image. The image should
254
+ be in RGB mode and a size equal to the display size.
255
+ """
256
+ if image .mode != 'RGB' :
257
+ raise ValueError ('Image must be in mode RGB.' )
258
+ imwidth , imheight = image .size
259
+ if imwidth != self .width or imheight != self .height :
260
+ raise ValueError ('Image must be same dimensions as display ({0}x{1}).' \
261
+ .format (self .width , self .height ))
262
+ # Grab all the pixels from the image, faster than getpixel.
263
+ pix = image .load ()
264
+
265
+ for y in iter (range (image .size [1 ])):
266
+ for x in iter (range (image .size [0 ])):
267
+ if x == 0 :
268
+ x = 1
269
+ pixel = pix [x , y ]
270
+
271
+ addr = int (((self ._width - x ) * self ._height + y )/ 8 )
272
+
273
+ if pixel == (0xFF , 0 , 0 ):
274
+ addr = addr + self .bw_bufsize
275
+ current = self .sram .read8 (addr )
276
+
277
+ if pixel in ((0xFF , 0 , 0 ), (0 , 0 , 0 )):
278
+ current = current & ~ (1 << (7 - y % 8 ))
279
+ else :
280
+ current = current | (1 << (7 - y % 8 ))
281
+
282
+ self .sram .write8 (addr , current )
0 commit comments