11/* !
2- * @file Adafruit_MonoOLED .cpp
2+ * @file Adafruit_GrayOLED .cpp
33 *
4- * This is documentation for Adafruit's generic library for monochrome
4+ * This is documentation for Adafruit's generic library for grayscale
55 * OLED displays: http://www.adafruit.com/category/63_98
66 *
77 * These displays use I2C or SPI to communicate. I2C requires 2 pins
1717
1818#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all
1919
20- #include " Adafruit_MonoOLED .h"
20+ #include " Adafruit_GrayOLED .h"
2121#include < Adafruit_GFX.h>
2222
2323// SOME DEFINES AND STATIC VARIABLES USED INTERNALLY -----------------------
2424
25- #define monooled_swap (a, b ) \
25+ #define grayoled_swap (a, b ) \
2626 (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) // /< No-temp-var swap operation
2727
2828// CONSTRUCTORS, DESTRUCTOR ------------------------------------------------
2929
3030/* !
3131 @brief Constructor for I2C-interfaced OLED displays.
32+ @param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
3233 @param w
3334 Display width in pixels
3435 @param h
5960 @note Call the object's begin() function before use -- buffer
6061 allocation is performed there!
6162*/
62- Adafruit_MonoOLED::Adafruit_MonoOLED ( uint16_t w , uint16_t h, TwoWire *twi ,
63- int8_t rst_pin, uint32_t clkDuring ,
64- uint32_t clkAfter)
63+ Adafruit_GrayOLED::Adafruit_GrayOLED ( uint8_t bpp , uint16_t w, uint16_t h ,
64+ TwoWire *twi, int8_t rst_pin ,
65+ uint32_t clkDuring, uint32_t clkAfter)
6566 : Adafruit_GFX(w, h), i2c_preclk(clkDuring), i2c_postclk(clkAfter),
66- buffer(NULL ), dcPin(-1 ), csPin(-1 ), rstPin(rst_pin) {
67+ buffer(NULL ), dcPin(-1 ), csPin(-1 ), rstPin(rst_pin), _bpp(bpp) {
6768 i2c_dev = NULL ;
6869 _theWire = twi;
6970}
7071
7172/* !
72- @brief Constructor for SPI MonoOLED displays, using software (bitbang)
73+ @brief Constructor for SPI GrayOLED displays, using software (bitbang)
7374 SPI.
75+ @param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
7476 @param w
7577 Display width in pixels
7678 @param h
@@ -94,16 +96,19 @@ Adafruit_MonoOLED::Adafruit_MonoOLED(uint16_t w, uint16_t h, TwoWire *twi,
9496 @note Call the object's begin() function before use -- buffer
9597 allocation is performed there!
9698*/
97- Adafruit_MonoOLED::Adafruit_MonoOLED (uint16_t w, uint16_t h, int8_t mosi_pin,
98- int8_t sclk_pin, int8_t dc_pin,
99- int8_t rst_pin, int8_t cs_pin)
100- : Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin) {
99+ Adafruit_GrayOLED::Adafruit_GrayOLED (uint8_t bpp, uint16_t w, uint16_t h,
100+ int8_t mosi_pin, int8_t sclk_pin,
101+ int8_t dc_pin, int8_t rst_pin,
102+ int8_t cs_pin)
103+ : Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin),
104+ _bpp(bpp) {
101105
102106 spi_dev = new Adafruit_SPIDevice (cs_pin, sclk_pin, -1 , mosi_pin, 1000000 );
103107}
104108
105109/* !
106- @brief Constructor for SPI MonoOLED displays, using native hardware SPI.
110+ @brief Constructor for SPI GrayOLED displays, using native hardware SPI.
111+ @param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
107112 @param w
108113 Display width in pixels
109114 @param h
@@ -127,19 +132,21 @@ Adafruit_MonoOLED::Adafruit_MonoOLED(uint16_t w, uint16_t h, int8_t mosi_pin,
127132 @note Call the object's begin() function before use -- buffer
128133 allocation is performed there!
129134*/
130- Adafruit_MonoOLED::Adafruit_MonoOLED (uint16_t w, uint16_t h, SPIClass *spi,
131- int8_t dc_pin, int8_t rst_pin,
132- int8_t cs_pin, uint32_t bitrate)
133- : Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin) {
135+ Adafruit_GrayOLED::Adafruit_GrayOLED (uint8_t bpp, uint16_t w, uint16_t h,
136+ SPIClass *spi, int8_t dc_pin,
137+ int8_t rst_pin, int8_t cs_pin,
138+ uint32_t bitrate)
139+ : Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin),
140+ _bpp(bpp) {
134141
135142 spi_dev = new Adafruit_SPIDevice (cs_pin, bitrate, SPI_BITORDER_MSBFIRST,
136143 SPI_MODE0, spi);
137144}
138145
139146/* !
140- @brief Destructor for Adafruit_MonoOLED object.
147+ @brief Destructor for Adafruit_GrayOLED object.
141148*/
142- Adafruit_MonoOLED ::~Adafruit_MonoOLED (void ) {
149+ Adafruit_GrayOLED ::~Adafruit_GrayOLED (void ) {
143150 if (buffer) {
144151 free (buffer);
145152 buffer = NULL ;
@@ -157,7 +164,7 @@ Adafruit_MonoOLED::~Adafruit_MonoOLED(void) {
157164 needed.
158165 @param c The single byte command
159166*/
160- void Adafruit_MonoOLED ::oled_command (uint8_t c) {
167+ void Adafruit_GrayOLED ::oled_command (uint8_t c) {
161168 if (i2c_dev) { // I2C
162169 uint8_t buf[2 ] = {0x00 , c}; // Co = 0, D/C = 0
163170 i2c_dev->write (buf, 2 );
@@ -167,7 +174,7 @@ void Adafruit_MonoOLED::oled_command(uint8_t c) {
167174 }
168175}
169176
170- // Issue list of commands to MonoOLED
177+ // Issue list of commands to GrayOLED
171178/* !
172179 @brief Issue multiple bytes of commands OLED, using I2C or hard/soft SPI as
173180 needed.
@@ -176,7 +183,7 @@ void Adafruit_MonoOLED::oled_command(uint8_t c) {
176183 @returns True for success on ability to write the data in I2C.
177184*/
178185
179- bool Adafruit_MonoOLED ::oled_commandList (const uint8_t *c, uint8_t n) {
186+ bool Adafruit_GrayOLED ::oled_commandList (const uint8_t *c, uint8_t n) {
180187 if (i2c_dev) { // I2C
181188 uint8_t dc_byte = 0x00 ; // Co = 0, D/C = 0
182189 if (!i2c_dev->write ((uint8_t *)c, n, true , &dc_byte, 1 )) {
@@ -213,10 +220,11 @@ bool Adafruit_MonoOLED::oled_commandList(const uint8_t *c, uint8_t n) {
213220 proceeding.
214221 @note MUST call this function before any drawing or updates!
215222*/
216- bool Adafruit_MonoOLED ::_init (uint8_t addr, bool reset) {
223+ bool Adafruit_GrayOLED ::_init (uint8_t addr, bool reset) {
217224
218225 // attempt to malloc the bitmap framebuffer
219- if ((!buffer) && !(buffer = (uint8_t *)malloc (WIDTH * ((HEIGHT + 7 ) / 8 )))) {
226+ if ((!buffer) &&
227+ !(buffer = (uint8_t *)malloc (_bpp * WIDTH * ((HEIGHT + 7 ) / 8 )))) {
220228 return false ;
221229 }
222230
@@ -269,25 +277,24 @@ bool Adafruit_MonoOLED::_init(uint8_t addr, bool reset) {
269277 @param color
270278 Pixel color, one of: MONOOLED_BLACK, MONOOLED_WHITE or
271279 MONOOLED_INVERT.
272- @return None (void).
273280 @note Changes buffer contents only, no immediate effect on display.
274281 Follow up with a call to display(), or with other graphics
275282 commands as needed by one's own application.
276283*/
277- void Adafruit_MonoOLED ::drawPixel (int16_t x, int16_t y, uint16_t color) {
284+ void Adafruit_GrayOLED ::drawPixel (int16_t x, int16_t y, uint16_t color) {
278285 if ((x >= 0 ) && (x < width ()) && (y >= 0 ) && (y < height ())) {
279286 // Pixel is in-bounds. Rotate coordinates if needed.
280287 switch (getRotation ()) {
281288 case 1 :
282- monooled_swap (x, y);
289+ grayoled_swap (x, y);
283290 x = WIDTH - x - 1 ;
284291 break ;
285292 case 2 :
286293 x = WIDTH - x - 1 ;
287294 y = HEIGHT - y - 1 ;
288295 break ;
289296 case 3 :
290- monooled_swap (x, y);
297+ grayoled_swap (x, y);
291298 y = HEIGHT - y - 1 ;
292299 break ;
293300 }
@@ -298,29 +305,43 @@ void Adafruit_MonoOLED::drawPixel(int16_t x, int16_t y, uint16_t color) {
298305 window_x2 = max (window_x2, x);
299306 window_y2 = max (window_y2, y);
300307
301- switch (color) {
302- case MONOOLED_WHITE:
303- buffer[x + (y / 8 ) * WIDTH] |= (1 << (y & 7 ));
304- break ;
305- case MONOOLED_BLACK:
306- buffer[x + (y / 8 ) * WIDTH] &= ~(1 << (y & 7 ));
307- break ;
308- case MONOOLED_INVERSE:
309- buffer[x + (y / 8 ) * WIDTH] ^= (1 << (y & 7 ));
310- break ;
308+ if (_bpp == 1 ) {
309+ switch (color) {
310+ case MONOOLED_WHITE:
311+ buffer[x + (y / 8 ) * WIDTH] |= (1 << (y & 7 ));
312+ break ;
313+ case MONOOLED_BLACK:
314+ buffer[x + (y / 8 ) * WIDTH] &= ~(1 << (y & 7 ));
315+ break ;
316+ case MONOOLED_INVERSE:
317+ buffer[x + (y / 8 ) * WIDTH] ^= (1 << (y & 7 ));
318+ break ;
319+ }
320+ }
321+ if (_bpp == 4 ) {
322+ uint8_t *pixelptr = &buffer[x / 2 + (y * WIDTH / 2 )];
323+ // Serial.printf("(%d, %d) -> offset %d\n", x, y, x/2 + (y * WIDTH / 2));
324+ if (x % 2 == 0 ) { // even, left nibble
325+ uint8_t t = pixelptr[0 ] & 0x0F ;
326+ t |= (color & 0xF ) << 4 ;
327+ pixelptr[0 ] = t;
328+ } else { // odd, right lower nibble
329+ uint8_t t = pixelptr[0 ] & 0xF0 ;
330+ t |= color & 0xF ;
331+ pixelptr[0 ] = t;
332+ }
311333 }
312334 }
313335}
314336
315337/* !
316338 @brief Clear contents of display buffer (set all pixels to off).
317- @return None (void).
318339 @note Changes buffer contents only, no immediate effect on display.
319340 Follow up with a call to display(), or with other graphics
320341 commands as needed by one's own application.
321342*/
322- void Adafruit_MonoOLED ::clearDisplay (void ) {
323- memset (buffer, 0 , WIDTH * ((HEIGHT + 7 ) / 8 ));
343+ void Adafruit_GrayOLED ::clearDisplay (void ) {
344+ memset (buffer, 0 , _bpp * WIDTH * ((HEIGHT + 7 ) / 8 ));
324345 // set max dirty window
325346 window_x1 = 0 ;
326347 window_y1 = 0 ;
@@ -339,20 +360,20 @@ void Adafruit_MonoOLED::clearDisplay(void) {
339360 @note Reads from buffer contents; may not reflect current contents of
340361 screen if display() has not been called.
341362*/
342- bool Adafruit_MonoOLED ::getPixel (int16_t x, int16_t y) {
363+ bool Adafruit_GrayOLED ::getPixel (int16_t x, int16_t y) {
343364 if ((x >= 0 ) && (x < width ()) && (y >= 0 ) && (y < height ())) {
344365 // Pixel is in-bounds. Rotate coordinates if needed.
345366 switch (getRotation ()) {
346367 case 1 :
347- monooled_swap (x, y);
368+ grayoled_swap (x, y);
348369 x = WIDTH - x - 1 ;
349370 break ;
350371 case 2 :
351372 x = WIDTH - x - 1 ;
352373 y = HEIGHT - y - 1 ;
353374 break ;
354375 case 3 :
355- monooled_swap (x, y);
376+ grayoled_swap (x, y);
356377 y = HEIGHT - y - 1 ;
357378 break ;
358379 }
@@ -366,7 +387,7 @@ bool Adafruit_MonoOLED::getPixel(int16_t x, int16_t y) {
366387 @return Pointer to an unsigned 8-bit array, column-major, columns padded
367388 to full byte boundary if needed.
368389*/
369- uint8_t *Adafruit_MonoOLED ::getBuffer (void ) { return buffer; }
390+ uint8_t *Adafruit_GrayOLED ::getBuffer (void ) { return buffer; }
370391
371392// OTHER HARDWARE SETTINGS -------------------------------------------------
372393
@@ -376,26 +397,24 @@ uint8_t *Adafruit_MonoOLED::getBuffer(void) { return buffer; }
376397 @param i
377398 If true, switch to invert mode (black-on-white), else normal
378399 mode (white-on-black).
379- @return None (void).
380400 @note This has an immediate effect on the display, no need to call the
381401 display() function -- buffer contents are not changed, rather a
382402 different pixel mode of the display hardware is used. When
383403 enabled, drawing MONOOLED_BLACK (value 0) pixels will actually draw
384404 white, MONOOLED_WHITE (value 1) will draw black.
385405*/
386- void Adafruit_MonoOLED ::invertDisplay (bool i) {
387- oled_command (i ? MONOOLED_INVERTDISPLAY : MONOOLED_NORMALDISPLAY );
406+ void Adafruit_GrayOLED ::invertDisplay (bool i) {
407+ oled_command (i ? GRAYOLED_INVERTDISPLAY : GRAYOLED_NORMALDISPLAY );
388408}
389409
390410/* !
391411 @brief Adjust the display contrast.
392412 @param level The contrast level from 0 to 0x7F
393- @return None (void).
394413 @note This has an immediate effect on the display, no need to call the
395414 display() function -- buffer contents are not changed.
396415*/
397- void Adafruit_MonoOLED ::setContrast (uint8_t level) {
398- uint8_t cmd[] = {MONOOLED_SETCONTRAST , level};
416+ void Adafruit_GrayOLED ::setContrast (uint8_t level) {
417+ uint8_t cmd[] = {GRAYOLED_SETCONTRAST , level};
399418 oled_commandList (cmd, 2 );
400419}
401420
0 commit comments