Phone-Modding Part 2, the Python and the Program

Part 1

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.

Author: ariock

You're on the website. Just look around.

2 thoughts on “Phone-Modding Part 2, the Python and the Program”

Leave a Reply

Your email address will not be published. Required fields are marked *