Program Listing for File ssd1306.hpp

Return to documentation for file (/tmp/ws/src/turtlebot4_robot/turtlebot4_base/include/turtlebot4_base/ssd1306.hpp)

/*
 * MIT License
 *
 * Copyright (c) 2018 Aleksander Alekseev
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Original driver: https://github.com/afiskon/stm32-ssd1306
 *
 * @author Roni Kreinin (rkreinin@clearpathrobotics.com)
 */

#ifndef TURTLEBOT4_BASE__SSD1306_HPP_
#define TURTLEBOT4_BASE__SSD1306_HPP_

#include <unistd.h>
#include <memory>
#include <string>

#include "turtlebot4_base/i2c_interface.hpp"
#include "turtlebot4_base/ssd1306_fonts.hpp"

namespace turtlebot4_base
{

// SSD1306 OLED height in pixels
#ifndef SSD1306_HEIGHT
#define SSD1306_HEIGHT          64
#endif

// SSD1306 width in pixels
#ifndef SSD1306_WIDTH
#define SSD1306_WIDTH           128
#endif

#ifndef SSD1306_BUFFER_SIZE
#define SSD1306_BUFFER_SIZE   SSD1306_WIDTH * SSD1306_HEIGHT / 8
#endif

#ifdef SSD1306_INCLUDE_FONT_7x10
#define SSD1306_FONT Font_7x10
#define SSD1306_FONT_HEIGHT Font_7x10.FontHeight
#define SSD1306_FONT_WIDTH Font_7x10.FontWidth
#endif

#ifdef SSD1306_INCLUDE_FONT_6x8
#define SSD1306_HEADER_FONT Font_6x8
#define SSD1306_HEADER_FONT_HEIGHT Font_6x8.FontHeight
#define SSD1306_HEADER_FONT_WIDTH Font_6x8.FontWidth
#endif

#define SSD1306_NUM_LINES ((SSD1306_HEIGHT - SSD1306_HEADER_FONT_HEIGHT - 2) / SSD1306_FONT_HEIGHT)
#define SSD1306_CHAR_PER_LINE (SSD1306_WIDTH / SSD1306_FONT_WIDTH)
#define SSD1306_CHAR_PER_LINE_HEADER (SSD1306_WIDTH / SSD1306_HEADER_FONT_WIDTH)

enum ESsd1306Commands
{
  SSD1306_SETLOWCOLUMN     = 0x00,
  SSD1306_SETHIGHCOLUMN    = 0x10,
  SSD1306_MEMORYMODE       = 0x20,
  SSD1306_COLUMNADDR       = 0x21,
  SSD1306_PAGEADDR         = 0x22,
  SSD1306_SETSTARTLINE     = 0x40,
  SSD1306_DEFAULT_ADDRESS  = 0x78,
  SSD1306_SETCONTRAST      = 0x81,
  SSD1306_CHARGEPUMP       = 0x8D,
  SSD1306_SEGREMAP         = 0xA0,
  SSD1306_DISPLAYALLON_RESUME = 0xA4,
  SSD1306_DISPLAYALLON     = 0xA5,
  SSD1306_NORMALDISPLAY    = 0xA6,
  SSD1306_INVERTDISPLAY    = 0xA7,
  SSD1306_SETMULTIPLEX     = 0xA8,
  SSD1306_DISPLAYOFF       = 0xAE,
  SSD1306_DISPLAYON        = 0xAF,
  SSD1306_SETPAGE          = 0xB0,
  SSD1306_COMSCANINC       = 0xC0,
  SSD1306_COMSCANDEC       = 0xC8,
  SSD1306_SETDISPLAYOFFSET = 0xD3,
  SSD1306_SETDISPLAYCLOCKDIV = 0xD5,
  SSD1306_SETPRECHARGE     = 0xD9,
  SSD1306_SETCOMPINS       = 0xDA,
  SSD1306_SETVCOMDETECT    = 0xDB,
  SSD1306_SWITCHCAPVCC     = 0x02,
  SSD1306_NOP              = 0xE3,
};

enum ESsd1306MemoryMode
{
  HORIZONTAL_ADDRESSING_MODE  = 0x00,
  VERTICAL_ADDRESSING_MODE    = 0x01,
  PAGE_ADDRESSING_MODE        = 0x02,
};

static const uint8_t ssd1306_128x32_initData[] =
{
  SSD1306_DISPLAYOFF,   // display off
  SSD1306_SETDISPLAYCLOCKDIV, 0x80,
  SSD1306_SETMULTIPLEX, 0x1F,
  SSD1306_SETDISPLAYOFFSET, 0x00,   // --no offset
  SSD1306_SETSTARTLINE | 0x00,
  SSD1306_CHARGEPUMP, 0x14,   // 0x10
  SSD1306_SEGREMAP | 0x01,    // Reverse mapping
  SSD1306_COMSCANDEC,
  SSD1306_SETCOMPINS, 0x02,
  SSD1306_SETCONTRAST, 0x7F,   // contrast value
  SSD1306_SETPRECHARGE, 0x22,   // 0x1F
  SSD1306_SETVCOMDETECT, 0x40,
  SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE,
  SSD1306_DISPLAYALLON_RESUME,
  SSD1306_NORMALDISPLAY,
  SSD1306_DISPLAYON,
};

static const uint8_t ssd1306_128x64_initData[] =
{
  SSD1306_DISPLAYOFF,   // display off
  SSD1306_SETDISPLAYCLOCKDIV, 0x80,
  SSD1306_SETMULTIPLEX, 0x3F,
  SSD1306_SETDISPLAYOFFSET, 0x00,   // --no offset
  SSD1306_SETSTARTLINE | 0x00,
  SSD1306_CHARGEPUMP, 0x10,   // 0x10
  SSD1306_SEGREMAP | 0x01,    // Reverse mapping
  SSD1306_COMSCANDEC,
  SSD1306_SETCOMPINS, 0x12,
  SSD1306_SETCONTRAST, 0x01,   // contrast value
  SSD1306_SETPRECHARGE, 0x22,   // 0x1F
  SSD1306_SETVCOMDETECT, 0x40,
  SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE,
  SSD1306_DISPLAYALLON_RESUME,
  SSD1306_NORMALDISPLAY,
  SSD1306_DISPLAYON,
};


// Enumeration for screen colors
typedef enum
{
  Black = 0x00,   // Black color, no pixel
  White = 0x01    // Pixel is set. Color depends on OLED
} SSD1306_COLOR;

typedef enum
{
  SSD1306_OK = 0x00,
  SSD1306_ERR = 0x01    // Generic error.
} SSD1306_Error_t;

// Struct to store transformations
typedef struct
{
  uint16_t CurrentX;
  uint16_t CurrentY;
  uint8_t Inverted;
  uint8_t Initialized;
  uint8_t DisplayOn;
} SSD1306_t;
typedef struct
{
  uint8_t x;
  uint8_t y;
} SSD1306_VERTEX;

union SSD1306_Page_Buffer {
  struct
  {
    uint8_t control;
    uint8_t data[SSD1306_WIDTH];
  } page;
  uint8_t raw[SSD1306_WIDTH + 1];
};

union SSD1306_Command_Buffer {
  struct
  {
    uint8_t control;
    uint8_t byte;
  } command;
  uint8_t raw[2];
};

class Ssd1306
{
public:
  Ssd1306(std::shared_ptr<I2cInterface> i2c_interface, uint8_t device_id);

  void Init(void);
  void Fill(SSD1306_COLOR color);
  void UpdateScreen(void);
  void DrawPixel(uint8_t x, uint8_t y, SSD1306_COLOR color);
  char WriteChar(char ch, FontDef Font, SSD1306_COLOR color);
  bool WriteString(std::string str, FontDef Font, SSD1306_COLOR color);
  void SetCursor(uint8_t x, uint8_t y);
  SSD1306_t GetCursor();
  void DrawBattery(uint8_t x1, uint8_t y1, SSD1306_COLOR color);
  void Line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, SSD1306_COLOR color);
  void DrawArc(
    uint8_t x, uint8_t y, uint8_t radius, uint16_t start_angle, uint16_t sweep,
    SSD1306_COLOR color);
  void DrawCircle(uint8_t par_x, uint8_t par_y, uint8_t par_r, SSD1306_COLOR color);
  void Polyline(const SSD1306_VERTEX * par_vertex, uint16_t par_size, SSD1306_COLOR color);
  void DrawRectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, SSD1306_COLOR color);
  void SetContrast(const uint8_t value);
  void SetDisplayOn(const uint8_t on);
  uint8_t GetDisplayOn();

  // Low-level procedures
  void Reset(void);
  void WriteCommand(uint8_t byte);
  void WriteData(uint8_t * buffer, size_t buff_size);
  void WritePage(uint8_t page);
  SSD1306_Error_t FillBuffer(uint8_t * buf, uint32_t len);

  float DegToRad(float par_deg);
  uint16_t NormalizeTo0_360(uint16_t par_deg);

private:
  void HandleRet(int8_t ret);

  std::shared_ptr<I2cInterface> i2c_interface_;
  uint8_t device_id_;
  uint8_t error_count_;

  SSD1306_t SSD1306;
  uint8_t buffer_[SSD1306_BUFFER_SIZE];
};

}  // namespace turtlebot4_base

#endif  // TURTLEBOT4_BASE__SSD1306_HPP_