#-----------------------------------------------------------------------------
# qwiic_alphanumeric.py
#
# Python library for the SparkFun Qwiic Alphanumeric displays.
# https://www.sparkfun.com/products/16916
# https://www.sparkfun.com/products/16917
# https://www.sparkfun.com/products/16918
# https://www.sparkfun.com/products/16919
# https://www.sparkfun.com/products/18565
# https://www.sparkfun.com/products/18566
#
#------------------------------------------------------------------------
#
# Written by Priyanka Makin @ SparkFun Electronics, August 2021
#
# This python library supports the SparkFun Electroncis qwiic
# qwiic sensor/board ecosystem
#
# More information on qwiic is at https:// www.sparkfun.com/qwiic
#
# Do you like this library? Help support SparkFun. Buy a board!
#==================================================================================
# Copyright (c) 2020 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#==================================================================================
"""
qwiic_alphanumeric
==================
Python module for the SparkFun Qwiic Alphanumeric displays.
This package is a port of the existing [SparkFun Alphanumeric Display Arduino Library](https://github.com/sparkfun/SparkFun_Alphanumeric_Display_Arduino_Library).
This package can be used in conjunction with the overall [SparkFun Qwiic Python Package](https://github.com/sparkfun/Qwiic_Py).
New to qwiic? Take a look at the entire [SparkFun Qwiic Ecosystem](https://www.sparkfun.com/qwiic).
"""
# ---------------------------------------------------------------------------------
import time
import qwiic_i2c
_DEFAULT_NAME = "Qwiic Alphanumeric"
_QWIIC_ALPHANUMERIC_DEFAULT_ADDRESS = 0x70
_AVAILABLE_I2C_ADDRESS = [_QWIIC_ALPHANUMERIC_DEFAULT_ADDRESS, 0x71, 0x72, 0x73]
[docs]class QwiicAlphanumeric(object):
"""
QwiicAlphanumeric
:param address: The I2C address to use for the device.
If not provided, the default address is used.
:param i2c_driver: An existing i2c driver object. If not provided a
a driver is created.
:return: The QwiicAlphanumeric device object.
:rtype: Object
"""
# Constructor
device_name = _DEFAULT_NAME
available_addresses = _AVAILABLE_I2C_ADDRESS
DEFAULT_NOTHING_ATTACHED = 0xFF
# Define constants for segment bits
SEG_A = 0x0001
SEG_B = 0x0002
SEG_C = 0x0004
SEG_D = 0x0008
SEG_E = 0x0010
SEG_F = 0x0020
SEG_G = 0x0040
SEG_H = 0x0080
SEG_I = 0x0100
SEG_J = 0x0200
SEG_K = 0x0400
SEG_L = 0x0800
SEG_M = 0x1000
SEG_N = 0x2000
# Blink rate
ALPHA_BLINK_RATE_NOBLINK = 0b00
ALPHA_BLINK_RATE_2HZ = 0b01
ALPHA_BLINK_RATE_1HZ = 0b10
ALPHA_BLINK_RATE_0_5HZ = 0b11
# Display settings
ALPHA_DISPLAY_ON = 0b1
ALPHA_DISPLAY_OFF = 0b0
# Decimal settings
ALPHA_DECIMAL_ON = 0b1
ALPHA_DECIMAL_OFF = 0b0
# Colon settings
ALPHA_COLON_ON = 0b1
ALPHA_COLON_OFF = 0b0
# Commands
ALPHA_CMD_SYSTEM_SETUP = 0b00100000
ALPHA_CMD_DISPLAY_SETUP = 0b10000000
ALPHA_CMD_DIMMING_SETUP = 0b11100000
SFE_ALPHANUM_UNKNOWN_CHAR = 95
# Lookup table of segments for various characters
alphanumeric_segs = []
# nmlkjihgfedcba
alphanumeric_segs.append(0b00000000000000) # ' ' (space)
alphanumeric_segs.append(0b00001000001000) # '!'
alphanumeric_segs.append(0b00001000000010) # '"'
alphanumeric_segs.append(0b01001101001110) # '#'
alphanumeric_segs.append(0b01001101101101) # '$'
alphanumeric_segs.append(0b10010000100100) # '%'
alphanumeric_segs.append(0b00110011011001) # '&'
alphanumeric_segs.append(0b00001000000000) # '''
alphanumeric_segs.append(0b00000000111001) # '('
alphanumeric_segs.append(0b00000000001111) # ')'
alphanumeric_segs.append(0b11111010000000) # '*'
alphanumeric_segs.append(0b01001101000000) # '+'
alphanumeric_segs.append(0b10000000000000) # ','
alphanumeric_segs.append(0b00000101000000) # '-'
alphanumeric_segs.append(0b00000000000000) # '.'
alphanumeric_segs.append(0b10010000000000) # '/'
alphanumeric_segs.append(0b00000000111111) # '0'
alphanumeric_segs.append(0b00010000000110) # '1'
alphanumeric_segs.append(0b00000101011011) # '2'
alphanumeric_segs.append(0b00000101001111) # '3'
alphanumeric_segs.append(0b00000101100110) # '4'
alphanumeric_segs.append(0b00000101101101) # '5'
alphanumeric_segs.append(0b00000101111101) # '6'
alphanumeric_segs.append(0b01010000000001) # '7'
alphanumeric_segs.append(0b00000101111111) # '8'
alphanumeric_segs.append(0b00000101100111) # '9'
alphanumeric_segs.append(0b00000000000000) # ':'
alphanumeric_segs.append(0b10001000000000) # ';'
alphanumeric_segs.append(0b00110000000000) # '<'
alphanumeric_segs.append(0b00000101001000) # '='
alphanumeric_segs.append(0b01000010000000) # '>'
alphanumeric_segs.append(0b01000100000011) # '?'
alphanumeric_segs.append(0b00001100111011) # '@'
alphanumeric_segs.append(0b00000101110111) # 'A'
alphanumeric_segs.append(0b01001100001111) # 'B'
alphanumeric_segs.append(0b00000000111001) # 'C'
alphanumeric_segs.append(0b01001000001111) # 'D'
alphanumeric_segs.append(0b00000101111001) # 'E'
alphanumeric_segs.append(0b00000101110001) # 'F'
alphanumeric_segs.append(0b00000100111101) # 'G'
alphanumeric_segs.append(0b00000101110110) # 'H'
alphanumeric_segs.append(0b01001000001001) # 'I'
alphanumeric_segs.append(0b00000000011110) # 'J'
alphanumeric_segs.append(0b00110001110000) # 'K'
alphanumeric_segs.append(0b00000000111000) # 'L'
alphanumeric_segs.append(0b00010010110110) # 'M'
alphanumeric_segs.append(0b00100010110110) # 'N'
alphanumeric_segs.append(0b00000000111111) # 'O'
alphanumeric_segs.append(0b00000101110011) # 'P'
alphanumeric_segs.append(0b00100000111111) # 'Q'
alphanumeric_segs.append(0b00100101110011) # 'R'
alphanumeric_segs.append(0b00000110001101) # 'S'
alphanumeric_segs.append(0b01001000000001) # 'T'
alphanumeric_segs.append(0b00000000111110) # 'U'
alphanumeric_segs.append(0b10010000110000) # 'V'
alphanumeric_segs.append(0b10100000110110) # 'W'
alphanumeric_segs.append(0b10110010000000) # 'X'
alphanumeric_segs.append(0b01010010000000) # 'Y'
alphanumeric_segs.append(0b10010000001001) # 'Z'
alphanumeric_segs.append(0b00000000111001) # '['
alphanumeric_segs.append(0b00100010000000) # '\'
alphanumeric_segs.append(0b00000000001111) # ']'
alphanumeric_segs.append(0b10100000000000) # '^'
alphanumeric_segs.append(0b00000000001000) # '_'
alphanumeric_segs.append(0b00000010000000) # '`'
alphanumeric_segs.append(0b00000101011111) # 'a'
alphanumeric_segs.append(0b00100001111000) # 'b'
alphanumeric_segs.append(0b00000101011000) # 'c'
alphanumeric_segs.append(0b10000100001110) # 'd'
alphanumeric_segs.append(0b00000001111001) # 'e'
alphanumeric_segs.append(0b00000001110001) # 'f'
alphanumeric_segs.append(0b00000110001111) # 'g'
alphanumeric_segs.append(0b00000101110100) # 'h'
alphanumeric_segs.append(0b01000000000000) # 'i'
alphanumeric_segs.append(0b00000000001110) # 'j'
alphanumeric_segs.append(0b01111000000000) # 'k'
alphanumeric_segs.append(0b01001000000000) # 'l'
alphanumeric_segs.append(0b01000101010100) # 'm'
alphanumeric_segs.append(0b00100001010000) # 'n'
alphanumeric_segs.append(0b00000101011100) # 'o'
alphanumeric_segs.append(0b00010001110001) # 'p'
alphanumeric_segs.append(0b00100101100011) # 'q'
alphanumeric_segs.append(0b00000001010000) # 'r'
alphanumeric_segs.append(0b00000110001101) # 's'
alphanumeric_segs.append(0b00000001111000) # 't'
alphanumeric_segs.append(0b00000000011100) # 'u'
alphanumeric_segs.append(0b10000000010000) # 'v'
alphanumeric_segs.append(0b10100000010100) # 'w'
alphanumeric_segs.append(0b10110010000000) # 'x'
alphanumeric_segs.append(0b00001100001110) # 'y'
alphanumeric_segs.append(0b10010000001001) # 'z'
alphanumeric_segs.append(0b10000011001001) # '{'
alphanumeric_segs.append(0b01001000000000) # '|'
alphanumeric_segs.append(0b00110100001001) # '}'
alphanumeric_segs.append(0b00000101010010) # '~'
alphanumeric_segs.append(0b11111111111111) # Unknown character (DEL or RUBOUT)
# Globals
_device_address_display_one = 0 # Address of primary alphanumeric display
_device_address_display_two = 0
_device_address_display_three = 0
_device_address_display_four = 0
digit_position = 0 # Tracks the position of the current digit
number_of_displays = 1 # Tracks the number of displays connected to the I2C bus, default is one display
display_on_off = 0 # Tracks the on/off state of the display
decimal_on_off = 0 # Tracks the on/off state of the decimal segment
colon_on_off = 0 # Tracks the on/off state of the colon segment
blink_rate = ALPHA_BLINK_RATE_NOBLINK # Tracks the current blinking status
display_RAM = [' '] * 16 * 4
display_content = [' '] * (4 * 4 + 1)
def __init__(self, address=None, i2c_driver=None):
# Did the user specify an I2C address?
self.address = address if address != None else self.available_addresses[0]
# Load the I2C driver if one isn't provided
if i2c_driver == None:
self._i2c = qwiic_i2c.getI2CDriver()
if self._i2c == None:
print("Unable to load I2C driver for this platform.")
return
else:
self._i2c = i2c_driver
# ---------------------------------------------------------------------------------
# begin(address_left, address_left_center, address_right_center, address_right)
#
# Initialize the system and validate the baord.
[docs] def begin(self, address_display_one = _QWIIC_ALPHANUMERIC_DEFAULT_ADDRESS, address_display_two = DEFAULT_NOTHING_ATTACHED, address_display_three = DEFAULT_NOTHING_ATTACHED, address_display_four = DEFAULT_NOTHING_ATTACHED):
"""
Initialize the operation of the Qwiic Alphanumeric.
Assign addresses to displays and determine the number of displays connected to the bus.
Run is_connected().
Initialize and clear displays.
:param address_display_one: I2C address of first display
:param address_display_two: I2C address of the second display
:param address_dispplay_three: I2C address of the third display
:param address_display_four: I2C address of the fourth display
:return: Returns true if a Qwiic Alphanumeric is connected to the system.
False otherwise.
:rtype: bool
"""
self._device_address_display_one = address_display_one # Grab the address(es) of the alphanumeric(s)
self._device_address_display_two = address_display_two
self._device_address_display_three = address_display_three
self._device_address_display_four = address_display_four
# Figure out how many displays are attached by the number of addresses the user specified
if self._device_address_display_four != self.DEFAULT_NOTHING_ATTACHED:
self.number_of_displays = 4
elif self._device_address_display_three != self.DEFAULT_NOTHING_ATTACHED:
self.number_of_displays = 3
elif self._device_address_display_two != self.DEFAULT_NOTHING_ATTACHED:
self.number_of_displays = 2
else:
self.number_of_displays = 1
for i in range(1, self.number_of_displays + 1):
if self.is_connected(i) == False:
return False
time.sleep(0.01)
if self.initialize() == False:
return False
if self.clear() == False:
return False
self.display_content[4 * 4] = '\0' # Terminate the array because we are doing direct prints
# ---------------------------------------------------------------------------------
# is_connected(display_number)
#
# Check if there are acutal boards connected to the system
[docs] def is_connected(self, display_number):
"""
Check that dispplays are responding on the I2C bus.
:param display_number: The number of the display on the bus
:return: True if the device is connected, false otherwise.
:rtype: bool
"""
tries_before_giveup = 5
# The LED driver IC sometimes fails to respond. This attempts multiple times before giving up.
for x in range(0, tries_before_giveup):
if qwiic_i2c.isDeviceConnected(self.look_up_display_address(display_number)) == True:
return True
time.sleep(0.01)
return False
# ---------------------------------------------------------------------------------
# initialize()
#
# Run through initialization sequence for each display connected on the I2C bus
[docs] def initialize(self):
"""
Run through initialization sequence for each display connected on the I2C bus
Enable clocks, set brightness default to full brightness, turn off blinking, and
turn all displays on
:return: True if all function calls passed, False if there's a failure somewhere
:rtype: bool
"""
# Turn on system clock of all displays
if self.enable_system_clock() == False:
return False
# Set brightness of all displays to full brightness
if self.set_brightness(15) == False:
return False
# Turn blinking off for all displays
if self.set_blink_rate(self.ALPHA_BLINK_RATE_NOBLINK) == False:
return False
# Turn on all displays
if self.display_on() == False:
return False
return True
# ---------------------------------------------------------------------------------
# enable_system_clock()
#
# Turn on the system oscillator for all displays on the I2C bus
[docs] def enable_system_clock(self):
"""
Turn on the system oscillator for all displays on the I2C bus
:return: True if all clocks successfully enabled, false otherwise.
:rtype: bool
"""
status = True
for i in range(1, self.number_of_displays + 1):
if self.enable_system_clock_single(i) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# disable_system_clock()
#
# Turn off the system oscillator for all displays on the bus
[docs] def disable_system_clock(self):
"""
Turn off the system oscillator for all displays on the bus
:return: True if all clocks successfully disabled, false otherwise.
:rtype: bool
"""
status = True
for i in range(1, self.number_of_displays + 1):
if self.disable_system_clock_single(i) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# enable_system_clock_single(display_number)
#
# Turn on the system oscillator for normal operation mode
[docs] def enable_system_clock_single(self, display_number):
"""
Turn on the system oscillator for normal operation mode
:param display_number: number of display on I2C bus to enable the system clock
for.
:return: True if setting updated successfully, false otherwise.
:rtype: bool
"""
data_to_write = self.ALPHA_CMD_SYSTEM_SETUP | 1 # Enable system clock bit
status = self.write_RAM_byte(self.look_up_display_address(display_number), data_to_write)
time.sleep(0.001) # Allow display to start
return status
# ---------------------------------------------------------------------------------
# disable_system_clock_single(display_number)
#
# Turn off the system oscillator for standby mode
[docs] def disable_system_clock_single(self, display_number):
"""
Turn off the system oscillator for standby mode
:param display_number: number of display on I2C bus to disable the system
clock for.
:return: True if setting updated successfully, false otherwise.
:rtype: bool
"""
data_to_write = self.ALPHA_CMD_SYSTEM_SETUP | 0 # Standby mode
return self.write_RAM(self.look_up_display_address(display_number), data_to_write)
# ---------------------------------------------------------------------------------
# look_up_display_address(display_number)
#
# This function connects the display number to its coressponding address
[docs] def look_up_display_address(self, display_number):
"""
This function connects the display number to its coressponding address
:param display_number: number of display on I2C bus. The left-most display is zero
and display number increments by 1 with each additional display on bus.
:return: The I2C address of given display. 0 if display_number is not valid
:rtype: int
"""
if display_number == 1:
return self._device_address_display_one
elif display_number == 2:
return self._device_address_display_two
elif display_number == 3:
return self._device_address_display_three
elif display_number == 4:
return self._device_address_display_four
return 0 # We shouldn't get here
# ---------------------------------------------------------------------------------
# clear()
#
# Turn off all segments of all displays connected to bus
[docs] def clear(self):
"""
Turn off all segments of all displays connected to bus
:return: True if display was updated correctly, false otherwise
:rtype: bool
"""
# Clear the display_RAM array
for i in range(0, 16 * self.number_of_displays):
self.display_RAM[i] = 0
# Reset digit position
self.digit_position = 0
return self.update_display()
# ---------------------------------------------------------------------------------
# set_brightness(duty)
#
# This function sets the brightness of all displays on the bus
[docs] def set_brightness(self, duty):
"""
This function sets the brightness of all displays on the bus.
Duty cycle over 16.
:param duty: Valid between 0 (display off) and 15 (full brightness)
:return: True if brightness is successfully updated, false otherwise.
:rtype: bool
"""
status = True
for i in range(1, self.number_of_displays + 1):
if self.set_brightness_single(i, duty) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# set_brightness_single(display_number, duty)
#
# Set the brightness of a single display
[docs] def set_brightness_single(self, display_number, duty):
"""
Set the brightness of a single display
:param display_number: The number of display on the I2C bus.
:param duty: Over 16. Valid between 0 (display off) and 15 (full brightness)
:return: True if brightness is successfully updated, false otherwise.
:rtype: bool
"""
# Error check
if duty > 15:
duty = 15
elif duty < 0:
duty = 0
data_to_write = self.ALPHA_CMD_DIMMING_SETUP | duty
return self.write_RAM_byte(self.look_up_display_address(display_number), data_to_write)
# ---------------------------------------------------------------------------------
# set_blink_rate(rate)
#
# Set the blink rate of all displays on the bus
[docs] def set_blink_rate(self, rate):
"""
Set the blink rate of all displays on the bus as defined by the datasheet.
:param rate: Blink frequency in Hz. Valid options are defined by datasheet:
2.0, 1.0, or 0.5 Hz. Any other input to this function will result in steady
alphanumeric display (no blink).
:return: True if blink setting is successfully updated, false otherwise.
:rtype: bool
"""
status = True
for i in range(1, self.number_of_displays + 1):
if self.set_blink_rate_single(i, rate) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# set_blink_rate_single(display_number, rate)
#
# Set the blink rate of a single display on the bus
[docs] def set_blink_rate_single(self, display_number, rate):
"""
Set the blink rate of a single display on the bus
:param display_number: the number of display to be updated
:param rate: Blink frequency in Hz. Valid options are defined by datasheet:
2.0, 1.0, or 0.5 Hz. Any other input to this function will result in steady
alphanumeric display (no blink).
:return: True if blink setting is successfully updated, false otherwise.
:rtype: bool
"""
if rate == 2.0:
blink_rate = self.ALPHA_BLINK_RATE_2HZ
elif rate == 1.0:
blink_rate = self.ALPHA_BLINK_RATE_1HZ
elif rate == 0.5:
blink_rate = self.ALPHA_BLINK_RATE_0_5HZ
# Default to no blink
else:
blink_rate = self.ALPHA_BLINK_RATE_NOBLINK
data_to_write = self.ALPHA_CMD_DISPLAY_SETUP | (blink_rate << 1) | self.display_on_off
return self.write_RAM_byte(self.look_up_display_address(display_number), data_to_write)
# ---------------------------------------------------------------------------------
# display_on_single(display_number)
#
# Turn a single alphanumeric display on
[docs] def display_on_single(self, display_number):
"""
Turn a single alphanumeric display on
:param display_number: the number of display to be updated
:return: True if display is successfully turned on, false otherwise
:rtype: bool
"""
return self.set_display_on_off(display_number, True)
# ---------------------------------------------------------------------------------
# display_off_single(display_number)
#
# Turn a single alphanumeric display off
[docs] def display_off_single(self, display_number):
"""
Turn a single alphanumeric display off
:param display_number: the number of display to be updated
:return: True if display is successfully turned off, false otherwise
:rtype: bool
"""
return self.set_display_on_off(display_number, False)
# ---------------------------------------------------------------------------------
# set_display_on_off(display_number, turn_on_display)
#
# Set or clear the display on/off bit of a given display number
[docs] def set_display_on_off(self, display_number, turn_on_display):
"""
Set or clear the display on/off bit of a given display number
:param display_number: the number of display to be updated
:param turn_on_display: boolean variable. If true, will turn display on.
If false, will turn display off
:return: True if display is successfully updated, false otherwise.
:rtype: bool
"""
if turn_on_display:
self.display_on_off = self.ALPHA_DISPLAY_ON
else:
self.display_on_off = self.ALPHA_DISPLAY_OFF
data_to_write = self.ALPHA_CMD_DISPLAY_SETUP | (self.blink_rate << 1) | self.display_on_off
return self.write_RAM_byte(self.look_up_display_address(display_number), data_to_write)
# ---------------------------------------------------------------------------------
# display_on()
#
# Turn on all displays on the I2C bus
[docs] def display_on(self):
"""
Turn on all displays on the I2C bus
:return: True if displays are successfully turned on, false otherwise.
:rtype: bool
"""
status = True
self.display_on_off = self.ALPHA_DISPLAY_ON
for i in range(1, self.number_of_displays + 1):
if self.display_on_single(i) == False:
status = false
return status
# ---------------------------------------------------------------------------------
# display_off()
#
# Turn off all displays on the I2C bus
[docs] def display_off(self):
"""
Turn off all displays on the I2C bus
:return: True if all displays are successfully turned off, false otherwise.
:rtype: bool
"""
status = True
self.display_on_off = self.ALPHA_DISPLAY_OFF
for i in range(1, self.number_of_displays + 1):
if self.display_off_single(i) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# decimal_on_single(display_number)
#
# Turn the decimal point on for a single display
[docs] def decimal_on_single(self, display_number):
"""
Turn the decimal point on for a single display
:param display_number: the number of display to turn the decimal on for.
:return: true if decimal is successfully turned on, false otherwise.
:rtype: bool
"""
return self.set_decimal_on_off(display_number, True)
# ---------------------------------------------------------------------------------
# decimal_off_single(display_number)
#
# Turn the decimal point off for a single display
[docs] def decimal_off_single(self, display_number):
"""
Turn the decimal point off for a single display
:param display_number: the number of display to turn the decimal point off for.
:return: true if decimal is successfully turned off, false otherwise.
:rtype: bool
"""
return self.set_decimal_on_off(display_number, False)
# ---------------------------------------------------------------------------------
# set_decimal_on_off(display_number, turn_on_decimal)
#
# Set or clear the decimal on/off bit
[docs] def set_decimal_on_off(self, display_number, turn_on_decimal):
"""
Set or clear the decimal on/off bit
:param display_number: the number of display to update.
:param turn_on_decimal: boolean variable. If true, will turn decimal on.
If false, will turn decimal off.
:return: true if the display is updated successfully, false otherwise.
:rtype: bool
"""
adr = 0x03
dat = 0
if turn_on_decimal == True:
self.decimal_on_off = self.ALPHA_DECIMAL_ON
dat = 0x01
else:
self.decimal_on_off = self.ALPHA_DECIMAL_OFF
dat = 0x00
self.display_RAM[adr + (display_number - 1) * 16] = self.display_RAM[adr + (display_number - 1) * 16] | dat
return self.update_display()
# ---------------------------------------------------------------------------------
# decimal_on()
#
# Turn the decimal on for all displays on bus
[docs] def decimal_on(self):
"""
Turn the decimal on for all displays on the bus
:return: true if displays are updated successfully, false otherwise.
:rtype: bool
"""
status = True
self.decimal_on_off = self.ALPHA_DECIMAL_ON
for i in range(1, self.number_of_displays + 1):
if self.decimal_on_single(i) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# decimal_off()
#
# Turn the decimal point off for all displays on bus
[docs] def decimal_off(self):
"""
Turn the decimal point off for all displays on the bus
:return: true if displays are updated successfully, false otherwise.
:rtype: bool
"""
status = True
self.decimal_on_off = self.ALPHA_DECIMAL_OFF
for i in range(1, self.number_of_displays + 1):
if self.decimal_off_single(i) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# colon_on_single(display_number)
#
# Turn the colon on for a single display
[docs] def colon_on_single(self, display_number):
"""
Turn the colon on for a single display
:param display_number: number of display to update.
:return: true if display updated successfully, false otherwise.
:rtype: bool
"""
return self.set_colon_on_off(display_number, True)
# ---------------------------------------------------------------------------------
# colon_off_single(display_number)
#
# Turn the colon off for a single display
[docs] def colon_off_single(self, display_number):
"""
Turn the colon off for a single display
:param display_number: number of display to update.
:return: true if display updated successfully, false otherwise.
:rtype: bool
"""
return self.set_colon_on_off(display_number, False)
# ---------------------------------------------------------------------------------
# set_colon_on_off(display_number, turn_on_colon)
#
# Set or clear the colon on/off bit
[docs] def set_colon_on_off(self, display_number, turn_on_colon):
"""
Set or clear the colon on/off bit
:param display_number: number of display to update.
:param turn_on_colon: boolean variable. If true, colon will turn on.
If false, colon will turn off.
:return true if display updated successfully, false otherwise.
:rtype: bool
"""
adr = 0x01
dat = 0
if turn_on_colon == True:
self.colon_on_off = self.ALPHA_COLON_ON
dat = 0x01
else:
self.colon_on_off = self.ALPHA_COLON_OFF
dat = 0x00
self.display_RAM[adr + (display_number - 1) * 16] = self.display_RAM[adr + (display_number - 1) * 16] | dat
return self.update_display()
# ---------------------------------------------------------------------------------
# colon_on()
#
# Turn the colon on for all displays on the bus
[docs] def colon_on(self):
"""
Turn the colon on for all displays on the bus
:return: true if displays successfully updated, false otherwise.
:rtype: bool
"""
status = True
self.colon_on_off = self.ALPHA_COLON_ON
for i in range(1, self.number_of_displays + 1):
if self.colon_on_single(i) == False:
return False
return status
# ---------------------------------------------------------------------------------
# colon_off()
#
# Turn the colon off for all displays on the bus
[docs] def colon_off(self):
"""
Turn the colon off for all displays on the bus
:return: true if all displays are successfully updated, false otherwise.
:rtype: bool
"""
status = True
self.colon_on_off = self.ALPHA_COLON_OFF
for i in range(1, self.number_of_displays + 1):
if self.colon_off_single(i) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# illuminate_segment(segment, digit)
#
# Given a segment and a digit, set the matching bit within the RAM of the Holtek RAM set
[docs] def illuminate_segment(self, segment, digit):
"""
Given a segment and a digit, set the matching bit within the RAM of the Holtek RAM set
:param segment: the segment to illuminate. There are 14 segments available, so A-N
:param digit: the digit on the display to turn the segment on. There are 4 digits
per display
:return: nothing
:rtype: Void
"""
segment = ord(segment)
com = segment - ord('A') # Convert the segment letter back to a number
if com > 6:
com = com - 7
# Special cases in which the segment order is a lil switched.
if segment == ord('I'):
com = 0
if segment == ord('H'):
com = 1
row = digit % 4 # Convert digit (1 to 16) back to a relative position on a given
# digit on a display
if segment > ord('G'):
row = row + 4
offset = int(digit / 4) * 16
adr = com * 2 + offset
# Determine the address
if row > 7:
adr = adr + 1
# Determine the data bit
if row > 7:
row = row - 8
dat = 1 << row
self.display_RAM[adr] = self.display_RAM[adr] | dat
# ---------------------------------------------------------------------------------
# illuminate_char(segments_to_turn_on, digit)
#
# Given a binary set of segments and a digit, store this data into the RAM array
[docs] def illuminate_char(self, segments_to_turn_on, digit):
"""
Fiven a binary set of segments and a digit, store this data into the RAM array
:param segments_to_turn_on: list of segments to illuminate which create an
alphanumeric character
:param digit: digit on which to illuminate this char (list of segments)
:return: nothing
:rtype: Void
"""
for i in range(0, 14):
if (segments_to_turn_on >> i) & 0b1:
temp_char = ord('A') + i
temp_char = chr(temp_char)
self.illuminate_segment(temp_char, digit) # Convert the segment number to a letter
# ---------------------------------------------------------------------------------
# print_char(display_char, digit)
#
# Print a character, for a given digit, on display
[docs] def print_char(self, display_char, digit):
"""
Print a character, for a given digit, on display
:param display_char: the character to be printed to display
:param digit: the digit position where character should be printed
:return: nothing
:rtype: Void
"""
# Convert character to ASCII representation
display_char = ord(display_char)
character_position = 65532
# Space
if display_char == ord(' '):
character_position = 0
# Printable symbols -- between first character '!' and last character '~'
elif display_char >= ord('!') and display_char <= ord('~'):
character_position = display_char - ord('!') + 1
disp_num = int(self.digit_position / 4)
# Take care of special characters by turning correct segment on
if character_position == 14: # '.'
self.decimal_on_single(disp_num+1)
if character_position == 26: # ':'
self.colon_on_single(disp_num+1)
if character_position == 65532: # unknown character
character_position = self.SFE_ALPHANUM_UNKNOWN_CHAR
self.illuminate_char(self.alphanumeric_segs[character_position], digit)
# ---------------------------------------------------------------------------------
# print(print_string)
#
# Print a whole string to the alphanumeric display(s)
[docs] def print(self, print_string):
"""
Print a whole string to the alphanumeric display(s)
:param print_string: string to be printed
:return: true if update_display() is successful, false otherwise
:rtype: bool
"""
# Clear the display_RAM array
self.clear()
self.digit_position = 0
for i in range(0, len(print_string)):
# For special characters like '.' or ':', do not increment the digit position
if print_string[i] == '.':
self.print_char('.', 0)
elif print_string[i] == ':':
self.print_char(':', 0)
else:
self.print_char(print_string[i], self.digit_position)
# Record to internal list
self.display_content[i] = print_string[i]
self.digit_position = self.digit_position + 1
self.digit_position = self.digit_position % (self.number_of_displays * 4)
self.update_display()
# ---------------------------------------------------------------------------------
# update_display()
#
# Push the contents of display_RAM out to the various displays in 16 byte chunks
[docs] def update_display(self):
"""
Push the contents of display_RAM out on to the various displays in 16 byte chunks
:return: true if displays are updated successfully, false otherwise.
:rtype: bool
"""
status = True
for i in range(1, self.number_of_displays + 1):
if self.write_RAM(self.look_up_display_address(i), 0, self.display_RAM[(i-1)*16:(i*16)-1]) == False:
status = False
return status
# ---------------------------------------------------------------------------------
# shift_right(shift_amt)
#
# Shift the display content to the right a number of digits
[docs] def shift_right(self, shift_amt = 1):
"""
Shift the display content to the right a number of digits
:param shift_amt: the number of digits to shift the string
:return: true if display updates successfully, false otherwise.
:rtype: bool
"""
for x in range((4 * self.number_of_displays) - shift_amt, shift_amt-1, -1):
self.display_content[x] = self.display_content[x - shift_amt]
# Clear the leading characters
for x in range(0, shift_amt):
if x + shift_amt > (4 * self.number_of_displays):
break # Error check
self.display_content[0 + x] = ' '
# Convert list of characters into string
temp = ""
for x in range(0, len(self.display_content)):
if self.display_content[x] != '\x00':
temp += self.display_content[x]
self.print(temp)
# ---------------------------------------------------------------------------------
# shift_left(shift_amt)
#
# Shift the display content to the left a number of digits
[docs] def shift_left(self, shift_amt = 1):
"""
Shift the display content to the left a number of digits
:param shift_amt: the number of digits to shift the string
:return: true if display updates successfully, false otherwise.
:rtype: bool
"""
for x in range(0, 4 * self.number_of_displays):
if (x + shift_amt) > (4 * self.number_of_displays):
break # Error check
self.display_content[x] = self.display_content[x + shift_amt]
# Clear the trailing characters
for x in range(0, shift_amt):
if (4 * self.number_of_displays - 1 - x) < 0:
break # Error check
self.display_content[4 * self.number_of_displays - 1 - x] = ' '
# Convert list of characters into string
temp = ''
for x in range(0, len(self.display_content)):
if self.display_content[x] != '\x00':
temp += self.display_content[x]
self.print(temp)
# ---------------------------------------------------------------------------------
# write_RAM(address, reg, buff)
#
# write LED updates to the RAM of the LED driver IC
[docs] def write_RAM(self, address, reg, buff):
"""
Write LED updates to the RAM of the LED driver IC
:param address: I2C address of the display
:param reg: the location in RAM to write to
:param buff: the bytes to be written
:return: true if RAM has been written to successfully, false otherwise.
:rtype: bool
"""
display_num = 1
if address == self._device_address_display_two:
display_num = 2
elif address == self._device_address_display_three:
display_num = 3
elif address == self._device_address_display_four:
display_num = 4
self.is_connected(display_num)
self._i2c.writeBlock(address, reg, buff)
def write_RAM_byte(self, address, data_to_write):
self._i2c.writeCommand(address, data_to_write)