/*
 * oled.h
 *
 *  Created on: Oct 22, 2019
 *      Author: mmalex
 */

#ifndef OLED_H_
#define OLED_H_

#define W 128
#define H 32

void oled_flip(const u8* vram_with_offset);
void oled_init(void);

#ifdef IMPL
#define SSD1306_COLUMNADDR 0x21
#define SSD1306_DISPLAYOFF 0xAE
#define SSD1306_DISPLAYON 0xAF
#define SSD1306_PAGEADDR   0x22
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
#define SSD1306_SETPRECHARGE 0xD9
#define SSD1306_SETCONTRAST 0x81
#define SSD1306_SETDISPLAYOFFSET 0xD3
#define SSD1306_SETMULTIPLEX 0xA8
#define SSD1306_SETSTARTLINE 0x40
#define SSD1306_CHARGEPUMP 0x8D
#define SSD1306_SEGREMAP 0xA0
#define SSD1306_COMSCANDEC 0xC8
#define SSD1306_COMSCANINC 0xC0
#define SSD1306_MEMORYMODE 0x20
#define SSD1306_SETCOMPINS 0xDA
#define SSD1306_SETVCOMDETECT 0xDB
#define SSD1306_DISPLAYALLON_RESUME 0xA4
#define SSD1306_NORMALDISPLAY 0xA6
#define SSD1306_DEACTIVATE_SCROLL 0x2E
#define SSD1306_EXTERNALVCC 0x1
#define SSD1306_SWITCHCAPVCC 0x2
#define SSD1306_DISPLAYALLON 0xA5
#define SSD1306_INVERTDISPLAY 0xA7
#define SSD1306_SETLOWCOLUMN 0x00
#define SSD1306_SETHIGHCOLUMN 0x10
#include "logo.h"

const static unsigned char oled_i2caddr = 0x3c << 1;

static inline void ssd1306_command(unsigned char c) {
#ifndef EMU
	u8 buf[2] = { 0, c };
	HAL_StatusTypeDef r = HAL_I2C_Master_Transmit(&hi2c2, oled_i2caddr, buf, 2, I2C_TIMEOUT);
	if (r != HAL_OK)
		DebugLog("error in ssd1306 command %d\r\n", (int) r);
	HAL_Delay(1);
#endif
}


static inline bool oled_busy(void) {
#ifndef EMU
	return HAL_I2C_GetState(&hi2c2) == HAL_I2C_STATE_BUSY_TX;
#else
	return false;
#endif
}

static inline void oled_wait(void) {
	  while (oled_busy()) ;
}

bool update_accelerometer_raw(void);


void oled_flip(const u8* vram_with_offset) {
//	  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
	// send a bunch of data in one xmission
	oled_wait();
#ifndef EMU
	ssd1306_command(0); // Page start address (0 = reset)
//	ssd1306_command(3); // Page end address - 32 pixels. 1=16 pixels

	HAL_StatusTypeDef r = 	HAL_I2C_Master_Transmit(&hi2c2, oled_i2caddr, (u8*)vram_with_offset, W * H / 8+1, 500);
	if (r != HAL_OK)
		DebugLog("error in ssd1306 data %d\r\n", (int) r);
	update_accelerometer_raw();
#else
	void OledFlipEmu(const u8 *vram);
	OledFlipEmu(vram_with_offset);
#endif
}


void oled_init(void) {
	// Init sequence
	ssd1306_command(SSD1306_DISPLAYOFF);                    // 0xAE
	ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV);            // 0xD5
	ssd1306_command(0x80);                                  // the suggested ratio 0x80

	ssd1306_command(SSD1306_SETMULTIPLEX);                  // 0xA8
	ssd1306_command(H - 1);

	ssd1306_command(SSD1306_SETDISPLAYOFFSET);              // 0xD3
	ssd1306_command(0x0);                                   // no offset
	ssd1306_command(SSD1306_SETSTARTLINE | 0x0);            // line #0
	ssd1306_command(SSD1306_CHARGEPUMP);                    // 0x8D
	ssd1306_command(0x14);  // switchcap
	ssd1306_command(SSD1306_MEMORYMODE);                    // 0x20
	ssd1306_command(0x00);                                  // 0x0 act like ks0108
	ssd1306_command(SSD1306_SEGREMAP | 0x1);
	ssd1306_command(SSD1306_COMSCANDEC);
	ssd1306_command(SSD1306_SETCOMPINS);                    // 0xDA
	ssd1306_command(0x02);
	ssd1306_command(SSD1306_SETCONTRAST);                   // 0x81
	ssd1306_command(0x8F);

	ssd1306_command(SSD1306_SETPRECHARGE);                  // 0xd9
	ssd1306_command(0xF1); // switchcap
	ssd1306_command(SSD1306_SETVCOMDETECT);                 // 0xDB
	ssd1306_command(0x40);
	ssd1306_command(SSD1306_DISPLAYALLON_RESUME);           // 0xA4
	ssd1306_command(SSD1306_NORMALDISPLAY);                 // 0xA6

	ssd1306_command(SSD1306_DEACTIVATE_SCROLL);

// put the plinky logo up before switching on the screen
	// prepare flip
	ssd1306_command(SSD1306_COLUMNADDR);
	ssd1306_command(0);   // Column start address (0 = reset)
	ssd1306_command(W - 1); // Column end address (127 = reset)
	ssd1306_command(SSD1306_PAGEADDR);
	ssd1306_command(0); // Page start address (0 = reset)
	ssd1306_command(3); // Page end address - 32 pixels. 1=16 pixels
	ssd1306_command(SSD1306_DISPLAYON);                 //--turn on oled panel

	oled_flip(logobuf);
	oled_wait();
}
#endif
#endif /* OLED_H_ */
