Skip to content

Instantly share code, notes, and snippets.

@gjyoung1974
Last active Jun 7, 2020
Embed
What would you like to do?
pyphone.py
#!/bin/env python
import pickle
import fnmatch
import os # For Raspi hardware + Find OS Path for images
import pygame
# why do we need *?
from pygame import *
from time import sleep
import serial
busy = False
threadExited = False
screenMode = 0 # Current screen mode; default = viewfinder
phonecall = 1
screenModePrior = -1 # Prior screen mode (for detecting changes)
iconPath = 'icons' # Subdirectory containing UI bitmaps (PNG format)
numeric = 0 # number from numeric keypad
numberstring = ""
motorRunning = 0
motorDirection = 0
returnScreen = 0
shutterpin = 17
motorpinA = 18
motorpinB = 27
motorpin = motorpinA
currentframe = 0
framecount = 100
settling_time = 0.2
shutter_length = 0.2
interval_delay = 0.2
dict_idx = "Interval"
v = {"Pulse": 100,
"Interval": 3000,
"Images": 150}
icons = [] # This list gets populated at startup
# UI classes ---------------------------------------------------------------
# The list of Icons is populated at runtime from the contents of the 'icons' directory.
class Icon:
def __init__(self, name):
self.name = name
try:
self.bitmap = pygame.image.load(iconPath + '/' + name + '.png')
except:
pass
class Button:
def __init__(self, rect, **kwargs):
self.rect = rect # Bounds
self.color = None # Background fill color, if any
self.iconBg = None # Background Icon (atop color fill)
self.iconFg = None # Foreground Icon (atop background)
self.bg = None # Background Icon name
self.fg = None # Foreground Icon name
self.callback = None # Callback function
self.value = None # Value passed to callback
for key, value in kwargs.items():
if key == 'color':
self.color = value
elif key == 'bg':
self.bg = value
elif key == 'fg':
self.fg = value
elif key == 'cb':
self.callback = value
elif key == 'value':
self.value = value
def selected(self, pos):
x1 = self.rect[0]
y1 = self.rect[1]
x2 = x1 + self.rect[2] - 1
y2 = y1 + self.rect[3] - 1
if ((pos[0] >= x1) and (pos[0] <= x2) and
(pos[1] >= y1) and (pos[1] <= y2)):
if self.callback:
if self.value is None:
self.callback()
else:
self.callback(self.value)
return True
return False
def draw(self, screen):
if self.color:
screen.fill(self.color, self.rect)
if self.iconBg:
screen.blit(self.iconBg.bitmap,
(self.rect[0] + (self.rect[2] - self.iconBg.bitmap.get_width()) / 2,
self.rect[1] + (self.rect[3] - self.iconBg.bitmap.get_height()) / 2))
if self.iconFg:
screen.blit(self.iconFg.bitmap,
(self.rect[0] + (self.rect[2] - self.iconFg.bitmap.get_width()) / 2,
self.rect[1] + (self.rect[3] - self.iconFg.bitmap.get_height()) / 2))
def setBg(self, name):
if name is None:
self.iconBg = None
else:
for i in icons:
if name == i.name:
self.iconBg = i
break
# UI callbacks -------------------------------------------------------------
# These are defined before globals because they're referenced by items in
# the global buttons[] list.
def numericCallback(n): # Pass 1 (next setting) or -1 (prev setting)
global screenMode
global numberstring
global phonecall
if n < 10 and screenMode == 0:
numberstring = numberstring + str(n)
elif n == 10 and screenMode == 0:
numberstring = numberstring[:-1]
elif n == 12:
# if phonecall == 0:
if screenMode == 0:
if len(numberstring) > 0:
serialport.write(str('AT\r').encode('ascii'))
# response = str(serialport.readlines(None)).encode('ascii')
new_numberstring = str(numberstring + ';\r').encode('ascii')
serialport.write(new_numberstring)
# @ + str(numberstring).encode('ascii') + ';\r')
# response = serialport.readlines(str(None).encode('ascii'))
# print response
# phonecall = 1
screenMode = 1
else:
print("Hanging Up...")
serialport.write(str("AT\r").encode('ascii'))
serialport.write(str("ATH\r").encode('ascii'))
screenMode = 0
if len(numberstring) > 0:
numeric = int(numberstring)
v[dict_idx] = numeric
buttons = [
# Screen 0 for numeric input
[Button((30, 0, 320, 60), bg='box'),
Button((30, 60, 60, 60), bg='1', cb=numericCallback, value=1),
Button((90, 60, 60, 60), bg='2', cb=numericCallback, value=2),
Button((150, 60, 60, 60), bg='3', cb=numericCallback, value=3),
Button((30, 110, 60, 60), bg='4', cb=numericCallback, value=4),
Button((90, 110, 60, 60), bg='5', cb=numericCallback, value=5),
Button((150, 110, 60, 60), bg='6', cb=numericCallback, value=6),
Button((30, 160, 60, 60), bg='7', cb=numericCallback, value=7),
Button((90, 160, 60, 60), bg='8', cb=numericCallback, value=8),
Button((150, 160, 60, 60), bg='9', cb=numericCallback, value=9),
Button((30, 210, 60, 60), bg='star', cb=numericCallback, value=0),
Button((90, 210, 60, 60), bg='0', cb=numericCallback, value=0),
Button((150, 210, 60, 60), bg='hash', cb=numericCallback, value=0),
Button((180, 260, 60, 60), bg='del2', cb=numericCallback, value=10),
Button((90, 260, 60, 60), bg='call', cb=numericCallback, value=12)],
# Screen 1 for numeric input
[Button((30, 0, 320, 60), bg='box'),
Button((90, 260, 60, 60), bg='hang', cb=numericCallback, value=12)]
]
# TODO better way to save settings
def saveSettings():
global v
try:
outfile = open('piphone.pkl', 'wb')
# Use a dictionary (rather than pickling 'raw' values) so
# the number & order of things can change without breaking.
pickle.dump(v, outfile)
outfile.close()
except:
pass
pickle
def loadSettings():
global v
try:
infile = open('piphone.pkl', 'rb')
v = pickle.load(infile)
infile.close()
except:
pass
# Initialization -----------------------------------------------------------
# Init framebuffer/touchscreen environment variables
# Specific to Rasberri Pi Hardware
# os.putenv('SDL_VIDEODRIVER', 'fbcon')
# os.putenv('SDL_FBDEV', '/dev/fb1')
# os.putenv('SDL_MOUSEDRV', 'TSLIB')
# os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')
# # Init pygame and screen
pygame.init()
# pygame.mouse.set_visible(False)
# Hide mouse on RasPi
# Show mouse on Linux
pygame.mouse.set_visible(True)
modes = pygame.display.list_modes(16)
# Rasberri Pi screen
# screen = pygame.display.set_mode(modes[0], FULLSCREEN, 16)
# screen = pygame.display.set_mode(modes)
# Linux Lappy
screen = pygame.display.set_mode(size=(240, 320), flags=0, depth=0, display=0)
# Load all icons at startup.
for file in os.listdir(iconPath):
if fnmatch.fnmatch(file, '*.png'):
icons.append(Icon(file.split('.')[0]))
# Assign Icons to Buttons, now that they're loaded
for s in buttons: # For each screenful of buttons...
for b in s: # For each button on screen...
for i in icons: # For each icon...
if b.bg == i.name: # Compare names; match?
b.iconBg = i # Assign Icon to Button
b.bg = None # Name no longer used; allow garbage collection
if b.fg == i.name:
b.iconFg = i
b.fg = None
loadSettings() # Must come last; fiddles with Button/Icon states
img = pygame.image.load("icons/PiPhone.png")
if img is None or img.get_height() < 240: # Letterbox, clear background
screen.fill(0)
if img:
screen.blit(img,
((240 - img.get_width()) / 2,
(320 - img.get_height()) / 2))
pygame.display.update()
sleep(2)
print('Initialising Modem..')
# Laptop vs Raspi
serialport = serial.Serial("/dev/ttyUSB0", 115200, timeout=0.5)
serialport.write(str("AT\r").encode('ascii'))
response = serialport.readlines(None)
serialport.write(str("ATE0\r").encode('ascii'))
response = serialport.readlines(None)
serialport.write(str("AT\r").encode('ascii'))
# Need a serial port emulator for Linux Laptops vs RasPi hardware
response = 'connect' # serialport.readlines(None)
print(response)
while (True):
# Process touchscreen input
while True:
screen_change = 0
for event in pygame.event.get():
if (event.type is MOUSEBUTTONDOWN):
pos = pygame.mouse.get_pos()
for b in buttons[screenMode]:
if b.selected(pos): break
screen_change = 1
# if screenMode >= 1 or screenMode != screenModePrior: break
if screen_change == 1 or screenMode != screenModePrior: break
if img is None or img.get_height() < 240:
screen.fill(0)
if img:
screen.blit(img,
((240 - img.get_width()) / 2,
(320 - img.get_height()) / 2))
# Overlay buttons on display and update
for i, b in enumerate(buttons[screenMode]):
b.draw(screen)
if screenMode == 0:
myfont = pygame.font.SysFont("Arial", 40)
label = myfont.render(numberstring, 1, (255, 255, 255))
screen.blit(label, (10, 2))
else:
myfont = pygame.font.SysFont("Arial", 35)
label = myfont.render("Calling", 1, (255, 255, 255))
screen.blit(label, (10, 80))
myfont = pygame.font.SysFont("Arial", 35)
label = myfont.render(numberstring + "...", 1, (255, 255, 255))
screen.blit(label, (10, 120))
pygame.display.update()
screenModePrior = screenMode
# if __name__ == "__main__":
# # execute only if run as a script
# main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment