Subversion Repositories libOLED

Rev

Rev 7 | Rev 11 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * displayclass.cpp
  3.  *
  4.  *  Created on: 31 Oct 2020
  5.  *      Author: mike
  6.  */
  7.  
  8. #include "libOLED/displayclass.H"
  9.  
  10. #include <cstring>
  11. #include <cstdlib>
  12. namespace
  13. {
  14.   uint8_t const SSD1306_SETCONTRAST = 0x81;
  15.   uint8_t const SSD1306_DISPLAYALLON_RESUME = 0xA4;
  16.   uint8_t const SSD1306_DISPLAYALLON = 0xA5;
  17.   uint8_t const SSD1306_NORMALDISPLAY = 0xA6;
  18.   uint8_t const SSD1306_INVERTDISPLAY = 0xA7;
  19.   uint8_t const SSD1306_DISPLAYOFF = 0xAE;
  20.   uint8_t const SSD1306_DISPLAYON = 0xAF;
  21.  
  22.   uint8_t const SSD1306_SETDISPLAYOFFSET = 0xD3;
  23.   uint8_t const SSD1306_SETCOMPINS = 0xDA;
  24.  
  25.   uint8_t const SSD1306_SETVCOMDETECT = 0xDB;
  26.  
  27.   uint8_t const SSD1306_SETDISPLAYCLOCKDIV = 0xD5;
  28.   uint8_t const SSD1306_SETPRECHARGE = 0xD9;
  29.  
  30.   uint8_t const SSD1306_SETMULTIPLEX = 0xA8;
  31.  
  32.   uint8_t const SSD1306_SETLOWCOLUMN = 0x00;
  33.   uint8_t const SSD1306_SETHIGHCOLUMN = 0x10;
  34.  
  35.   uint8_t const SSD1306_SETSTARTLINE = 0x40;
  36.  
  37.   uint8_t const SSD1306_MEMORYMODE = 0x20;
  38.   uint8_t const SSD1306_COLUMNADDR = 0x21;
  39.   uint8_t const SSD1306_PAGEADDR = 0x22;
  40.  
  41.   uint8_t const SSD1306_COMSCANINC = 0xC0;
  42.   uint8_t const SSD1306_COMSCANDEC = 0xC8;
  43.  
  44.   uint8_t const SSD1306_SEGREMAP = 0xA0;
  45.  
  46.   uint8_t const SSD1306_CHARGEPUMP = 0x8D;
  47.  
  48.   uint8_t const SSD1306_EXTERNALVCC = 0x1;
  49.   uint8_t const SSD1306_SWITCHCAPVCC = 0x2;
  50.  
  51. // Scrolling #defines
  52.   uint8_t const SSD1306_ACTIVATE_SCROLL = 0x2F;
  53.   uint8_t const SSD1306_DEACTIVATE_SCROLL = 0x2E;
  54.   uint8_t const SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3;
  55.   uint8_t const SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26;
  56.   uint8_t const SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27;
  57.   uint8_t const SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29;
  58.   uint8_t const SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A;
  59.  
  60.   template<class T>
  61.     void
  62.     swap (T &x, T &y)
  63.     {
  64.       T temp = x;
  65.       x = y;
  66.       y = temp;
  67.     }
  68.  
  69.   template<class T>
  70.     T
  71.     abs (T x)
  72.     {
  73.       return x < 0 ? -x : x;
  74.     }
  75.  
  76. }
  77. // provided to allow a destructor to destroy something not deleted
  78. // this is only OK because destructors shouldnt be needed
  79. void
  80. operator delete (void *data, unsigned int f)
  81. {
  82.   (void) data;
  83.   (void) f;
  84. }
  85.  
  86. // provided to implement an "error handler" on pure virtual
  87. extern "C" void
  88. __cxa_pure_virtual ()
  89. {
  90.   while (1)
  91.     ;
  92. }
  93.  
  94. display_t::display_t (int const width, int const height, int const ramwidth,
  95.                       uint8_t *const data) :
  96.     m_width (width), m_height (height), m_ramwidth (ramwidth), m_cursor_x (0), m_cursor_y (
  97.         0), m_rotation (0), m_colour (WHITE), m_data (data)
  98. {
  99. }
  100.  
  101. display_t::~display_t ()
  102. {
  103.  
  104. }
  105.  
  106. void display_t::reset()
  107. {
  108.   oledReset();
  109. }
  110.  
  111. void
  112. display_t::init ()
  113. {
  114.   uint8_t const vccstate = SSD1306_EXTERNALVCC;
  115.  
  116.  
  117.   oledSetCD (0);
  118.  
  119.   // Init sequence for 128x32 or 128x64  OLED module
  120.   oledWrite (SSD1306_DISPLAYOFF); // 0xAE
  121.   oledWrite (SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
  122.   oledWrite (0x80); // the suggested ratio 0x80
  123.   oledWrite (SSD1306_SETMULTIPLEX); // 0xA8
  124.   oledWrite (m_height - 1);
  125.   oledWrite (SSD1306_SETDISPLAYOFFSET); // 0xD3
  126.   oledWrite (0x0); // no offset
  127.   oledWrite (SSD1306_SETSTARTLINE | 0x0); // line #0
  128.   oledWrite (SSD1306_CHARGEPUMP); // 0x8D
  129.   oledWrite (vccstate == SSD1306_EXTERNALVCC ? 0x10 : 0x14);
  130.   oledWrite (SSD1306_MEMORYMODE);                    // 0x20
  131.   oledWrite (0x00);                    // 0x0 act like ks0108
  132.   oledWrite (SSD1306_SEGREMAP | 0x1);
  133.   oledWrite (SSD1306_COMSCANDEC);
  134.   oledWrite (SSD1306_SETCOMPINS);                    // 0xDA
  135.   oledWrite (m_height == 32 ? 0x02 : 0x12);
  136.   oledWrite (SSD1306_SETCONTRAST);                    // 0x81
  137.   oledWrite (vccstate == SSD1306_EXTERNALVCC ? 0x9F : 0xCF);
  138.   oledWrite (SSD1306_SETPRECHARGE);                    // 0xd9
  139.   oledWrite (vccstate == SSD1306_EXTERNALVCC ? 0x22 : 0xF1);
  140.   oledWrite (SSD1306_SETVCOMDETECT);                 // 0xDB
  141.   oledWrite (0x40);
  142.   oledWrite (SSD1306_DISPLAYALLON_RESUME);                 // 0xA4
  143.   oledWrite (SSD1306_NORMALDISPLAY);                 // 0xA6
  144.  
  145.   oledWrite (SSD1306_DISPLAYON);             //--turn on oled panel
  146.  
  147.   clearDisplay ();
  148.  
  149. }
  150.  
  151. uint8_t
  152. display_t::getRotation (void)
  153. {
  154.   return m_rotation;
  155. }
  156.  
  157. int16_t
  158. display_t::width (void)
  159. {
  160.   switch (m_rotation)
  161.     {
  162.     case 0:
  163.       return m_width;
  164.       break;
  165.     case 1:
  166.       return m_width;
  167.       break;
  168.     case 2:
  169.       return m_height;
  170.       break;
  171.     case 3:
  172.       return -m_width;
  173.       break;
  174.     }
  175.   return 0;
  176. }
  177.  
  178. int16_t
  179. display_t::height (void)
  180. {
  181.   switch (m_rotation)
  182.     {
  183.     case 0:
  184.       return m_height;
  185.       break;
  186.     case 1:
  187.       return m_height;
  188.       break;
  189.     case 2:
  190.       return m_width;
  191.       break;
  192.     case 3:
  193.       return -m_height;
  194.       break;
  195.     }
  196.   return 0;
  197. }
  198.  
  199. // the most basic function, set a single pixel
  200. void
  201. display_t::drawPixel (int16_t x, int16_t y, bool pixel)
  202. {
  203.   if ((x < 0) || (x >= m_width) || (y < 0) || (y >= m_height))
  204.     return;
  205.  
  206.   // check rotation, move pixel around if necessary
  207.   switch (m_rotation)
  208.     {
  209.     case 1:
  210.       swap (x, y);
  211.       x = m_width - x - 1;
  212.       break;
  213.     case 2:
  214.       x = m_width - x - 1;
  215.       y = m_height - y - 1;
  216.       break;
  217.     case 3:
  218.       swap (x, y);
  219.       y = m_height - y - 1;
  220.       break;
  221.     }
  222.  
  223.   // x is which column
  224.   //  BLACK,  and 0,             invert 0
  225.   //  WHITE,   and 0,            invert 1
  226.   //  OVERLAY, and 1 (preserve) , invert 0/
  227.   // INVERT,  and 1, (preserve) , invert 1
  228.  
  229.   switch (m_colour)
  230.     {
  231.     case BLACK:
  232.     case WHITE:
  233.       m_data[x + (y / 8) * m_width] &= ~(1 << (y & 7));
  234.       break;
  235.     default:
  236.       break;
  237.     }
  238.   uint8_t pixData = 0;
  239.   switch (m_colour)
  240.     {
  241.     case BLACK:
  242.       pixData = pixel ? 0 : 1;
  243.       break;
  244.     case WHITE:
  245.     case OVERLAY:
  246.     case INVERT:
  247.        pixData = pixel ? 1 : 0;
  248.       break;
  249.     }
  250.  
  251.   m_data[x + (y / 8) * m_width] ^= (pixData << (y & 7));
  252.  
  253. }
  254.  
  255. void
  256. display_t::invertDisplay (uint8_t i)
  257. {
  258.   oledSetCD (0);
  259.   oledWrite (i ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY);
  260. }
  261.  
  262. // startscrollright
  263. // Activate a right handed scroll for rows start through stop
  264. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  265. // display.scrollright(0x00, 0x0F)
  266. void
  267. display_t::startscrollright (uint8_t start, uint8_t stop)
  268. {
  269.   oledSetCD (0);
  270.   oledWrite (SSD1306_RIGHT_HORIZONTAL_SCROLL);
  271.   oledWrite (0X00);
  272.   oledWrite (start);
  273.   oledWrite (0X00);
  274.   oledWrite (stop);
  275.   oledWrite (0X00);
  276.   oledWrite (0XFF);
  277.   oledWrite (SSD1306_ACTIVATE_SCROLL);
  278. }
  279.  
  280. // startscrollleft
  281. // Activate a right handed scroll for rows start through stop
  282. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  283. // display.scrollright(0x00, 0x0F)
  284. void
  285. display_t::startscrollleft (uint8_t start, uint8_t stop)
  286. {
  287.   oledSetCD (0);
  288.   oledWrite (SSD1306_LEFT_HORIZONTAL_SCROLL);
  289.   oledWrite (0X00);
  290.   oledWrite (start);
  291.   oledWrite (0X00);
  292.   oledWrite (stop);
  293.   oledWrite (0X00);
  294.   oledWrite (0XFF);
  295.   oledWrite (SSD1306_ACTIVATE_SCROLL);
  296. }
  297.  
  298. // startscrolldiagright
  299. // Activate a diagonal scroll for rows start through stop
  300. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  301. // display.scrollright(0x00, 0x0F)
  302. void
  303. display_t::startscrolldiagright (uint8_t start, uint8_t stop)
  304. {
  305.   oledSetCD (0);
  306.   oledWrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
  307.   oledWrite (0X00);
  308.   oledWrite (m_height);
  309.   oledWrite (SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
  310.   oledWrite (0X00);
  311.   oledWrite (start);
  312.   oledWrite (0X00);
  313.   oledWrite (stop);
  314.   oledWrite (0X01);
  315.   oledWrite (SSD1306_ACTIVATE_SCROLL);
  316. }
  317.  
  318. // startscrolldiagleft
  319. // Activate a diagonal scroll for rows start through stop
  320. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  321. // display.scrollright(0x00, 0x0F)
  322. void
  323. display_t::startscrolldiagleft (uint8_t start, uint8_t stop)
  324. {
  325.   oledSetCD (0);
  326.   oledWrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
  327.   oledWrite (0X00);
  328.   oledWrite (m_height);
  329.   oledWrite (SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
  330.   oledWrite (0X00);
  331.   oledWrite (start);
  332.   oledWrite (0X00);
  333.   oledWrite (stop);
  334.   oledWrite (0X01);
  335.   oledWrite (SSD1306_ACTIVATE_SCROLL);
  336. }
  337.  
  338. void
  339. display_t::stopscroll (void)
  340. {
  341.   oledSetCD (0);
  342.   oledWrite (SSD1306_DEACTIVATE_SCROLL);
  343. }
  344.  
  345. // Dim the display
  346. // dim = true: display is dimmed
  347. // dim = false: display is normal
  348. void
  349. display_t::dim (uint8_t contrast)
  350. {
  351.  
  352.   // the range of contrast to too small to be really useful
  353.   // it is useful to dim the display
  354.  
  355.   oledSetCD (0);
  356.   oledWrite (SSD1306_SETCONTRAST);
  357.   oledWrite (contrast);
  358. }
  359.  
  360. void
  361. display_t::display (void)
  362. {
  363.   oledSetCD (0);
  364.   // select entire display as window to write into
  365.   oledWrite (SSD1306_COLUMNADDR);
  366.   oledWrite (0);   // Column start address (0 = reset)
  367.   oledWrite (m_ramwidth - 1); // Column end address (127 = reset)
  368.  
  369.   oledWrite (SSD1306_PAGEADDR);
  370.   oledWrite (0); // Page start address (0 = reset)
  371.   oledWrite ((m_height == 64) ? 7 : 3); // Page end address
  372.  
  373.   int row;
  374.  
  375.   int col = m_ramwidth == 132 ? 2 : 0;
  376.   for (row = 0; row < m_height / 8; row++)
  377.     {
  378.       oledSetCD (0);
  379.       // set the cursor to
  380.       oledWrite (0xB0 + row); //set page address
  381.       oledWrite (col & 0xf); //set lower column address
  382.       oledWrite (0x10 | (col >> 4)); //set higher column address
  383.  
  384.       oledSetCD (1);
  385.       oledWrite (m_data + row * m_width, m_width);
  386.  
  387.     }
  388.  
  389. }
  390.  
  391. // clear everything
  392. void
  393. display_t::clearDisplay (colour_t colour)
  394. {
  395.   switch (colour)
  396.     {
  397.     case WHITE:
  398.     case OVERLAY:
  399.       memset (m_data, 255, dataSize (m_width, m_height));
  400.       break;
  401.     case BLACK:
  402.       memset (m_data, 0, dataSize (m_width, m_height));
  403.       break;
  404.     case INVERT:
  405.       for (size_t i = 0; i <  dataSize (m_width, m_height); i++)
  406.         m_data[i] ^= 255;
  407.       break;
  408.     }
  409.  
  410. }
  411.  
  412. void
  413. display_t::drawRectangle (int16_t x1, int16_t y1, int16_t x2, int16_t y2,
  414.                           colour_t color)
  415. {
  416.   for (int16_t x = x1; x <= x2; x++)
  417.     for (int16_t y = y1; y < y2; y++)
  418.       {
  419.         switch (color)
  420.           {
  421.           case BLACK:
  422.             m_data[x + (y / 8) * m_width] &= ~(1 << (y & 7));
  423.             break;
  424.  
  425.           default:
  426.           case WHITE:
  427.           case OVERLAY:
  428.             m_data[x + (y / 8) * m_width] |= (1 << (y & 7));
  429.             break;
  430.  
  431.           case INVERT:
  432.             m_data[x + (y / 8) * m_width] ^= (1 << (y & 7));
  433.             break;
  434.           }
  435.       }
  436. }
  437.  
  438. /* using Bresenham draw algorithm */
  439. void
  440. display_t::drawLine (int16_t x1, int16_t y1, int16_t x2, int16_t y2,
  441.                      colour_t  colour)
  442. {
  443.   int16_t x, y, dx, dy,    //deltas
  444.       dx2, dy2, //scaled deltas
  445.       ix, iy,   //increase rate on the x and y axis
  446.       err;      //the error term
  447.  
  448.  
  449.   uint16_t i;           //looping variable
  450.  
  451.   setPixelMode(colour);
  452.  
  453.   // identify the first pixel
  454.   x = x1;
  455.   y = y1;
  456.  
  457.   // difference between starting and ending points
  458.   dx = x2 - x1;
  459.   dy = y2 - y1;
  460.  
  461.   // calculate direction of the vector and store in ix and iy
  462.   if (dx >= 0)
  463.     ix = 1;
  464.  
  465.   if (dx < 0)
  466.     {
  467.       ix = -1;
  468.       dx = abs (dx);
  469.     }
  470.  
  471.   if (dy >= 0)
  472.     iy = 1;
  473.  
  474.   if (dy < 0)
  475.     {
  476.       iy = -1;
  477.       dy = abs (dy);
  478.     }
  479.  
  480.   // scale deltas and store in dx2 and dy2
  481.   dx2 = dx * 2;
  482.   dy2 = dy * 2;
  483.  
  484. // all  variables are set and it's time to enter the main loop.
  485.  
  486.   if (dx > dy)  // dx is the major axis
  487.     {
  488.       // initialize the error term
  489.       err = dy2 - dx;
  490.  
  491.       for (i = 0; i <= dx; i++)
  492.         {
  493.           drawPixel (x, y, 1);
  494.           if (err >= 0)
  495.             {
  496.               err -= dx2;
  497.               y += iy;
  498.             }
  499.           err += dy2;
  500.           x += ix;
  501.         }
  502.     }
  503.  
  504.   else          // dy is the major axis
  505.     {
  506.       // initialize the error term
  507.       err = dx2 - dy;
  508.  
  509.       for (i = 0; i <= dy; i++)
  510.         {
  511.           drawPixel (x, y, 1);
  512.           if (err >= 0)
  513.             {
  514.               err -= dy2;
  515.               x += ix;
  516.             }
  517.           err += dx2;
  518.           y += iy;
  519.         }
  520.     }
  521. }
  522.  
  523.