Skip to content

Print() scrolling text #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 87 additions & 24 deletions PiicoDev_SSD1306.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ def _set_pos(self, col=0, page=0):
c1, c2 = col * 2 & 0x0F, col >> 3
self.write_cmd(0x00 | c1) # lower start column address
self.write_cmd(0x10 | c2) # upper start column address

def fill(self, c=0):
for i in range(0, 1024):
if c > 0:
self.buffer[i] = 0xFF
else:
self.buffer[i] = 0x00

def pixel(self, x, y, color):
x = x & (WIDTH - 1)
y = y & (HEIGHT - 1)
Expand All @@ -78,17 +78,17 @@ def pixel(self, x, y, color):
def line(self, x1, y1, x2, y2, c):
# bresenham
steep = abs(y2-y1) > abs(x2-x1)

if steep:
# Swap x/y
tmp = x1
x1 = y1
y1 = tmp

tmp = y2
y2 = x2
x2 = tmp

if x1 > x2:
# Swap start/end
tmp = x1
Expand All @@ -97,12 +97,12 @@ def line(self, x1, y1, x2, y2, c):
tmp = y1
y1 = y2
y2 = tmp

dx = x2 - x1;
dy = abs(y2-y1)

err = dx/2

if(y1 < y2):
ystep = 1
else:
Expand All @@ -118,23 +118,23 @@ def line(self, x1, y1, x2, y2, c):
y1 += ystep
err += dx
x1 += 1

def hline(self, x, y, l, c):
self.line(x, y, x + l, y, c)

def vline(self, x, y, h, c):
self.line(x, y, x, y + h, c)

def rect(self, x, y, w, h, c):
self.hline(x, y, w, c)
self.hline(x, y+h, w, c)
self.vline(x, y, h, c)
self.vline(x+w, y, h, c)

def fill_rect(self, x, y, w, h, c):
for i in range(y, y + h):
self.hline(x, i, w, c)

def text(self, text, x, y, c=1):
fontFile = open("font-pet-me-128.dat", "rb")
font = bytearray(fontFile.read())
Expand All @@ -149,8 +149,8 @@ def text(self, text, x, y, c=1):
y_coordinate = y+i
if x_coordinate < WIDTH and y_coordinate < HEIGHT:
self.pixel(x_coordinate, y_coordinate, c)


class PiicoDev_SSD1306(framebuf.FrameBuffer):
def init_display(self):
self.width = WIDTH
Expand Down Expand Up @@ -192,6 +192,7 @@ def init_display(self):
_SET_DISP | 0x01, # display on
): # on
self.write_cmd(cmd)
self._init_print_text = False

def poweroff(self):
self.write_cmd(_SET_DISP)
Expand Down Expand Up @@ -220,15 +221,15 @@ def show(self):
self.write_cmd(0)
self.write_cmd(self.pages - 1)
self.write_data(self.buffer)

def write_cmd(self, cmd):
try:
self.i2c.writeto_mem(self.addr, int.from_bytes(b'\x80','big'), bytes([cmd]))
self.comms_err = False
except:
print(i2c_err_str.format(self.addr))
self.comms_err = True

def write_data(self, buf):
try:
self.write_list[1] = buf
Expand All @@ -237,7 +238,69 @@ def write_data(self, buf):
except:
print(i2c_err_str.format(self.addr))
self.comms_err = True


@property
def displaySize(self):
return [self.width,self.height]

def _init_print_text_func(self,spacing,font_size):
self.line_cnt = (HEIGHT-spacing[1])//(8+spacing[2])
self.disp_lst = [['',1]]* self.line_cnt
self.temp_display_lst = [['',1]]* self.line_cnt
self.font_height = font_size[1]
self.line_y_coord = [None]* self.line_cnt
self.font_size = font_size
for i in range(self.line_cnt):
self.line_y_coord[i] = spacing[1] + (font_size[1] + spacing[2])*i # Reduces processor burden
self._init_print_text = True
return self.line_y_coord

def draw_print_text(self,font_size_y,spacing,blanking):
if blanking:
self.fill(0)
for i in range(1,self.line_cnt+1):
self.text(self.temp_display_lst[-i][0],spacing[0],self.line_y_coord[self.line_cnt-i],self.temp_display_lst[-i][1])
if blanking:
self.show()
self.temp_display_lst = [['',1]]* self.line_cnt
self.disp_lst = self.disp_lst[-self.line_cnt:]

def trunctate_text(self,txt,delim,c):
if len(txt) > 15:
find_val= txt.rfind(' ',delim,15)
if delim and find_val is not -1:
[disp,to_disp] = [txt[0:find_val],txt[(find_val):].strip()]
else:
[disp,to_disp] = [txt[0:15],txt[15:]]
self.disp_lst.append([disp,c])
self.trunctate_text(to_disp,delim,c)
else:
self.disp_lst.append([txt,c])

def print(self,txt='',c=1,line_num=None,blanking=True,delim=True,font_size=[8,8],spacing=[0,0,0]):
''' Prints up to 15 characters on a new line of the OLED, more characters will flow on to a new line, repeated calls will increment the line counter'''
# line num - optional argument to manually specify the line number to be printed on, takes prio over auto incremented lines (allows them to be blanked, does not overwrite the text buffer)
# auto_scroll - does the text auto-scroll
# Delim, will a delimiting character move that 'word' to the next line
# Font size - [x,y] dimensions of the characters
#Spacing is formatted as [starting-x,starting-y, y-spacing(bottom to top of char), ]

if not self._init_print_text:
self._init_print_text_func(spacing,font_size)
if isinstance(txt,float) or isinstance(txt,int):
txt = str(txt)
if delim and not line_num:
if len(txt) > 15:
self.trunctate_text(txt,delim,c)
else:
self.disp_lst.append([txt,c])
self.temp_display_lst = self.disp_lst
if line_num is not None and (0< line_num <= self.line_cnt):
self.temp_display_lst[line_num-1] = [txt,c]
elif line_num is not None and not (0< line_num <= self.line_cnt):
print('line_num out of range, max is {}'.format(self.line_cnt))
self.draw_print_text(font_size[1],spacing,blanking)

def circ(self,x,y,r,t=1,c=1):
for i in range(x-r,x+r+1):
for j in range(y-r,y+r+1):
Expand All @@ -247,14 +310,14 @@ def circ(self,x,y,r,t=1,c=1):
else:
if((i-x)**2 + (j-y)**2 < r**2) and ((i-x)**2 + (j-y)**2 >= (r-r*t-1)**2):
self.pixel(i,j,c)

def arc(self,x,y,r,stAng,enAng,t=0,c=1):
for i in range(r*(1-t)-1,r):
for ta in range(stAng,enAng,1):
X = int(i*cos(radians(ta))+ x)
Y = int(i*sin(radians(ta))+ y)
self.pixel(X,Y,c)

def load_pbm(self, filename, c):
with open(filename, 'rb') as f:
line = f.readline()
Expand All @@ -272,7 +335,7 @@ def load_pbm(self, filename, c):
y_coordinate = byte * 8 // WIDTH
if x_coordinate < WIDTH and y_coordinate < HEIGHT:
self.pixel(x_coordinate, y_coordinate, c)

class graph2D:
def __init__(self, originX = 0, originY = HEIGHT-1, width = WIDTH, height = HEIGHT, minValue=0, maxValue=255, c = 1, bars = False):
self.minValue = minValue
Expand Down Expand Up @@ -314,7 +377,7 @@ def __init__(self, bus=None, freq=None, sda=None, scl=None, addr=0x3C):
super().__init__(self.buffer, WIDTH, HEIGHT, framebuf.MONO_VLSB)
self.fill(0)
self.show()

class PiicoDev_SSD1306_MicroBit(PiicoDev_SSD1306):
def __init__(self, bus=None, freq=None, sda=None, scl=None, addr=0x3C):
self.i2c = create_unified_i2c(bus=bus, freq=freq, sda=sda, scl=scl)
Expand All @@ -334,7 +397,7 @@ def __init__(self, bus=None, freq=None, sda=None, scl=None, addr=0x3C):
self.init_display()
self.fill(0)
self.show()

def create_PiicoDev_SSD1306(address=0x3C,bus=None, freq=None, sda=None, scl=None, asw=None):
if asw == 0: _a = 0x3C
elif asw == 1: _a = 0x3D
Expand All @@ -352,4 +415,4 @@ def create_PiicoDev_SSD1306(address=0x3C,bus=None, freq=None, sda=None, scl=None
display = PiicoDev_SSD1306_Linux(addr=_a, freq=freq)
else:
display = PiicoDev_SSD1306_MicroPython(addr=_a, bus=bus, freq=freq, sda=sda, scl=scl)
return display
return display
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ x2 | int | 0 - 127 | X2 coordinate
y2 | int | 0 - 63 | Y2 coordinate
c | int | 0 - 1 | Set the line to the given color (0: Black, 1: White)

### `PiicoDev_SSD1306.print(txt, c, line_num=None, auto_scroll=True, delim=True, font_size=[8,8], spacing=[0,0,0])`
Print text on the OLED, each subsequent call will increment the line number from the bottom of the display.

Parameter | Type | Range | Default | Description
--- | --- | --- | --- | ---
txt | string | Dependent | | Text to display.
c | int | 0 - 1 | 1 | The colour of the printed text
line_num | int | 0 - 8 (Dependent) | 0 | Optional: Prints on the requested line, default scrolls the text upwards
blanking | bool | True/False | True | When enabled each print() call redraws the display
delim | int | 0 - 16 | 1 | Set = 0/False to disable Delimiting
font_size | list of Integers | [1 - Font Width,1 - Font Height] | [8,8] | Used in calculations for the line spacing
spacing | list of Integers | [X-Starting Point, Y-Starting Point, Y-Spacing] | [0,0,0] | [X Starting Coordinate for all strings, Y Starting Coordinate for the first text write, Vertical spacing between Characters ]


### `PiicoDev_SSD1306.rect(x, y, w, h, c)`
Draw a rectangle at the given location, size and color. Draws only a 1 pixel outline.

Expand Down
85 changes: 85 additions & 0 deletions example/print.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from PiicoDev_SSD1306 import *
from PiicoDev_Unified import sleep_ms

import utime

display = create_PiicoDev_SSD1306()

delay = 3000

# Basic print statements
example_number = 210.2

display.print('Hello world')
display.print()
display.print(example_number) # Emulating printing sensor values
display.print()
display.print("Number: {}".format(example_number))

# Clear screen and internal lists
sleep_ms(delay)
for _ in range(8):
display.print()

# Demonstrate printing text at specific lines (with background boxes)

display.print('Line 2 text',line_num=2)
display.print('Line 4 text',line_num=4)
display.fill_rect(0,40,128,8,1)
display.print('Spooky line', line_num=6,c=0,blanking=False)
display.show()


# Clear screen and internal lists
sleep_ms(delay)
for _ in range(8):
display.print()

display.print('Show overflowing lines')

sleep_ms(int(delay/2))






# Clear screen and internal lists
sleep_ms(delay)
for _ in range(8):
display.print()

# Demonstrating the delimiting text functionality
show_delim = True
show_no_delim = False

if show_delim:
display.print('this string should overflow a couple of times into the next line on the OLED',delim=True) # Default

if show_no_delim:
display.print('this string should overflow a couple of times into the next line on the OLED',delim=False) # Raggedy

# Clear screen and internal lists
sleep_ms(delay)
for _ in range(8):
display.print()

# Running a benchmark for printing lines
display.print('show how fast it takes to print lots of lines')

sleep_ms(int(delay/2))

start = utime.ticks_us()
for i in range(100):
display.print('some text' + str(i))


display.print()
display.print()

outcome_str = str(round(utime.ticks_diff(utime.ticks_us(), start)/(100000000),2)) + ' seconds/print'
display.print(outcome_str)
print(outcome_str)



40 changes: 40 additions & 0 deletions example/print_menu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from PiicoDev_SSD1306 import *
from PiicoDev_Unified import sleep_ms

import utime

display = create_PiicoDev_SSD1306()

textYCoords = display._init_print_text_func(font_size=[8,8],spacing=[0,0,0])

def menuSelect(lineNum,display,textYCoords,font_height=8):
dispParams = display.displaySize
display.fill_rect(0,textYCoords[lineNum-1],dispParams[0],font_height,1)

def showMenu(mn_opt,hv_ln):
for i, item in enumerate(mn_opt):
if i == hv_ln-1:
display.print(item,line_num=i+1,c=0,blanking=False)
else:
display.print(item,line_num=i+1,c=1,blanking=False)

hover_line = 1

menu_options = ['option1','option2','option3','option4','option5']


for i in range(1,len(menu_options)):
display.fill(0)
menuSelect(hover_line,display,textYCoords)
showMenu(menu_options,hover_line)
hover_line = hover_line + 1
display.show()
sleep_ms(700)

for i in range(len(menu_options)+1,1,-1):
display.fill(0)
menuSelect(hover_line,display,textYCoords)
showMenu(menu_options,hover_line)
hover_line = hover_line-1
display.show()
sleep_ms(700)