Again, I highly recommend reviewing the previously linked site for how to get python up and running. Here’s a link to the next section:
https://learn.adafruit.com/touch-tone-phone-dial-a-song/circuitpython
I followed the instructions on here closely and had no problem getting python running and connecting to the board. I used a short USB type C connector to connect the feather to my computer. I never needed to use safe mode or anything. It just worked.
Next is the code:
https://learn.adafruit.com/touch-tone-phone-dial-a-song/circuitpython
I highly recommend getting Mu, which is a tool to assist in programming with python on boards like this. Here’s a link with help on doing that:
https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor
In the video I posted, showing the system working, I am using Mu. I have the program stopped at the beginning, and then using the REPL, I start the program, which causes the dial tone to start playing. Basically, you connect your Feather to the computer. You start Mu. You open a serial connection to the Feather in Mu. And finally, you hit Ctrl-C to stop the program. You hit Ctrl-D to restart it.
Another great thing about Mu is that it will check the code for you. For example, several of the lines in the code provided are too long according to Mu. Also, be careful with spaces around comments.
In addition to the code provided with the instructions on building the phone, we also need code for our SD Card reader. Here’s where I went for help:
https://learn.adafruit.com/adafruit-micro-sd-breakout-board-card-tutorial/circuitpython
Which is different from this:
https://learn.adafruit.com/adafruit-microsd-spi-sdio/circuitpython
Note that there are a number of confusing and contradictory bits. The code I ended up using seemed the simplest, and it ultimately worked.
Returning to the main guide for the phone, the last thing mentioned on the program page is regarding modifying audio files so that they’ll work with the program.
https://learn.adafruit.com/microcontroller-compatible-audio-file-conversion/check-your-files
Make sure you follow the instructions closely when making your audio files. I accidentally used a 24000 hz instead of 20000 hz for one file, and the program wouldn’t open it.
Finally, here’s the code I used. It works so far.
# SPDX-FileCopyrightText: 2022 John Park for Adafruit Industries
# Modified By Ariock for beekeepers
# 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
import busio
import sdcardio
import storage
# Use the board's primary SPI bus
# spi = board.SPI()
# Or, use an SPI bus on specific pins:
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
# old spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
# spi = busio.SPI(board.SD_SCK, MOSI=board.SD_MOSI, MISO=board.SD_MISO)
# For breakout boards, you can choose any GPIO pin that's convenient:
cs = board.D10
# Boards with built in SPI SD card slots will generally have a
# pin called SD_CS:
# cs = board.SD_CS
sdcard = sdcardio.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
# 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 Feather RP2040
column_pins=(board.A3, board.A2, board.A1,),
row_pins=(
board.D24,
board.D25,
board.D4,
board.D5,
),
)
numbers = {
"8675309" : "songs/beepbox.wav",
"6358393" : "songs/streetchicken.wav",
"5551212" : "songs/carpeter.wav",
"7654321" : "songs/daisy.wav",
"9255292" : "/sd/week1_subject2.wav", # walkawa
"2772643" : "/sd/week1_subject3.wav", # arrange
"2696338" : "/sd/week1_subject1.wav", # boymeet
"4423273" : "/sd/week1_subject5.wav", # ihadare
"9486377" : "/sd/week2_subject2.wav", # witness
"7332888" : "/sd/week2_subject3.wav", # redbutt
"4376636" : "/sd/week2_subject1.wav", # ifsomeo
"6537743" : "/sd/week2_subject5.wav", # oldspie
"8446546" : "/sd/week3_subject2.wav", # thinkin
"2442536" : "/sd/week3_subject3.wav", # chicken
"8293778" : "/sd/week3_subject1.wav", # taxessu
"2762259" : "/sd/week3_subject5.wav", # apocaly
"2443640" : "/sd/week4_subject2.wav", # bigdog0
"8682559" : "/sd/week4_subject3.wav", # totally
"2834800" : "/sd/week4_subject1.wav", # audit00
"7327848" : "/sd/week4_subject4.wav", # recruit
"3644620" : "/sd/week4_subject5.wav", # enigma0
"2264000" : "/sd/week5_subject2.wav", # bang000
"2274660" : "/sd/week5_subject3.wav", # casino0
"2765343" : "/sd/week5_subject1.wav", # asoldie
"9333464" : "/sd/week5_subject4.wav", # wedding
"3333464" : "/sd/week5_subject5.wav", # feeding
"4232732" : "/sd/week6_subject2.wav", # icecrea
"2332470" : "/sd/week6_subject3.wav", # affair0
"7867699" : "/sd/week6_subject1.wav", # stormyw
"5867370" : "/sd/week6_subject4.wav", # jumper0
"6926672" : "/sd/week6_subject5.wav", # myconsc
"2444373" : "/sd/week7_subject2.wav", # biggerd
"9276463" : "/sd/week7_subject3.wav", # yasmine
"7533777" : "/sd/week7_subject1.wav", # sleepsp
"5278786" : "/sd/week7_subject4.wav", # laststo
"3475662" : "/sd/week7_subject5.wav", # diploma
"3863725" : "/sd/week8_subject2.wav", # funeral
"2672547" : "/sd/week8_subject3.wav", # coralis
"4475423" : "/sd/week8_subject1.wav", # girlhad
"6965353" : "/sd/week8_subject4.wav", # myoldke
"7378587" : "/sd/week8_subject5.wav", # results
"2797825" : "/sd/week9_subject2.wav", # crystal
"3384500" : "/sd/week9_subject3.wav", # devil00
"7383693" : "/sd/week9_subject1.wav", # sevenye
"2526246" : "/sd/week9_subject4.wav", # clamcho
"9687325" : "/sd/week9_subject5.wav", # youreal
"5646464" : "/sd/week10_subject2.wav", # joining
"3264597" : "/sd/week10_subject3.wav", # familyr
"5377397" : "/sd/week10_subject1.wav", # jerseys
"7358282" : "/sd/week10_subject4.wav", # relucta
"8742645" : "/sd/week10_subject5.wav", # triangl
"4376370" : "/sd/week11.wav", # heroes0
"6637646" : "/sd/week12_subject2.wav", # onepoin
"3426233" : "/sd/week12_subject3.wav", # fiancee
"5878254" : "/sd/week12_subject1.wav", # justali
"7328466" : "/sd/week12_subject4.wav" # section
}
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 fr 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 on the keypad button, add 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 string is in 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 b4 answr
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" msg
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 play doing anything
The next section is on modding the phone itself.
2 thoughts on “Phone-Modding Part 2, the Python and the Program”