/*
 * $Id: oled_ssd1306.h 464 2019-08-01 02:15:54Z true $
 * begin 20190505 true
 */

#ifndef INC_DRIVER_OLED_SSD1306_H_
#define INC_DRIVER_OLED_SSD1306_H_



// we're using the EFM8 I2C driver true wrote
#include "driver/efm8_smb1.h"



#define SSD1306_RESET_ON_COMM_FAIL		// disable to have a device that never starts.


#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 xdata *mode;
	uint8_t xdata *fb;
	void (*callback)();
} SSD1306;



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



#define ssd1306_write(x,y,z)			smb1_mwrite(SSD1306_I2C_ADDR, x, y, z)
#define ssd1306_idle()					(smb1_get_state() == SMB1_IDLE)




void ssd1306_idle_wait();

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

void ssd1306_init(uint8_t display_off_during_init);

void ssd1306_update();
void ssd1306_cls(SSD1306 xdata *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 /* INC_DRIVER_OLED_SSD1306_H_ */
