//
//  s95160_1.c	Layer 1 (Physical device interface)
//  Graphic LCD module "SUCCESS ELECTRONIC S95160" I/O library
//  Copyright(C)2013-2017 Toyohiko Togashi tog001@nifty.com
//
//
//  This program is free software; you can redistribute it and/or modify it under the terms of the
//  GNU General Public License as published by the Free Software Foundation; either version 3
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//  See the GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along with this program.
//  If not, see <http://www.gnu.org/licenses/>
//
//
//    Update history
//    ---------- ----- -------------------------------------------
//    2013.01.22 v0.0  First cording
//    2017.04.15 v0.3  Supported a System Workbench for STM32 and STM32CubeF4
//    2017.04.15 v0.3  Supported a STM32 NUCLEO F446RE
//

//---------------------------------------------------------------------
//
//						STM32Cube HAL Drivers
//
//---------------------------------------------------------------------
#ifdef USE_HAL_DRIVER					// ADD START 2017.04.15
#include <stm32f4xx.h>
#include <stm32f4xx_hal_gpio.h>
#include <stm32f4xx_hal_rcc.h>
#include <stdint.h>

//
// Hardware config
//
#if defined(STM32F4DISCOVERY)
#define LCD_CONF_DB1_GPIO		GPIOD
#define LCD_CONF_DB1_PIN		(GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3)
#define LCD_CONF_DB2_GPIO		GPIOE
#define LCD_CONF_DB2_PIN		(GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15)
#define LCD_CONF_CS_GPIO		GPIOD
#define LCD_CONF_CS_PIN			GPIO_PIN_6
#define LCD_CONF_RS_GPIO		GPIOD
#define LCD_CONF_RS_PIN			GPIO_PIN_7
#define LCD_CONF_WR_GPIO		GPIOD
#define LCD_CONF_WR_PIN			GPIO_PIN_8
#define LCD_CONF_RD_GPIO		GPIOD
#define LCD_CONF_RD_PIN			GPIO_PIN_9
#define LCD_CONF_RCCINIT()		{\
								__HAL_RCC_GPIOD_CLK_ENABLE();\
								__HAL_RCC_GPIOE_CLK_ENABLE();\
								}
#elif defined(NUCLEO_F446RE)
#define LCD_CONF_DB_GPIO		GPIOC
#define LCD_CONF_CS_GPIO		GPIOB
#define LCD_CONF_CS_PIN			GPIO_PIN_4
#define LCD_CONF_RS_GPIO		GPIOB
#define LCD_CONF_RS_PIN			GPIO_PIN_5
#define LCD_CONF_WR_GPIO		GPIOB
#define LCD_CONF_WR_PIN			GPIO_PIN_6
#define LCD_CONF_RD_GPIO		GPIOB
#define LCD_CONF_RD_PIN			GPIO_PIN_7
#define LCD_CONF_RCCINIT()		{\
								__HAL_RCC_GPIOB_CLK_ENABLE();\
								__HAL_RCC_GPIOC_CLK_ENABLE();\
								}
#else
#error "Not supported"
#endif
#define HAL_GPIO_SetPin(port, pin)		port->BSRR = pin
#define HAL_GPIO_ResetPin(port, pin)	port->BSRR = (uint32_t)pin << 16U
#define HAL_GPIO_Write(port, data)		port->ODR = data
#define HAL_GPIO_Read(port)				port->IDR

//
// One data port
//
#ifdef LCD_CONF_DB_GPIO
const GPIO_InitTypeDef lcd_port_bus_w = {GPIO_PIN_All, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_MEDIUM};
const GPIO_InitTypeDef lcd_port_bus_r = {GPIO_PIN_All, GPIO_MODE_INPUT,     GPIO_PULLUP, GPIO_SPEED_FREQ_MEDIUM};

void lcd_portStart(void) {
	GPIO_InitTypeDef p = {0, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_MEDIUM};

	LCD_CONF_RCCINIT();
	HAL_GPIO_Init(LCD_CONF_DB_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_w));
	p.Pin = LCD_CONF_CS_PIN;	HAL_GPIO_Init(LCD_CONF_CS_GPIO, &p);
	p.Pin = LCD_CONF_RS_PIN;	HAL_GPIO_Init(LCD_CONF_RS_GPIO, &p);
	p.Pin = LCD_CONF_WR_PIN;	HAL_GPIO_Init(LCD_CONF_WR_GPIO, &p);
	p.Pin = LCD_CONF_RD_PIN;	HAL_GPIO_Init(LCD_CONF_RD_GPIO, &p);
	HAL_GPIO_SetPin  (LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_RS_GPIO, LCD_CONF_RS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_WR_GPIO, LCD_CONF_WR_PIN);
	HAL_GPIO_SetPin  (LCD_CONF_RD_GPIO, LCD_CONF_RD_PIN);
	return;
}

void lcd_portWrite(char dc, unsigned short data) {
	static int	f;

	HAL_GPIO_Write(LCD_CONF_DB_GPIO, data);
	if (f != dc) {
		f = dc;
		HAL_GPIO_WritePin(LCD_CONF_RS_GPIO, LCD_CONF_RS_PIN, dc);
	}
//	HAL_GPIO_ResetPin(LCD_CONF_WR_GPIO, LCD_CONF_WR_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);	// Delay1
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);	// Delay2
	HAL_GPIO_SetPin  (LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
//	HAL_GPIO_SetPin  (LCD_CONF_WR_GPIO, LCD_CONF_WR_PIN);
	return;
}

unsigned short lcd_portRead(char dc) {
	unsigned short	data;

	HAL_GPIO_Init(LCD_CONF_DB_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_r));
	HAL_GPIO_WritePin(LCD_CONF_RS_GPIO, LCD_CONF_RS_PIN, dc);
	HAL_GPIO_SetPin  (LCD_CONF_RD_GPIO, LCD_CONF_WR_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_RD_GPIO, LCD_CONF_RD_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);

    data = HAL_GPIO_Read(LCD_CONF_DB_GPIO);
    HAL_GPIO_SetPin  (LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
    HAL_GPIO_SetPin  (LCD_CONF_RD_GPIO, LCD_CONF_RD_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_RD_GPIO, LCD_CONF_WR_PIN);
    HAL_GPIO_Init(LCD_CONF_DB_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_w));
	return(data);
}

//
// Two data port
//
#else	// LCD_CONF_DB_GPIO
const GPIO_InitTypeDef lcd_port_bus_w1 = {LCD_CONF_DB1_PIN, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_MEDIUM};
const GPIO_InitTypeDef lcd_port_bus_w2 = {LCD_CONF_DB2_PIN, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_MEDIUM};
const GPIO_InitTypeDef lcd_port_bus_r1 = {LCD_CONF_DB1_PIN, GPIO_MODE_INPUT,     GPIO_PULLUP, GPIO_SPEED_FREQ_MEDIUM};
const GPIO_InitTypeDef lcd_port_bus_r2 = {LCD_CONF_DB2_PIN, GPIO_MODE_INPUT,     GPIO_PULLUP, GPIO_SPEED_FREQ_MEDIUM};

void lcd_portStart(void) {
	GPIO_InitTypeDef p = {0, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_MEDIUM};

	LCD_CONF_RCCINIT();
	HAL_GPIO_Init(LCD_CONF_DB1_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_w1));
	HAL_GPIO_Init(LCD_CONF_DB2_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_w2));
	p.Pin = LCD_CONF_CS_PIN;	HAL_GPIO_Init(LCD_CONF_CS_GPIO, &p);
	p.Pin = LCD_CONF_RS_PIN;	HAL_GPIO_Init(LCD_CONF_RS_GPIO, &p);
	p.Pin = LCD_CONF_WR_PIN;	HAL_GPIO_Init(LCD_CONF_WR_GPIO, &p);
	p.Pin = LCD_CONF_RD_PIN;	HAL_GPIO_Init(LCD_CONF_RD_GPIO, &p);
	HAL_GPIO_SetPin  (LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_RS_GPIO, LCD_CONF_RS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_WR_GPIO, LCD_CONF_WR_PIN);
	HAL_GPIO_SetPin  (LCD_CONF_RD_GPIO, LCD_CONF_RD_PIN);
	return;
}

void lcd_portWrite(char dc, unsigned short data) {
	static int	f;

	HAL_GPIO_Write(LCD_CONF_DB1_GPIO, (HAL_GPIO_Read(LCD_CONF_DB1_GPIO) & ~LCD_CONF_DB1_PIN) | (data & LCD_CONF_DB1_PIN));
	HAL_GPIO_Write(LCD_CONF_DB2_GPIO, (HAL_GPIO_Read(LCD_CONF_DB2_GPIO) & ~LCD_CONF_DB2_PIN) | (data & LCD_CONF_DB2_PIN));
	if (f != dc) {
		f = dc;
		HAL_GPIO_WritePin(LCD_CONF_RS_GPIO, LCD_CONF_RS_PIN, dc);
	}
//	HAL_GPIO_ResetPin(LCD_CONF_WR_GPIO, LCD_CONF_WR_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);	// Delay1
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);	// Delay2
	HAL_GPIO_SetPin  (LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
//	HAL_GPIO_SetPin  (LCD_CONF_WR_GPIO, LCD_CONF_WR_PIN);
	return;
}

unsigned short lcd_portRead(char dc) {
	unsigned short	data;

	HAL_GPIO_Init(LCD_CONF_DB1_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_r1));
	HAL_GPIO_Init(LCD_CONF_DB2_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_r2));
	HAL_GPIO_WritePin(LCD_CONF_RS_GPIO, LCD_CONF_RS_PIN, dc);
	HAL_GPIO_SetPin  (LCD_CONF_RD_GPIO, LCD_CONF_WR_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_RD_GPIO, LCD_CONF_RD_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);

    data = (HAL_GPIO_Read(LCD_CONF_DB1_GPIO) & LCD_CONF_DB2_PIN)
         | (HAL_GPIO_Read(LCD_CONF_DB2_GPIO) & LCD_CONF_DB2_PIN));
    HAL_GPIO_SetPin  (LCD_CONF_CS_GPIO, LCD_CONF_CS_PIN);
    HAL_GPIO_SetPin  (LCD_CONF_RD_GPIO, LCD_CONF_RD_PIN);
	HAL_GPIO_ResetPin(LCD_CONF_RD_GPIO, LCD_CONF_WR_PIN);
    HAL_GPIO_Init(LCD_CONF_DB1_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_w1));
    HAL_GPIO_Init(LCD_CONF_DB2_GPIO, (GPIO_InitTypeDef *)&(lcd_port_bus_w2));
	return(data);
}
#endif	// LCD_CONF_DB_GPIO

void lcd_portWait(int ms) {
	uint32_t	w;
	w = HAL_GetTick() + ms;
	while(w > HAL_GetTick());
	return;
}


//---------------------------------------------------------------------
//
//						StdPeriph_Driver
//
//---------------------------------------------------------------------
#else	// USE_HAL_DRIVER				//

#include "stm32f4xx_gpio.h"				// Public library
#include "stm32f4xx_rcc.h"				// Public library

// Hardware config
#define LCD_CONF_DB1_GPIO		GPIOD
#define LCD_CONF_DB1_PIN		(GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3)
#define LCD_CONF_DB2_GPIO		GPIOE
#define LCD_CONF_DB2_PIN		(GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15)
#define LCD_CONF_CS_GPIO		GPIOC
#define LCD_CONF_CS_PIN			GPIO_Pin_11
#define LCD_CONF_RS_GPIO		GPIOC
#define LCD_CONF_RS_PIN			GPIO_Pin_6
#define LCD_CONF_WR_GPIO		GPIOC
#define LCD_CONF_WR_PIN			GPIO_Pin_8
#define LCD_CONF_RD_GPIO		GPIOC
#define LCD_CONF_RD_PIN			GPIO_Pin_9
#define LCD_CONF_RCCINIT()		{\
								RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);\
								RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);\
								RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);\
								}
										// ADD END 2017.04.15
//
//	I/O Port define
//
const struct {
	GPIO_TypeDef*		bus1_gpio;
	GPIO_InitTypeDef	bus1_w;
	GPIO_InitTypeDef	bus1_r;

	GPIO_TypeDef*		bus2_gpio;
	GPIO_InitTypeDef	bus2_w;
	GPIO_InitTypeDef	bus2_r;

	GPIO_TypeDef*		cs_gpio;
	GPIO_InitTypeDef	cs;

	GPIO_TypeDef*		rs_gpio;
	GPIO_InitTypeDef	rs;

	GPIO_TypeDef*		wr_gpio;
	GPIO_InitTypeDef	wr;

	GPIO_TypeDef*		rd_gpio;
	GPIO_InitTypeDef	rd;
} lcd_port = {
	LCD_CONF_DB1_GPIO,
	{LCD_CONF_DB1_PIN, GPIO_Mode_OUT,GPIO_Speed_25MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},
	{LCD_CONF_DB1_PIN, GPIO_Mode_IN, GPIO_Speed_25MHz, GPIO_OType_PP, GPIO_PuPd_UP    },

	LCD_CONF_DB2_GPIO,
	{LCD_CONF_DB2_PIN, GPIO_Mode_OUT,GPIO_Speed_25MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},
	{LCD_CONF_DB2_PIN, GPIO_Mode_IN, GPIO_Speed_25MHz, GPIO_OType_PP, GPIO_PuPd_UP    },

	LCD_CONF_CS_GPIO,
	{LCD_CONF_CS_PIN, GPIO_Mode_OUT, GPIO_Speed_25MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},

	LCD_CONF_RS_GPIO,
	{LCD_CONF_RS_PIN, GPIO_Mode_OUT, GPIO_Speed_25MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},

	LCD_CONF_WR_GPIO,
	{LCD_CONF_WR_PIN, GPIO_Mode_OUT, GPIO_Speed_25MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},

	LCD_CONF_RD_GPIO,
	{LCD_CONF_RD_PIN, GPIO_Mode_OUT, GPIO_Speed_25MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL}
};


//
//	Open
//
void lcd_portStart(void) {
	LCD_CONF_RCCINIT();

	GPIO_Init(lcd_port.bus1_gpio, (GPIO_InitTypeDef *)&(lcd_port.bus1_w));
	GPIO_Init(lcd_port.bus2_gpio, (GPIO_InitTypeDef *)&(lcd_port.bus2_w));
	GPIO_Init(lcd_port.cs_gpio,   (GPIO_InitTypeDef *)&(lcd_port.cs));
	GPIO_Init(lcd_port.rs_gpio,   (GPIO_InitTypeDef *)&(lcd_port.rs));
	GPIO_Init(lcd_port.wr_gpio,   (GPIO_InitTypeDef *)&(lcd_port.wr));
	GPIO_Init(lcd_port.rd_gpio,   (GPIO_InitTypeDef *)&(lcd_port.rd));

    GPIO_SetBits(lcd_port.cs_gpio, lcd_port.cs.GPIO_Pin);
    GPIO_SetBits(lcd_port.rs_gpio, lcd_port.rs.GPIO_Pin);
    GPIO_SetBits(lcd_port.wr_gpio, lcd_port.wr.GPIO_Pin);
    GPIO_SetBits(lcd_port.rd_gpio, lcd_port.rd.GPIO_Pin);

	return;
}

//
// 	Port I/O
//
void lcd_portWrite(char dc, unsigned short data) {

	GPIO_Write(lcd_port.bus1_gpio, (GPIO_ReadOutputData(lcd_port.bus1_gpio) & ~lcd_port.bus1_w.GPIO_Pin) | (data & lcd_port.bus1_w.GPIO_Pin));
	GPIO_Write(lcd_port.bus2_gpio, (GPIO_ReadOutputData(lcd_port.bus2_gpio) & ~lcd_port.bus2_w.GPIO_Pin) | (data & lcd_port.bus2_w.GPIO_Pin));

	GPIO_WriteBit(lcd_port.rs_gpio, lcd_port.rs.GPIO_Pin, dc);
	GPIO_ResetBits(lcd_port.wr_gpio, lcd_port.wr.GPIO_Pin);
	GPIO_ResetBits(lcd_port.cs_gpio, lcd_port.cs.GPIO_Pin);

	GPIO_SetBits(lcd_port.cs_gpio, lcd_port.cs.GPIO_Pin);
	GPIO_SetBits(lcd_port.wr_gpio, lcd_port.wr.GPIO_Pin);
	return;
}

unsigned short lcd_portRead(char dc) {
	unsigned short	data;

	GPIO_Init(lcd_port.bus1_gpio, (GPIO_InitTypeDef *)&lcd_port.bus1_r);
	GPIO_Init(lcd_port.bus2_gpio, (GPIO_InitTypeDef *)&lcd_port.bus2_r);

	GPIO_WriteBit(lcd_port.rs_gpio, lcd_port.rs.GPIO_Pin, dc);
    GPIO_ResetBits(lcd_port.rd_gpio, lcd_port.rd.GPIO_Pin);
    GPIO_ResetBits(lcd_port.cs_gpio, lcd_port.cs.GPIO_Pin);

	data  = GPIO_ReadInputData(lcd_port.bus1_gpio) & lcd_port.bus1_r.GPIO_Pin;
	data |= GPIO_ReadInputData(lcd_port.bus2_gpio) & lcd_port.bus2_r.GPIO_Pin;

	GPIO_SetBits(lcd_port.cs_gpio, lcd_port.cs.GPIO_Pin);
    GPIO_SetBits(lcd_port.rd_gpio, lcd_port.rd.GPIO_Pin);

	GPIO_Init(lcd_port.bus1_gpio, (GPIO_InitTypeDef *)&lcd_port.bus1_w);
	GPIO_Init(lcd_port.bus2_gpio, (GPIO_InitTypeDef *)&lcd_port.bus2_w);

	return(data);
}

#endif	// USE_HAL_DRIVER				// ADD 2017.04.15

