141 lines
5.2 KiB
Python
141 lines
5.2 KiB
Python
# SPDX-FileCopyrightText: 2022 John Park for Adafruit Industries
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
# DTMF keypad phone Dial-a-Song
|
|
import time
|
|
import random
|
|
import board
|
|
import keypad
|
|
from audiocore import WaveFile
|
|
from audiopwmio import PWMAudioOut as AudioOut # for RP2040 etc
|
|
import audiomixer
|
|
|
|
# time.sleep(3) # let USB settle during development, remove when on battery
|
|
|
|
km = keypad.KeyMatrix(
|
|
# 2500 phone ignoring first column store/redial/memory. reverse mount on Feather RP2040
|
|
column_pins=( board.A3, board.A2, board.A1,),
|
|
row_pins=(
|
|
board.D24,
|
|
board.D25,
|
|
board.SCK,
|
|
board.MOSI,
|
|
),
|
|
)
|
|
|
|
numbers = {
|
|
"8675309" : "songs/beepbox.wav",
|
|
"6358393" : "songs/streetchicken.wav",
|
|
"5551212" : "songs/carpeter.wav",
|
|
"7654321" : "songs/daisy.wav"
|
|
}
|
|
|
|
ringing = "songs/full_ring.wav"
|
|
wrong_number = "songs/blank_number.wav"
|
|
dial_tone = "songs/dial_tone_loop.wav"
|
|
busy_signal = "songs/busy_loop.wav"
|
|
|
|
button_tones = [
|
|
"dtmf/tt_1.wav", "dtmf/tt_2.wav", "dtmf/tt_3.wav",
|
|
"dtmf/tt_4.wav", "dtmf/tt_5.wav", "dtmf/tt_6.wav",
|
|
"dtmf/tt_7.wav", "dtmf/tt_8.wav", "dtmf/tt_9.wav",
|
|
"dtmf/tt_star.wav", "dtmf/tt_0.wav", "dtmf/tt_pound.wav"
|
|
]
|
|
|
|
digits_entered = 0 # counter
|
|
dialed = [] # list of digits user enters to make one 7 digit number
|
|
dialed_str = "" # stores the phone number string for dictionary comparison
|
|
|
|
audio = AudioOut(board.TX) # PWM out pin
|
|
mixer = audiomixer.Mixer(
|
|
voice_count=4,
|
|
sample_rate=22050,
|
|
channel_count=1,
|
|
bits_per_sample=16,
|
|
samples_signed=True,
|
|
)
|
|
audio.play(mixer)
|
|
mixer.voice[0].level = 1.0 # dial tone voice
|
|
mixer.voice[1].level = 1.0 # touch tone voice
|
|
mixer.voice[2].level = 0.0 # song/message voice
|
|
mixer.voice[3].level = 0.0 # busy signal
|
|
|
|
wave_file0 = open(dial_tone, "rb")
|
|
wave0 = WaveFile(wave_file0)
|
|
mixer.voice[0].play(wave0, loop=True) # play dial tone
|
|
|
|
wave_file2 = open(wrong_number, "rb")
|
|
wave2 = WaveFile(wave_file2)
|
|
|
|
wave_file3 = open(busy_signal, "rb")
|
|
wave3 = WaveFile(wave_file3)
|
|
mixer.voice[3].play(wave3, loop=True) # play dial tone
|
|
|
|
|
|
def reset_number():
|
|
# pylint: disable=global-statement
|
|
global digits_entered, dialed, dialed_str
|
|
digits_entered = 0
|
|
dialed = []
|
|
dialed_str = ""
|
|
km.events.clear()
|
|
|
|
|
|
while True:
|
|
|
|
event = km.events.get() # check for keypad presses
|
|
if event:
|
|
if event.pressed:
|
|
mixer.voice[0].level = 0.0 # mute the dial tone
|
|
wave_file1 = open(button_tones[event.key_number], "rb") # play Touch Tone
|
|
wave1 = WaveFile(wave_file1)
|
|
mixer.voice[1].play(wave1)
|
|
if event.key_number == 9 or event.key_number == 11: # check for special keys
|
|
if event.key_number == 9: # pressed the '*' key
|
|
reset_number() # or make some cool new function for this key
|
|
if event.key_number == 11: # pressed the '#' key
|
|
reset_number() # or make some cool new function for this key
|
|
|
|
else: # number keys
|
|
if digits_entered < 7: # adding up to full number
|
|
# convert event to number printed on the keypad button, append to string
|
|
if event.key_number < 9: # 1-9 on keypad
|
|
dialed.append(event.key_number+1)
|
|
if event.key_number == 10: # the 0 key, ignore '*' and "#'
|
|
dialed.append(0)
|
|
dialed_str = "".join(str(n) for n in dialed)
|
|
digits_entered = digits_entered + 1 # increment counter
|
|
|
|
if digits_entered == 7: # a full number has been entered
|
|
if not mixer.voice[2].playing:
|
|
dialed_str = "".join(str(n) for n in dialed)
|
|
if dialed_str in numbers: # check if dialed string is one in the directory
|
|
value = numbers[dialed_str]
|
|
time.sleep(0.6)
|
|
|
|
wave_file2 = open(ringing, "rb") # ring before it answers
|
|
wave2 = WaveFile(wave_file2)
|
|
mixer.voice[2].level = 1.0
|
|
mixer.voice[2].play(wave2, loop=True)
|
|
|
|
time.sleep(random.uniform(4.0, 9.5)) # random ring before "answer"
|
|
|
|
wave_file2 = open(value, "rb") # answered
|
|
wave2 = WaveFile(wave_file2)
|
|
mixer.voice[2].level = 1.0
|
|
mixer.voice[2].play(wave2, loop=True)
|
|
|
|
else: # number is not in directory
|
|
time.sleep(0.5)
|
|
weighted_coin_toss = random.randint(0, 4)
|
|
if weighted_coin_toss < 3: # favor the "not in service" message
|
|
mixer.voice[2].level = 1.0
|
|
mixer.voice[2].play(wave2)
|
|
else:
|
|
mixer.voice[3].level = 1.0
|
|
|
|
reset_number()
|
|
|
|
if mixer.voice[2].playing:
|
|
reset_number() # stop #s dialed during message play from doing anything
|