diff --git a/drivers/aip31068/Makefile b/drivers/aip31068/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/aip31068/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/aip31068/Makefile.dep b/drivers/aip31068/Makefile.dep new file mode 100644 index 0000000000..f9167d261d --- /dev/null +++ b/drivers/aip31068/Makefile.dep @@ -0,0 +1,8 @@ +FEATURES_REQUIRED += periph_i2c + +USEMODULE += xtimer + +ifeq (esp32,$(CPU)) + # necessary to fix driver initialization on esp32 + USEMODULE += esp_i2c_hw +endif diff --git a/drivers/aip31068/Makefile.include b/drivers/aip31068/Makefile.include new file mode 100644 index 0000000000..ae3baa531b --- /dev/null +++ b/drivers/aip31068/Makefile.include @@ -0,0 +1,2 @@ +USEMODULE_INCLUDES_aip31068 := $(LAST_MAKEFILEDIR)/include +USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_aip31068) diff --git a/drivers/aip31068/aip31068.c b/drivers/aip31068/aip31068.c new file mode 100644 index 0000000000..305f794097 --- /dev/null +++ b/drivers/aip31068/aip31068.c @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2020 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_aip31068 + * @brief Device driver for AIP31068 + * @author Hendrik van Essen + * @file + * @{ + */ + +#include + +#include "xtimer.h" + +#include "aip31068.h" +#include "aip31068_regs.h" +#include "aip31068_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Write a data byte to the device. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] value Data byte to write + * + * @return 0 on success + * @return -1 if acquiring of I2C bus fails + * @return -EIO When slave device doesn't ACK the byte + * @return -ENXIO When no devices respond on the address sent on the bus + * @return -ETIMEDOUT When timeout occurs before device's response + * @return -EINVAL When an invalid argument is given + * @return -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @return -EAGAIN When a lost bus arbitration occurs + */ +static inline int _data(aip31068_t *dev, uint8_t value); + +/** + * @brief Write a command byte with it's arguments (modified bits) to the device. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] value Command byte to write + * + * @return 0 on success + * @return -1 if acquiring of I2C bus fails + * @return -EIO When slave device doesn't ACK the byte + * @return -ENXIO When no devices respond on the address sent on the bus + * @return -ETIMEDOUT When timeout occurs before device's response + * @return -EINVAL When an invalid argument is given + * @return -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @return -EAGAIN When a lost bus arbitration occurs + */ +static inline int _command(aip31068_t *dev, uint8_t value); + +/** + * @brief Write a command or data byte to the device. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] data_byte Byte to write + * @param[in] is_cmd Whether byte should be interpreted as data or command + * + * @return 0 on success + * @return -1 if acquiring of I2C bus fails + * @return -EIO When slave device doesn't ACK the byte + * @return -ENXIO When no devices respond on the address sent on the bus + * @return -ETIMEDOUT When timeout occurs before device's response + * @return -EINVAL When an invalid argument is given + * @return -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @return -EAGAIN When a lost bus arbitration occurs + */ +static inline int _write(aip31068_t *dev, uint8_t data_byte, bool is_cmd); + +/** + * @brief Write data to the device. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] data Data to write + * @param[in] len Length of the data + * + * @return 0 on success + * @return -1 if acquiring of I2C bus fails + * @return -EIO When slave device doesn't ACK the byte + * @return -ENXIO When no devices respond on the address sent on the bus + * @return -ETIMEDOUT When timeout occurs before device's response + * @return -EINVAL When an invalid argument is given + * @return -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @return -EAGAIN When a lost bus arbitration occurs + */ +static int _device_write(aip31068_t *dev, uint8_t *data, uint8_t len); + +int aip31068_init(aip31068_t *dev, const aip31068_params_t *params) +{ + assert(dev); + assert(params); + + /* displays with more than 4 lines are not supported + * (see aip31068_set_cursor_position) */ + assert(params->row_count <= 4); + + dev->params = *params; + dev->_curr_display_control = 0; + dev->_curr_entry_mode_set = 0; + + i2c_init(dev->params.i2c_dev); + + uint8_t _function_set = 0; + + /* configure bit mode */ + if (params->bit_mode == BITMODE_8_BIT) { + SETBIT(_function_set, AIP31068_BIT_FUNCTION_SET_BITMODE); + } + + /* configure line count */ + if (params->row_count >= 2) { + SETBIT(_function_set, AIP31068_BIT_FUNCTION_SET_LINECOUNT); + } + + /* configure character size */ + if (params->font_size == FONT_SIZE_5x10) { + SETBIT(_function_set, AIP31068_BIT_FUNCTION_SET_FONTSIZE); + } + + /* Begin of the initialization sequence (page 20 in the datasheet). + * The initialization sequence here is writing AIP31068_CMD_FUNCTION_SET + * three times with different sleep periods in between according to the + * data sheet of the HD44780. The AIP31068 is forwarding commands to the + * HD44780 hidden behind it so to be sure that it works for all kinds of + * HD44780 we follow the initialization sequence of the HD44780, even though + * it might be unnecessary for others. */ + xtimer_usleep(50 * US_PER_MS); + + int rc = 0; + + /* send function set command sequence */ + rc = _command(dev, AIP31068_CMD_FUNCTION_SET | _function_set); + if (rc < 0) { + return rc; + } + + /* wait after the first try */ + xtimer_usleep(5 * US_PER_MS); + + /* second try */ + rc = _command(dev, AIP31068_CMD_FUNCTION_SET | _function_set); + if (rc < 0) { + return rc; + } + + /* wait after the second try */ + xtimer_usleep(500); + + /* third go */ + rc = _command(dev, AIP31068_CMD_FUNCTION_SET | _function_set); + if (rc < 0) { + return rc; + } + + rc = aip31068_turn_off(dev); + if (rc < 0) { + return rc; + } + + rc = aip31068_clear(dev); + if (rc < 0) { + return rc; + } + + rc = aip31068_set_text_insertion_mode(dev, LEFT_TO_RIGHT); + if (rc < 0) { + return rc; + } + + /* End of the initialization sequence. */ + + return 0; +} + +int aip31068_turn_on(aip31068_t *dev) +{ + SETBIT(dev->_curr_display_control, AIP31068_BIT_DISPLAY_CONTROL_DISPLAY); + + return _command(dev, AIP31068_CMD_DISPLAY_CONTROL | dev->_curr_display_control); +} + +int aip31068_turn_off(aip31068_t *dev) +{ + CLRBIT(dev->_curr_display_control, AIP31068_BIT_DISPLAY_CONTROL_DISPLAY); + + return _command(dev, AIP31068_CMD_DISPLAY_CONTROL | dev->_curr_display_control); +} + +int aip31068_clear(aip31068_t *dev) +{ + int rc = _command(dev, AIP31068_CMD_CLEAR_DISPLAY); + + xtimer_usleep(AIP31068_EXECUTION_TIME_MAX); + + return rc; +} + +int aip31068_return_home(aip31068_t *dev) +{ + int rc = _command(dev, AIP31068_CMD_RETURN_HOME); + + xtimer_usleep(AIP31068_EXECUTION_TIME_MAX); + + return rc; +} + +int aip31068_set_auto_scroll_enabled(aip31068_t *dev, bool enabled) +{ + if (enabled) { + SETBIT(dev->_curr_entry_mode_set, AIP31068_BIT_ENTRY_MODE_AUTOINCREMENT); + } + else { + CLRBIT(dev->_curr_entry_mode_set, AIP31068_BIT_ENTRY_MODE_AUTOINCREMENT); + } + + return _command(dev, AIP31068_CMD_ENTRY_MODE_SET | dev->_curr_entry_mode_set); +} + +int aip31068_set_cursor_blinking_enabled(aip31068_t *dev, bool enabled) +{ + if (enabled) { + SETBIT(dev->_curr_display_control, AIP31068_BIT_DISPLAY_CONTROL_CURSOR_BLINKING); + } + else { + CLRBIT(dev->_curr_display_control, AIP31068_BIT_DISPLAY_CONTROL_CURSOR_BLINKING); + } + + return _command(dev, AIP31068_CMD_DISPLAY_CONTROL | dev->_curr_display_control); +} + +int aip31068_set_cursor_visible(aip31068_t *dev, bool visible) +{ + if (visible) { + SETBIT(dev->_curr_display_control, AIP31068_BIT_DISPLAY_CONTROL_CURSOR); + } + else { + CLRBIT(dev->_curr_display_control, AIP31068_BIT_DISPLAY_CONTROL_CURSOR); + } + + return _command(dev, AIP31068_CMD_DISPLAY_CONTROL | dev->_curr_display_control); +} + +int aip31068_set_cursor_position(aip31068_t *dev, uint8_t row, uint8_t col) +{ + uint8_t row_offsets[4]; + row_offsets[0] = 0x00; + row_offsets[1] = 0x40; + row_offsets[2] = 0x00 + dev->params.col_count; + row_offsets[3] = 0x40 + dev->params.col_count; + + if (row >= dev->params.row_count) { + row = dev->params.row_count - 1; + } + + return _command(dev, AIP31068_CMD_SET_DDRAM_ADDR | (col | row_offsets[row])); +} + +int aip31068_set_text_insertion_mode(aip31068_t *dev, + aip31068_text_insertion_mode_t mode) +{ + if (mode == LEFT_TO_RIGHT) { + SETBIT(dev->_curr_entry_mode_set, AIP31068_BIT_ENTRY_MODE_INCREMENT); + } + else { + CLRBIT(dev->_curr_entry_mode_set, AIP31068_BIT_ENTRY_MODE_INCREMENT); + } + + return _command(dev, AIP31068_CMD_ENTRY_MODE_SET | dev->_curr_entry_mode_set); +} + +int aip31068_move_cursor_left(aip31068_t *dev) +{ + uint8_t cmd = AIP31068_CMD_CURSOR_DISPLAY_SHIFT; + CLRBIT(cmd, AIP31068_BIT_CURSOR_DISPLAY_SHIFT_DIRECTION); + + return _command(dev, cmd); +} + +int aip31068_move_cursor_right(aip31068_t *dev) +{ + uint8_t cmd = AIP31068_CMD_CURSOR_DISPLAY_SHIFT; + SETBIT(cmd, AIP31068_BIT_CURSOR_DISPLAY_SHIFT_DIRECTION); + + return _command(dev, cmd); +} + +int aip31068_scroll_display_left(aip31068_t *dev) +{ + uint8_t cmd = AIP31068_CMD_CURSOR_DISPLAY_SHIFT; + SETBIT(cmd, AIP31068_BIT_CURSOR_DISPLAY_SHIFT_SELECTION); + CLRBIT(cmd, AIP31068_BIT_CURSOR_DISPLAY_SHIFT_DIRECTION); + + return _command(dev, cmd); +} + +int aip31068_scroll_display_right(aip31068_t *dev) +{ + uint8_t cmd = AIP31068_CMD_CURSOR_DISPLAY_SHIFT; + SETBIT(cmd, AIP31068_BIT_CURSOR_DISPLAY_SHIFT_SELECTION); + SETBIT(cmd, AIP31068_BIT_CURSOR_DISPLAY_SHIFT_DIRECTION); + + return _command(dev, cmd); +} + +int aip31068_set_custom_symbol(aip31068_t *dev, + aip31068_custom_symbol_t custom_symbol, + const uint8_t charmap[]) +{ + /* Bits 0-2 define the row address of a custom character in CGRAM. + * Bits 3-5 define the base address of a custom character in CGRAM. */ + uint8_t location = custom_symbol << 3; + int rc = _command(dev, AIP31068_CMD_SET_CGRAM_ADDR | location); + + if (rc < 0) { + return rc; + } + + /* How many rows are necessary for a complete character for given font? */ + int row_count = dev->params.font_size == FONT_SIZE_5x8 ? 8 : 10; + + for (int i = 0; i < row_count; i++) { + rc = _data(dev, charmap[i]); + + if (rc < 0) { + return rc; + } + } + + return _command(dev, AIP31068_CMD_SET_DDRAM_ADDR); +} + +int aip31068_print_custom_symbol(aip31068_t *dev, + aip31068_custom_symbol_t custom_symbol) +{ + return _data(dev, (uint8_t) custom_symbol); +} + +int aip31068_print(aip31068_t *dev, const char *data) +{ + while (*data != '\0') { + int rc; + if ((rc = _data(dev, *data)) != 0) { + return rc; + } + data++; + } + + return 0; +} + +int aip31068_print_char(aip31068_t *dev, char c) +{ + return _data(dev, c); +} + +static inline int _data(aip31068_t *dev, uint8_t value) +{ + int rc = _write(dev, value, false); + + xtimer_usleep(AIP31068_EXECUTION_TIME_DEFAULT); + + return rc; +} + +static inline int _command(aip31068_t *dev, uint8_t value) +{ + int rc = _write(dev, value, true); + + xtimer_usleep(AIP31068_EXECUTION_TIME_DEFAULT); + + return rc; +} + +static inline int _write(aip31068_t *dev, uint8_t data_byte, bool is_cmd) +{ + uint8_t control_byte = 0; + if (!is_cmd) { + SETBIT(control_byte, AIP31068_BIT_CONTROL_BYTE_RS); + } + + uint8_t data[] = { control_byte, data_byte }; + + return _device_write(dev, data, sizeof(data)); +} + +static int _device_write(aip31068_t* dev, uint8_t *data, uint8_t len) +{ + i2c_t i2c_dev = dev->params.i2c_dev; + + if (i2c_acquire(i2c_dev) != 0) { + return -1; + } + + int rc = i2c_write_bytes(i2c_dev, dev->params.i2c_addr, data, len, 0); + + i2c_release(i2c_dev); + + return rc; +} diff --git a/drivers/aip31068/include/aip31068_internal.h b/drivers/aip31068/include/aip31068_internal.h new file mode 100644 index 0000000000..5aca847bb3 --- /dev/null +++ b/drivers/aip31068/include/aip31068_internal.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_aip31068 + * @brief Internal definitions for the AIP31068 I2C LCD controller + * @author Hendrik van Essen + * @file + * @{ + */ + +#ifndef AIP31068_INTERNAL_H +#define AIP31068_INTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Longest execution time is 1.52 ms for 'clear' and 'home' command + */ +#define AIP31068_EXECUTION_TIME_MAX (1600U) + +/** + * @brief Execution time for writing to RAM is given as 43 µs + * Execution time for most commands is given as 37 µs + */ +#define AIP31068_EXECUTION_TIME_DEFAULT (50U) + +#ifdef __cplusplus +} +#endif + +#endif /* AIP31068_INTERNAL_H */ +/** @} */ diff --git a/drivers/aip31068/include/aip31068_params.h b/drivers/aip31068/include/aip31068_params.h new file mode 100644 index 0000000000..66933d4dda --- /dev/null +++ b/drivers/aip31068/include/aip31068_params.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_aip31068 + * @brief Default configuration for the AIP31068 I2C LCD controller + * + * @{ + * + * @author Hendrik van Essen + * @file + */ +#ifndef AIP31068_PARAMS_H +#define AIP31068_PARAMS_H + +#include + +#include "periph/i2c.h" + +#include "aip31068_regs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** +* @name Set default configuration parameters +* @{ +*/ +#ifndef AIP31068_PARAM_I2C_DEV +/** I2C device is I2C_DEV(0) */ +#define AIP31068_PARAM_I2C_DEV I2C_DEV(0) +#endif + +#ifndef AIP31068_PARAM_I2C_ADDR +/** I2C address of device is (0x7c >> 1) */ +#define AIP31068_PARAM_I2C_ADDR (0x7c >> 1) +#endif + +#ifndef AIP31068_PARAMS +#define AIP31068_PARAMS \ + { \ + .i2c_dev = AIP31068_PARAM_I2C_DEV, \ + .i2c_addr = AIP31068_PARAM_I2C_ADDR, \ + .row_count = 2, \ + .col_count = 16, \ + .font_size = FONT_SIZE_5x8, \ + .bit_mode = BITMODE_8_BIT, \ + } +#endif /* AIP31068_PARAMS */ +/**@}*/ + +/** + * @brief Allocate some memory to store the actual configuration + */ +static const aip31068_params_t aip31068_params[] = +{ + AIP31068_PARAMS +}; + +#ifdef __cplusplus +} +#endif + +#endif /* AIP31068_PARAMS_H */ +/** @} */ diff --git a/drivers/aip31068/include/aip31068_regs.h b/drivers/aip31068/include/aip31068_regs.h new file mode 100644 index 0000000000..c5f0f67f93 --- /dev/null +++ b/drivers/aip31068/include/aip31068_regs.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2020 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_aip31068 + * @brief Register definitions for the AIP31068 I2C LCD controller + * @author Hendrik van Essen + * @file + * @{ + */ + +#ifndef AIP31068_REGS_H +#define AIP31068_REGS_H + +#include "bitarithm.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Commands (page 18, table 3) */ + +/** + * @brief Clears entire display and sets cursor to position (0, 0). + * + * @note: Also changes AIP31068_BIT_ENTRY_MODE_INCREMENT to 1 + */ +#define AIP31068_CMD_CLEAR_DISPLAY 0x01 + +/** + * @brief Sets cursor to position (0, 0) and resets display to original position + * before any shift operations. + */ +#define AIP31068_CMD_RETURN_HOME 0x02 + +/** + * @brief Sets cursor move direction and specifies display shift. + */ +#define AIP31068_CMD_ENTRY_MODE_SET 0x04 + +/** + * @brief Sets entire display on/off, cursor on/off, and blinking of cursor + * position character on/off. + */ +#define AIP31068_CMD_DISPLAY_CONTROL 0x08 + +/** + * @brief Moves cursor and shifts display. + */ +#define AIP31068_CMD_CURSOR_DISPLAY_SHIFT 0x10 + +/** + * @brief Sets interface data length, number of display lines and character + * font size. + */ +#define AIP31068_CMD_FUNCTION_SET 0x20 + +/** + * @brief Sets CGRAM address. + */ +#define AIP31068_CMD_SET_CGRAM_ADDR 0x40 + +/** + * @brief Sets DDRAM address. + */ +#define AIP31068_CMD_SET_DDRAM_ADDR 0x80 + + + +/* Bits for AIP31068_CMD_ENTRY_MODE_SET (page 16, section 3) */ + +/** + * @brief 0 = Decrement cursor after insertion + * 1 = Increment cursor after insertion + */ +#define AIP31068_BIT_ENTRY_MODE_INCREMENT BIT1 + +/** + * @brief 0 = No automated display scroll + * 1 = Automated display scroll + */ +#define AIP31068_BIT_ENTRY_MODE_AUTOINCREMENT BIT0 + + + +/* Bits for AIP31068_CMD_DISPLAY_CONTROL (page 16, section 4) */ + +/** + * @brief 0 = Display off + * 1 = Display on + */ +#define AIP31068_BIT_DISPLAY_CONTROL_DISPLAY BIT2 + +/** + * @brief 0 = Cursor off + * 1 = Cursor on + */ +#define AIP31068_BIT_DISPLAY_CONTROL_CURSOR BIT1 + +/** + * @brief 0 = Cursor blinking off + * 1 = Cursor blinking on + */ +#define AIP31068_BIT_DISPLAY_CONTROL_CURSOR_BLINKING BIT0 + + + +/* Bits for AIP31068_CMD_CURSOR_DISPLAY_SHIFT (page 17, section 5) */ + +/** + * @brief 0 = Shift the cursor position + * 1 = Scroll the display content + */ +#define AIP31068_BIT_CURSOR_DISPLAY_SHIFT_SELECTION BIT3 + +/** + * @brief 0 = Shift to the left + * 1 = Shift to the right + */ +#define AIP31068_BIT_CURSOR_DISPLAY_SHIFT_DIRECTION BIT2 + + + +/* Bits for AIP31068_CMD_FUNCTION_SET (page 17, section 6) */ + +/** + * @brief 0 = 4 bit interface data length + * 1 = 8 bit interface data length + */ +#define AIP31068_BIT_FUNCTION_SET_BITMODE BIT4 + +/** + * @brief 0 = Single line + * 1 = Two lines + */ +#define AIP31068_BIT_FUNCTION_SET_LINECOUNT BIT3 + +/** + * @brief 0 = 5x8 dots per character + * 1 = 5x10 dots per character + */ +#define AIP31068_BIT_FUNCTION_SET_FONTSIZE BIT2 + + + +/* Bits for control byte (page 12) */ + +/** + * @brief 0 = Last control byte + * 1 = Another control byte follows data byte + */ +#define AIP31068_BIT_CONTROL_BYTE_CO BIT7 + +/** + * @brief 0 = data byte interpreted as command + * 1 = data byte interpreted as data + */ +#define AIP31068_BIT_CONTROL_BYTE_RS BIT6 + +#ifdef __cplusplus +} +#endif + +#endif /* AIP31068_REGS_H */ +/** @} */ diff --git a/drivers/include/aip31068.h b/drivers/include/aip31068.h new file mode 100644 index 0000000000..867aefec3a --- /dev/null +++ b/drivers/include/aip31068.h @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2020 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_aip31068 AIP31068 I2C LCD controller + * @ingroup drivers_display + * @brief Device driver for AIP31068 + * + * @{ + * + * @author Hendrik van Essen + * @file + */ + +#ifndef AIP31068_H +#define AIP31068_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "stdbool.h" +#include "periph/i2c.h" + +#include "aip31068_regs.h" + +/** +* @brief Keys for custom symbols. +*/ +typedef enum { + CUSTOM_SYMBOL_1 = 0, /**< 1st custom symbol */ + CUSTOM_SYMBOL_2 = 1, /**< 2nd custom symbol */ + CUSTOM_SYMBOL_3 = 2, /**< 3rd custom symbol */ + CUSTOM_SYMBOL_4 = 3, /**< 4th custom symbol */ + CUSTOM_SYMBOL_5 = 4, /**< 5th custom symbol */ + CUSTOM_SYMBOL_6 = 5, /**< 6th custom symbol */ + CUSTOM_SYMBOL_7 = 6, /**< 7th custom symbol */ + CUSTOM_SYMBOL_8 = 7, /**< 8th custom symbol */ +} aip31068_custom_symbol_t; + +/** + * @brief Defines the direction of the text insertion. Starting from the cursor, + * either increment the column of the cursor position after insertion + * (LEFT_TO_RIGHT), or decrement the current column of the cursor + * position after insertion (RIGHT_TO_LEFT). + */ +typedef enum { + LEFT_TO_RIGHT, /**< Insert text from left to right */ + RIGHT_TO_LEFT, /**< Insert text from right to left */ +} aip31068_text_insertion_mode_t; + +/** +* @brief Size of a character of the display in dots/pixels. +*/ +typedef enum { + FONT_SIZE_5x8, /**< Single character has 5x8 pixels */ + FONT_SIZE_5x10, /**< Single character has 5x10 pixels */ +} aip31068_font_size_t; + +/** + * @brief Bit mode for the display. + */ +typedef enum { + BITMODE_4_BIT, /**< Use 4 bit mode */ + BITMODE_8_BIT, /**< Use 8 bit mode */ +} aip31068_bit_mode_t; + +/** + * @brief AIP31068 device initialization parameters + */ +typedef struct { + i2c_t i2c_dev; /**< I2C device */ + uint16_t i2c_addr; /**< I2C address of device */ + uint8_t row_count; /**< Number of rows */ + uint8_t col_count; /**< Number of columns */ + aip31068_font_size_t font_size; /**< Font size */ + aip31068_bit_mode_t bit_mode; /**< Bit mode */ +} aip31068_params_t; + +/** + * @brief AIP31068 PWM device data structure type + */ +typedef struct { + aip31068_params_t params; /**< Device initialization parameters */ + uint8_t _curr_display_control; /**< Current value of DISPLAY_CONTROL */ + uint8_t _curr_entry_mode_set; /**< Current value of ENTRY_MODE_SET */ +} aip31068_t; + +/** + * @brief Initialization. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] params Parameters for device initialization + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_init(aip31068_t *dev, const aip31068_params_t *params); + +/** + * @brief Turn on the display. + * + * @param[in] dev Device descriptor of the AIP31068 + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_turn_on(aip31068_t *dev); + +/** + * @brief Turn off the display. + * + * @param[in] dev Device descriptor of the AIP31068 + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_turn_off(aip31068_t *dev); + +/** + * @brief Clear the display and set the cursor to position (0, 0). + * + * @note: Also changes to setTextInsertionMode(LEFT_TO_RIGHT) + * + * @param[in] dev Device descriptor of the AIP31068 + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_clear(aip31068_t *dev); + +/** + * @brief Reset cursor position to (0, 0) and scroll display to original position. + * + * @param[in] dev Device descriptor of the AIP31068 + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_return_home(aip31068_t *dev); + +/** + * @brief Enable or disable automated scrolling. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] enabled Enable or disable + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_set_auto_scroll_enabled(aip31068_t *dev, bool enabled); + +/** + * @brief Enable or disable cursor blinking. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] enabled Enable or disable + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_set_cursor_blinking_enabled(aip31068_t *dev, bool enabled); + +/** + * @brief Show or hide the cursor. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] visible Show or hide + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_set_cursor_visible(aip31068_t *dev, bool visible); + +/** + * @brief Move the cursor to a given position. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] row Row of the new cursor position (starting at 0) + * @param[in] col Column of the new cursor position (starting at 0) + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_set_cursor_position(aip31068_t *dev, uint8_t row, uint8_t col); + +/** + * @brief Set the direction from which the text is inserted, starting from the cursor. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] mode Insertion mode + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_set_text_insertion_mode(aip31068_t *dev, + aip31068_text_insertion_mode_t mode); + +/** + * @brief Move the cursor one unit to the left. + * + * When the cursor passes the 40th character of the first line and a second line + * is available, the cursor will move to the second line. + * + * @param[in] dev Device descriptor of the AIP31068 + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_move_cursor_left(aip31068_t *dev); + +/** + * @brief Move the cursor one unit to the right. + * + * When the cursor passes the 40th character of the first line and a second line + * is available, the cursor will move to the second line. + * + * @note: The cursor respects the setting for the insertion mode and is set + * to (1, 0) for LEFT_TO_RIGHT and to (1, COL_MAX) for RIGHT_TO_LEFT. + * + * @param[in] dev Device descriptor of the AIP31068 + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_move_cursor_right(aip31068_t *dev); + +/** + * @brief Scroll the entire display content (all lines) one unit to the left. + * + * @note: The cursor respects the setting for the insertion mode and is set + * to (1, 0) for LEFT_TO_RIGHT and to (1, COL_MAX) for RIGHT_TO_LEFT. + * + * @param[in] dev Device descriptor of the AIP31068 + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_scroll_display_left(aip31068_t *dev); + +/** + * @brief Scroll the entire display content (all lines) one unit to the right. + * + * @param[in] dev Device descriptor of the AIP31068 + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_scroll_display_right(aip31068_t *dev); + +/** + * @brief Create a custom symbol. + * + * Useful link: https://maxpromer.github.io/LCD-Character-Creator/ + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] customSymbol Key to which a custom symbol should be assigned + * @param[in] charmap Bitmap definition of the custom symbol + * + * @note: The size of charmap depends on how the AIP31068 was initialized. + * 8 bytes for FONT_SIZE_5x8 and 10 bytes for FONT_SIZE_5x10. + * + * This function resets the cursor position. Therefore this function + * should be called before printing any characters to the display. + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_set_custom_symbol(aip31068_t *dev, + aip31068_custom_symbol_t customSymbol, + const uint8_t charmap[]); + +/** + * @brief Print a custom symbol by key reference. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] customSymbol Key of the custom symbol to be printed + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_print_custom_symbol(aip31068_t *dev, + aip31068_custom_symbol_t customSymbol); + +/** + * @brief Print a string. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] data String to be printed (null-terminated) + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_print(aip31068_t *dev, const char *data); + +/** + * @brief Print a single character. + * + * @param[in] dev Device descriptor of the AIP31068 + * @param[in] c Character to be printed + * + * @retval 0 on success + * @retval -1 if acquiring of I2C bus fails + * @retval -EIO When slave device doesn't ACK the byte + * @retval -ENXIO When no devices respond on the address sent on the bus + * @retval -ETIMEDOUT When timeout occurs before device's response + * @retval -EINVAL When an invalid argument is given + * @retval -EOPNOTSUPP When MCU driver doesn't support the flag operation + * @retval -EAGAIN When a lost bus arbitration occurs + */ +int aip31068_print_char(aip31068_t *dev, char c); + +#ifdef __cplusplus +} +#endif + +#endif /* AIP31068_H */ +/** @} */