Saturday, August 11, 2018

Display Abstraction Layer


"Software never dies", the saying goes. But to help that happen, the software should be as independent as possible from the hardware it uses. Today, we are getting closer to this goal by introducing the Display Abstraction Layer (DAL), a simple framework that allows displaying on any suitable device. The implementation is based on polymorphism: using a virtual class when writing to the display, but instantiating a concrete display class depending on the device being written to. Each device requires its own concrete class that implements a set of functions (defined in the virtual class) used for outputting to the display. Thus every concrete display class becomes a simple “device driver” for the specific display device that was written for.

A class diagram of the DAL framework is shown below.










This is nothing revolutionary, just a simple solution that should have been there (in projects using displays) from the beginning. It provides an easy adaptation between the project functionality and the display, and also reduces the porting effort to just implementing a class for the new display.

The DAL interface consists of a set of function definitions used to output to the display. This set of functions depends on the project. That means that the DAL interface for WiFiChron will be different from the one for WiseClock. For example, in the case of WiFiChron, there are only 4 functions dealing with the display that need to be implemented:

    void setup();
    void writeDisplay (char* displayBuffer);
    void setBrightness(uint8_t brightness);
    void reset();

WiseClock uses a lot more display functions (currently defined in HT1632.h):

  void setup();
  void clear();
  void setBrightness(byte level);
  void snapshot_shadowram();
  byte get_snapshotram   (coord_t x, int8_t y);
  byte get_shadowram     (coord_t x, int8_t y);
  void clearSnapshot     ();
  void clearSnapshot     (int8_t dispNo = 0);
  void copyToVideo       (byte chipNo, char* vbuffer);
  void overlayWithSnapshotHorizontal(int8_t y);
  void overlayWithSnapshotVertical  (coord_t x);
  void plot         (coord_t x, int8_t y, byte color);
  void line         (coord_t x1, int8_t y1, coord_t x2, int8_t y2, byte val);
  void putChar      (coord_t x, int8_t y, char c, byte color);
  void putTinyChar  (coord_t x, int8_t y, char c, byte color);
  coord_t       putLargeChar (coord_t x, int8_t y, char c, byte color);
  void putBigDigit  (coord_t x, int8_t y, int8_t digit, int8_t fontNbr, byte color, int8_t columns);
  void putFullDigit (coord_t x, int8_t y, uint8_t digit, byte color, byte fontNumber=0);
  void putBitmap    (coord_t x, int8_t y, byte indexBmp, byte color=ORANGE);
  void putString    (coord_t x, int8_t y, const char* str, byte color);
  void putTinyString(coord_t x, int8_t y, const char* str, byte color);
  void displayStaticLine  (char* text, int8_t y, byte color);
  void displayStaticLine_P(const char* text, int8_t y, byte color);

Currently, I have implemented and tested a bunch of DAL classes for HDSPwise clock (the simpler version of WiFiChron). These include support for HDSP2534, DL1414, OLED (128x64). The common characteristic of these displays, that makes them suitable for the HDSP clock/WiFiChron, is that all of them can display 8 characters that can then be scrolled horizontally.

DAL for WiseClock would require implementing the above functions for a graphic display with a resolution of at least 32x16 pixels. Also, this graphic display should need no more than 4 control wires (hardware limitation of WiseClock4 board). So, if you wish to replace the 3216 display (not available from Sure Electronics anymore), a suitable candidate would be a TV (through the TV pixel library) or even an 128x64 I2C OLED. Keep in mind that controlling the 16x32 LED displays that use shift registers (either monochrome or RGB) requires more than 4 wires. Their support by Wise Clock 4 would need hardware changes, probably the insertion of a controller (e.g. HT1632, HT16K33 etc).