/*
 * ssd1306.h 494
 * begin 20190505 true
 */

#ifndef USER_HW_SSD1306_H_
#define USER_HW_SSD1306_H_



#include <stdint.h>

#include "../comm/i2c.h"



#define SSD1306_I2C_ADDR                0x3c
#define SSD1306_WIDTH                   128
#define SSD1306_HEIGHT                  32

#define SSD1306_EXTERNALVCC             0x01
#define SSD1306_SWITCHCAPVCC            0x02

#define SSD1306_MODE_CMD                0x00
#define SSD1306_MODE_DATA               0x40
#define SSD1306_MODE_SINGLE             0x80

#define SSD1306_CMD_CONTRAST            0x81
#define SSD1306_CMD_DISPLAY_ALLON_OFF   0xA4
#define SSD1306_CMD_DISPLAY_ALLON       0xA5
#define SSD1306_CMD_INVERT_OFF          0xA6
#define SSD1306_CMD_INVERT_ON           0xA7
#define SSD1306_CMD_DISPLAY_OFF         0xAE
#define SSD1306_CMD_DISPLAY_ON          0xAF
#define SSD1306_CMD_DISPLAYOFFSET       0xD3
#define SSD1306_CMD_SETCOMPINS          0xDA
#define SSD1306_CMD_SETVCOMDETECT       0xDB
#define SSD1306_CMD_DISPLAYCLOCKDIV     0xD5
#define SSD1306_CMD_PRECHARGE           0xD9
#define SSD1306_CMD_MULTIPLEX           0xA8
#define SSD1306_CMD_LOWCOLUMN           0x00
#define SSD1306_CMD_HIGHCOLUMN          0x10
#define SSD1306_CMD_STARTLINE           0x40
#define SSD1306_CMD_MEMORYMODE          0x20
#define SSD1306_CMD_COLUMNADDR          0x21
#define SSD1306_CMD_PAGEADDR            0x22
#define SSD1306_CMD_COMSCANINC          0xC0
#define SSD1306_CMD_COMSCANDEC          0xC8
#define SSD1306_CMD_SEGREMAP            0xA0
#define SSD1306_CMD_SEGREMAP_MIRROR     0xA1
#define SSD1306_CMD_CHARGEPUMP          0x8D


#define SSD1306_STATE_INITIALIZED       (1 << 0)
#define SSD1306_STATE_BUSY              (1 << 1)
#define SSD1306_STATE_FLIP              (1 << 2)
#define SSD1306_STATE_MIRROR            (1 << 3)

#define SSD1306_STATE_STR_HALFWIDTH     (1 << 4)

#define SSD1306_STATE_PIXEL_MASK        (0xC0)
#define SSD1306_STATE_SET_PIXEL         (1 << 6)
#define SSD1306_STATE_CLR_PIXEL         (0)
#define SSD1306_STATE_INVERT_PIXEL      (1 << 7)


typedef struct SSD1306 {
    char state;
    uint8_t width;
    uint8_t height;
    int8_t cursor_x;
    int8_t cursor_y;
    uint8_t *mode;
    uint8_t *fb;
    void (*callback)();
} SSD1306;



extern SSD1306 oled;
extern uint8_t oled_fb[((SSD1306_HEIGHT >> 3) * SSD1306_WIDTH) + 1];



#define ssd1306_write(dat, len, cb)     i2c_addr((SSD1306_I2C_ADDR << 1), 0); i2c_wrbuf(dat, len); if (cb) ssd1306_cb(0)
#define ssd1306_idle()                  0



void ssd1306_idle_wait();

void ssd1306_cb(uint8_t p);     // can be used to fake a callback event
uint8_t ssd1306_cb_get();

void ssd1306_init(uint8_t display_off_during_init);

void ssd1306_update();
void ssd1306_cls(SSD1306 *o);

void ssd1306_set_display(uint8_t display);
void ssd1306_set_invert(uint8_t invert);
void ssd1306_set_contrast(uint8_t contrast);
void ssd1306_set_flip(uint8_t flip);
void ssd1306_set_mirror(uint8_t mirror);
void ssd1306_set_flipmirror(uint8_t flipm);



#endif /* USER_DEVICE_SSD1306_H_ */
