# -*- coding: utf-8 -*-
"""
Created on Wed Jan 24 17:13:12 2024

@author: user01
"""

# -*- coding: utf-8 -*-
""" file DFRobot_RGBLCD1602.cpp
  # DFRobot_RGBLCD1602 class infrastructure, the implementation of basic methods
  @copyright	Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
  @licence     The MIT License (MIT)
  @maintainer [yangfeng](feng.yang@dfrobot.com)
  @version  V1.0
  @date  2021-09-24
  @url https://github.com/DFRobot/DFRobot_RGBLCD1602
"""
import time
import sys

# import wiringpi

LCD_ADDRESS = (0x7c >> 1)  # 0x3E or 62

# color define
WHITE = 0
RED = 1
GREEN = 2
BLUE = 3
REG_MODE1 = 0x00
REG_MODE2 = 0x01
REG_OUTPUT = 0x08
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80

# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00

# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00

# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00

from telemetrix import telemetrix

"""
This file contains a library to control an i2c LCD. 
See i2c_ldc_pcf8574_hello_world.py for an example of its use.

Rewriting the scipt to capture DFRobot RGBLCD1602 v2 features - from the header file DFRobot_RGBLCD1602.h


/*
Change the RGBaddr value based on the hardware version
-----------------------------------------
       Moudule        | Version| RGBAddr|
-----------------------------------------
  LCD1602 Module      |  V1.0  | 0x60   |
-----------------------------------------
  LCD1602 Module      |  V1.1  | 0x6B   |
-----------------------------------------
  LCD1602 RGB Module  |  V1.0  | 0x60   |
-----------------------------------------
  LCD1602 RGB Module  |  V2.0  | 0x2D   |
-----------------------------------------

Scanning...
I2C device found at address 0x2D !
I2C device found at address 0x3E !
done


*/
"""


# self.board.i2c_write(self._address, [output])


class DFRobot_RGBLCD1602:
    def __init__(self, board, address=LCD_ADDRESS, columns=16, rows=2, address_rgb=0x2D):
        # def __init__(self, board, rgb_addr,col, row):
        # self.i2c=i2c
        self._row = rows
        self._col = columns
        self._address = address
        self.RGB_ADDRESS = address_rgb
        print("LCD _row=%d _col=%d" % (self._row, self._col))
        # self.LCD = board.(LCD_ADDRESS)
        self.board = board

        self.board.set_pin_mode_i2c()
        self.board.i2c_write(self._address, [0])

        if self.RGB_ADDRESS == 0x60:
            self.REG_RED = 0x04
            self.REG_GREEN = 0x03
            self.REG_BLUE = 0x02
            self.REG_ONLY = 0x02
        elif self.RGB_ADDRESS == (0x60 >> 1):
            self.REG_RED = 0x06
            self.REG_GREEN = 0x07
            self.REG_BLUE = 0x08
            self.REG_ONLY = 0x08
        elif self.RGB_ADDRESS == 0x6B:
            self.REG_RED = 0x06
            self.REG_GREEN = 0x05
            self.REG_BLUE = 0x04
            self.REG_ONLY = 0x04
        elif self.RGB_ADDRESS == 0x2D:
            self.REG_RED = 0x01
            self.REG_GREEN = 0x02
            self.REG_BLUE = 0x03
            self.REG_ONLY = 0x01
        self._show_function = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS
        self._begin(self._row, self._col)

    def write(self, data):
        """
          @brief write character
          @param data the written data
        """
        b = bytearray(2)
        b[0] = 0x40
        b[1] = data
        self.board.i2c_write(self._address, [0x40, data])

    def set_RGB(self, r, g, b):
        """
          @brief set RGB
          @param r  red   range(0-255)
          @param g  green range(0-255)
          @param b  blue  range(0-255)
        """
        if self.RGB_ADDRESS == (0x60 >> 1):
            r = int(r * 192 / 255)
            g = int(g * 192 / 255)
            b = int(b * 192 / 255)

        self.board.i2c_write(self.RGB_ADDRESS, [self.REG_RED, r])
        self.board.i2c_write(self.RGB_ADDRESS, [self.REG_GREEN, g])
        self.board.i2c_write(self.RGB_ADDRESS, [self.REG_BLUE, b])
        if self.RGB_ADDRESS == 0x6b:
            self._set_reg(0x07, 0xFF)

    def set_cursor(self, col, row):
        """
          @brief set cursor position
          @param col columns optional range 0-15
          @param row rows optional range 0-1，0 is the first row, 1 is the second row
        """
        if row == 0:
            col |= 0x80
        else:
            col |= 0xc0
        self._command(col)

    def clear(self):
        """
          @brief clear the display and return the cursor to the initial position (position 0)
        """
        self._command(LCD_CLEARDISPLAY)
        time.sleep(0.002)

    def scroll_display_left(self):
        """
          @brief scroll left to display
        """
        self._command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT)

    def scroll_display_right(self):
        """
          @brief scroll right to display
        """
        self._command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT)

    def print_out(self, arg):
        """
          @brief output data to LCD to display
          @param arg output data
        """
        if isinstance(arg, int):
            arg = str(arg)

        for x in bytearray(arg, 'utf-8'):
            self.write(x)

    def home(self):
        """
          @brief return the cursor to the initial position（0,0）
        """
        self._command(LCD_RETURNHOME)  # set cursor position to zero
        time.sleep(1)  # this _command takes a long time!

    def no_display(self):
        """
          @brief Turn off the display
        """
        self._show_control &= ~LCD_DISPLAYON
        self._command(LCD_DISPLAYCONTROL | self._show_control)

    def display(self):
        """
          @brief Turn on the display
        """
        self._show_control |= LCD_DISPLAYON
        self._command(LCD_DISPLAYCONTROL | self._show_control)

    def stop_blink(self):
        """
          @brief Turn  off the blinking showCursor
        """
        self._show_control &= ~LCD_BLINKON
        self._command(LCD_DISPLAYCONTROL | self._show_control)

    def blink(self):
        """
          @brief Turn on  the blinking showCursor
        """
        self._show_control |= LCD_BLINKON
        self._command(LCD_DISPLAYCONTROL | self._show_control)

    def no_cursor(self):
        """
          @brief Turn off the underline showCursor 
        """
        self._show_control &= ~LCD_CURSORON
        self._command(LCD_DISPLAYCONTROL | self._show_control)

    def cursor(self):
        """
          @brief Turn on the underline showCursor 
        """
        self._show_control |= LCD_CURSORON
        self._command(LCD_DISPLAYCONTROL | self._show_control)

    def left_to_right(self):
        """
          @brief This is for text that flows Left to Right
        """
        self._show_mode |= LCD_ENTRYLEFT
        self._command(LCD_ENTRYMODESET | self._show_mode)

    def right_to_left(self):
        """
          @brief This is for text that flows Right to Left
        """
        self._show_mode &= ~LCD_ENTRYLEFT
        self._command(LCD_ENTRYMODESET | self._show_mode)

    def no_autoscroll(self):
        """
          @brief This will 'left justify' text from the showCursor
        """
        self._show_mode &= ~LCD_ENTRYSHIFTINCREMENT
        self._command(LCD_ENTRYMODESET | self._show_mode)

    def autoscroll(self):
        """
          @brief This will 'right justify' text from the showCursor
        """
        self._show_mode |= LCD_ENTRYSHIFTINCREMENT
        self._command(LCD_ENTRYMODESET | self._show_mode)

    def custom_symbol(self, location, charmap):
        """
          @brief Allows us to fill the first 8 C
          @param location substitute character range（0-7）
          @param charmap  character listing the size is 8 bytes
        """
        location &= 0x7  # we only have 8 locations 0-7
        self._command(LCD_SETCGRAMADDR | (location << 3))
        for i in range(0, 8):
            # wiringpi.wiringPiI2CWriteReg8(self.LCD,0x40,charmap[i])
            self.board.i2c_write(self._address, 0x40, charmap[i])

    def set_backlight(self, mode):
        """
          @brief set the backlight
          @param mode  true indicates the backlight is turned on and set to white, false indicates the backlight is turned off
        """
        if mode:
            self.set_color_white()  # turn backlight on
        else:
            self.close_backlight()  # turn backlight off

    def printstr(self, c):
        """
          @brief output string
        """
        # /< This function is not identical to the function used for "real" I2C displays
        # /< it's here so the user sketch doesn't have to be changed 
        self.print_out(c)

    def set_pwm(self, color, pwm):
        """
           @brief set backlight PWM output
           @param color  backlight color  Preferences：REG_RED\REG_GREEN\REG_BLUE
           @param pwm  color intensity   range(0-255)
        """
        self._set_reg(color, pwm)
        if self.RGB_ADDRESS == 0x6b:
            self._set_reg(0x07, 0xFF)

    def set_color_white(self):
        """
           @brief set the backlight to white
        """
        self.set_RGB(255, 255, 255)

    def close_backlight(self):
        """
          @brief close the backlight
        """
        self.set_RGB(0, 0, 0)

    def _begin(self, cols, lines, dotsize=LCD_5x8DOTS):
        """
          @brief the initialization function
          @param cols columns optional range 0-15
          @param lines rows optional range 0-1，0 is the first row, 1 is the second row
          @param dotsize  character size LCD_5x8DOTS\LCD_5x10DOTS
        """
        if lines > 1:
            self._show_function |= LCD_2LINE

        self._num_lines = lines
        self._curr_line = 0

        # for some 1 line displays you can select a 10 pixel high font
        if (dotsize != 0) and (lines == 1):
            self._show_function |= LCD_5x10DOTS

            # SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
        # according to datasheet, we need at least 40ms after power rises above 2.7V
        # before sending _commands. Arduino can turn on way before 4.5V, so we'll wait 50
        # delayMicroseconds(50000);
        time.sleep(0.05)

        # this is according to the hitachi HD44780 datasheet
        # page 45 figure 23

        # Send function set _command sequence
        self._command(LCD_FUNCTIONSET | self._show_function)
        # delayMicroseconds(4500);  # wait more than 4.1ms
        time.sleep(0.005)
        # second try
        self._command(LCD_FUNCTIONSET | self._show_function)
        # delayMicroseconds(150);
        time.sleep(0.005)
        # third go
        self._command(LCD_FUNCTIONSET | self._show_function)
        # finally, set # lines, font size, etc.
        self._command(LCD_FUNCTIONSET | self._show_function)
        # turn the display on with no cursor or blinking default
        self._show_control = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF
        self.display()
        # clear it off
        self.clear()
        # Initialize to default text direction (for romance languages)
        self._show_mode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT
        # set the entry mode
        self._command(LCD_ENTRYMODESET | self._show_mode)
        if self.RGB_ADDRESS == 0x60:
            # backlight init
            self._set_reg(REG_MODE1, 0)
            # set LEDs controllable by both PWM and GRPPWM registers
            self._set_reg(REG_OUTPUT, 0xFF)
            # set MODE2 values
            # 0010 0000 -> 0x20  (DMBLNK to 1, ie blinky mode)
            self._set_reg(REG_MODE2, 0x20)
        elif self.RGB_ADDRESS == (0x60 >> 1):
            self._set_reg(0x04, 0x15)
        elif self.RGB_ADDRESS == 0x6B:
            self._set_reg(0x2F, 0x00)
            self._set_reg(0x00, 0x20)
            self._set_reg(0x01, 0x00)
            self._set_reg(0x02, 0x01)
            self._set_reg(0x03, 0x04)
        self.set_color_white()

    def _command(self, cmd):
        """
          @brief send command
          @param data the sent data
        """
        b = bytearray(2)
        b[0] = 0x80
        b[1] = cmd
        # wiringpi.wiringPiI2CWriteReg8(self.LCD,0x80,cmd)
        self.board.i2c_write(self._address, [0x80, cmd])

    def _set_reg(self, reg, data):
        """
          @brief set the register
          @param addr register address
          @param data data
        """
        b = bytearray(1)
        b[0] = data
        # wiringpi.wiringPiI2CWriteReg8(self.RGB,reg,data)
        self.board.i2c_write(self._address, [reg, data])
