From bcfd8797b7d42364b8895a53fbc5434212d810e6 Mon Sep 17 00:00:00 2001 From: Ace Date: Mon, 25 Nov 2019 21:47:20 +0100 Subject: [PATCH] Add files via upload --- Inky-Calendar/modules/inkycal_drivers.py | 309 +++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 Inky-Calendar/modules/inkycal_drivers.py diff --git a/Inky-Calendar/modules/inkycal_drivers.py b/Inky-Calendar/modules/inkycal_drivers.py new file mode 100644 index 0000000..7f5aed8 --- /dev/null +++ b/Inky-Calendar/modules/inkycal_drivers.py @@ -0,0 +1,309 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +""" +Drivers file for Inky-Calendar software. +Handles E-Paper display related tasks +""" + +from PIL import Image +import RPi.GPIO as GPIO +from settings import display_type +import numpy +import spidev +import RPi.GPIO as GPIO +from time import sleep + +RST_PIN = 17 +DC_PIN = 25 +CS_PIN = 8 +BUSY_PIN = 24 + +EPD_WIDTH = 640 +EPD_HEIGHT = 384 + +SPI = spidev.SpiDev(0, 0) + +def epd_digital_write(pin, value): + GPIO.output(pin, value) + +def epd_digital_read(pin): + return GPIO.input(BUSY_PIN) + +def epd_delay_ms(delaytime): + sleep(delaytime / 1000.0) + +def spi_transfer(data): + SPI.writebytes(data) + +def epd_init(): + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(RST_PIN, GPIO.OUT) + GPIO.setup(DC_PIN, GPIO.OUT) + GPIO.setup(CS_PIN, GPIO.OUT) + GPIO.setup(BUSY_PIN, GPIO.IN) + SPI.max_speed_hz = 2000000 + SPI.mode = 0b00 + return 0; + +# EPD7IN5 commands +PANEL_SETTING = 0x00 +POWER_SETTING = 0x01 +POWER_OFF = 0x02 +POWER_OFF_SEQUENCE_SETTING = 0x03 +POWER_ON = 0x04 +POWER_ON_MEASURE = 0x05 +BOOSTER_SOFT_START = 0x06 +DEEP_SLEEP = 0x07 +DATA_START_TRANSMISSION_1 = 0x10 +DATA_STOP = 0x11 +DISPLAY_REFRESH = 0x12 +IMAGE_PROCESS = 0x13 +LUT_FOR_VCOM = 0x20 +LUT_BLUE = 0x21 +LUT_WHITE = 0x22 +LUT_GRAY_1 = 0x23 +LUT_GRAY_2 = 0x24 +LUT_RED_0 = 0x25 +LUT_RED_1 = 0x26 +LUT_RED_2 = 0x27 +LUT_RED_3 = 0x28 +LUT_XON = 0x29 +PLL_CONTROL = 0x30 +TEMPERATURE_SENSOR_COMMAND = 0x40 +TEMPERATURE_CALIBRATION = 0x41 +TEMPERATURE_SENSOR_WRITE = 0x42 +TEMPERATURE_SENSOR_READ = 0x43 +VCOM_AND_DATA_INTERVAL_SETTING = 0x50 +LOW_POWER_DETECTION = 0x51 +TCON_SETTING = 0x60 +TCON_RESOLUTION = 0x61 +SPI_FLASH_CONTROL = 0x65 +REVISION = 0x70 +GET_STATUS = 0x71 +AUTO_MEASUREMENT_VCOM = 0x80 +READ_VCOM_VALUE = 0x81 +VCM_DC_SETTING = 0x82 + +class EPD: + def __init__(self): + self.reset_pin = RST_PIN + self.dc_pin = DC_PIN + self.busy_pin = BUSY_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + def digital_write(self, pin, value): + epd_digital_write(pin, value) + + def digital_read(self, pin): + return epd_digital_read(pin) + + def delay_ms(self, delaytime): + epd_delay_ms(delaytime) + + def send_command(self, command): + self.digital_write(self.dc_pin, GPIO.LOW) + spi_transfer([command]) + + def send_data(self, data): + self.digital_write(self.dc_pin, GPIO.HIGH) + spi_transfer([data]) + + def init(self): + if (epd_init() != 0): + return -1 + self.reset() + self.send_command(POWER_SETTING) + self.send_data(0x37) + self.send_data(0x00) + self.send_command(PANEL_SETTING) + self.send_data(0xCF) + self.send_data(0x08) + self.send_command(BOOSTER_SOFT_START) + self.send_data(0xc7) + self.send_data(0xcc) + self.send_data(0x28) + self.send_command(POWER_ON) + self.wait_until_idle() + self.send_command(PLL_CONTROL) + self.send_data(0x3c) + self.send_command(TEMPERATURE_CALIBRATION) + self.send_data(0x00) + self.send_command(VCOM_AND_DATA_INTERVAL_SETTING) + self.send_data(0x77) + self.send_command(TCON_SETTING) + self.send_data(0x22) + self.send_command(TCON_RESOLUTION) + self.send_data(0x02) #source 640 + self.send_data(0x80) + self.send_data(0x01) #gate 384 + self.send_data(0x80) + self.send_command(VCM_DC_SETTING) + self.send_data(0x1E) #decide by LUT file + self.send_command(0xe5) #FLASH MODE + self.send_data(0x03) + + def wait_until_idle(self): + while(self.digital_read(self.busy_pin) == 0): # 0: busy, 1: idle + self.delay_ms(100) + + def reset(self): + self.digital_write(self.reset_pin, GPIO.LOW) # module reset + self.delay_ms(200) + self.digital_write(self.reset_pin, GPIO.HIGH) + self.delay_ms(200) + + def calibrate_display(no_of_cycles): + """Function for Calibration""" + black = Image.new('1', (EPD_WIDTH, EPD_HEIGHT), 'black') + white = Image.new('1', (EPD_WIDTH, EPD_HEIGHT), 'white') + red = Image.new('RGB', (EPD_WIDTH, EPD_HEIGHT), 'red') + print('----------Started calibration of E-Paper display----------') + for _ in range(no_of_cycles): + print('Calibrating black...') + self.show_image(black) + if display_type == "colour": + print('calibrating red...') + self.show_image(red) + print('Calibrating white...') + self.show_image(white) + + print('Cycle {0} of {1} complete'.format(_+1, no_of_cycles)) + print('-----------Calibration complete----------') + + def reduce_colours(self, image): + buffer = numpy.array(image) + r,g,b = buffer[:,:,0], buffer[:,:,1], buffer[:,:,2] + + if display_type == "colour": + buffer[numpy.logical_and(r > 245, g > 245)] = [255,255,255] #white + buffer[numpy.logical_and(r > 245, g < 245)] = [255,0,0] #red + buffer[numpy.logical_and(r != 255, r == g )] = [0,0,0] #black + + if display_type == "black_and_white": + buffer[numpy.logical_and(r > 245, g > 245)] = [255,255,255] #white + buffer[g < 255] = [0,0,0] #black + + image = Image.fromarray(buffer) + return image + + def get_frame_buffer(self, image): + imwidth, imheight = image.size + if imwidth == self.height and imheight == self.width: + image = image.rotate(270, expand = True) + print('Rotated image by 270 degrees...', end= '') + elif imwidth != self.width or imheight != self.height: + raise ValueError('Image must be same dimensions as display \ + ({0}x{1}).' .format(self.width, self.height)) + else: + print('Image size OK') + imwidth, imheight = image.size + + if display_type == 'colour': + buf = [0x00] * int(self.width * self.height / 4) + image_grayscale = image.convert('L', dither=None) + pixels = image_grayscale.load() + + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: # black + buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) + elif pixels[x, y] == 76: # convert gray to red + buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) + buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2) + else: # white + buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2) + + if display_type == 'black_and_white': + buf = [0x00] * int(self.width * self.height / 8) + image_monocolor = image.convert('1') + + pixels = image_monocolor.load() + for y in range(self.height): + for x in range(self.width): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] != 0: + buf[int((x + y * self.width) / 8)] |= 0x80 >> (x % 8) + + return buf + + def display_frame(self, frame_buffer): + self.send_command(DATA_START_TRANSMISSION_1) + if display_type == 'colour': + for i in range(0, int(self.width / 4 * self.height)): + temp1 = frame_buffer[i] + j = 0 + while (j < 4): + if ((temp1 & 0xC0) == 0xC0): + temp2 = 0x03 + elif ((temp1 & 0xC0) == 0x00): + temp2 = 0x00 + else: + temp2 = 0x04 + temp2 = (temp2 << 4) & 0xFF + temp1 = (temp1 << 2) & 0xFF + j += 1 + if((temp1 & 0xC0) == 0xC0): + temp2 |= 0x03 + elif ((temp1 & 0xC0) == 0x00): + temp2 |= 0x00 + else: + temp2 |= 0x04 + temp1 = (temp1 << 2) & 0xFF + self.send_data(temp2) + j += 1 + + if display_type == 'black_and_white': + for i in range(0, 30720): + temp1 = frame_buffer[i] + j = 0 + while (j < 8): + if(temp1 & 0x80): + temp2 = 0x03 + else: + temp2 = 0x00 + temp2 = (temp2 << 4) & 0xFF + temp1 = (temp1 << 1) & 0xFF + j += 1 + if(temp1 & 0x80): + temp2 |= 0x03 + else: + temp2 |= 0x00 + temp1 = (temp1 << 1) & 0xFF + self.send_data(temp2) + j += 1 + + self.send_command(DISPLAY_REFRESH) + self.delay_ms(100) + self.wait_until_idle() + + def show_image(self, image, reduce_colours = True): + print('Initialising E-Paper Display...', end='') + self.init() + sleep(5) + print('Done') + + if reduce_colours == True: + print('Optimising Image for E-Paper displays...', end = '') + image = self.reduce_colours(image) + print('Done') + else: + print('No colour optimisation done on image') + + print('Creating image buffer and sending it to E-Paper display...', end='') + data = self.get_frame_buffer(image) + print('Done') + print('Refreshing display...', end = '') + self.display_frame(data) + print('Done') + print('Sending E-Paper to deep sleep mode...',end='') + self.sleep() + print('Done') + + def sleep(self): + self.send_command(POWER_OFF) + self.wait_until_idle() + self.send_command(DEEP_SLEEP) + self.send_data(0xa5)