Arduino-based pill timer that makes phone calls
Operation of the pill timer
The pill timer connects to a keypad, an LCD, and a telephone handset. when the user powers on the pill timer, they must enter the current time using the keypad. To start the timer, the user presses tha "1" key on the keypad. The pill timer determines at what times the user needs to take their pills according to a schedule that has been hard-coded into the pill timer. When it is time for the user to take a pill, the timer will initiate a call to a pre-programmed number. Once the user has picked up, it will play a recorded message. Specifically, this recorded message is "It is time for pill box number" followed by a number.
Schematic and explanation
Memory chip
The Arduino is connected to a W25Q64JV 64 megabit flash chip that stores the voice messages. The first part of the message ("It is time for pill box number") is stored as a WAV file at address 0x000000. The numbers 1-7 are stored as WAV files at addresses 0x030000, 0x040000, and so on. Since the memory chip is a 3.3 volt device, resistor dividers were needed to make the voltages compatible.
Telephone
The Arduino communicates with and controls the telephone handset via the phone's serial port (For more details on hacking the phone, see below). ADC inputs 0 and 1 are configured as a differential input and receive a signal from the handset's speaker output. This allows the Arduino to identify call progress tones. To play the voice messages, the Arduino uses an R2R DAC (resistors R1-R18) to generate an analog signal from a digital port.
The phone is powered using a regulator circuit based on Q1. The power supply to the phone can be switched using pin L3. When pin L3 is high, C2 charges via the potentiometer. Q1 acts as an emitter follower and buffers the voltage on C2. C3 stabilizes the output. The voltage fed to the phone may be adjusted using the potentiometer so that it is around 3.5 volts.
Making calls with an Arduino
During the call, the Arduino must detect and identify the following call progress tones:Name | Frequency 1 | Frequency 2 | Cadence | Description |
---|---|---|---|---|
Dial tone | 350Hz | 440Hz | Continuous | Present if the line is not in use |
Busy tone | 480Hz | 620Hz | 0.5s on, 0.5s off | Present if the called party is using the phone |
Reorder tone | 480Hz | 620Hz | 0.25s on, 0.25s off | Present after the called party hangs up |
Ringing tone | 440Hz | 480Hz | 2s on, 4s off | Present after the calling party has dialled but before the called party has picked up |
DTMF * | 941Hz | 1209Hz | Continuous | Present when the called party presses the "*" button |
To do this, the Arduino collects 250 samples from the speaker output pins of the handset at a sample frequency of 8000 samples per second. A discrete Fourier transform (DFT) is applied to the collected samples. However, to save time and memory, the DFT is only calculated at the particular frequencies needed to identify the above tones (350, 440, 480, and 620Hz). To further speed up this process, a table of sine and cosine values for each frequency is precomputed and stored in program memory.
After computing the DFT, one is left with a "magnitude" for each frequency. For each of the above tones, the Arduino checks if the magnitudes of the frequencies involved in that tone are above a certain threshold. In this way, the Arduino can determine the state of the call.
Before placing a call, the Arduino tells the handset to enter the off-hook state. The Arduino then checks for a dial tone to verify that the line is not already in use. If it is, no call is placed. If the dial tone is detected, it will tell the handset to dial a pre-programmed number stored in the handset's phonebook. The Arduino will then listen to the output of the handset, and if it identifies a busy tone, it hangs up. If the phone begins to ring, the Arduino will count the number of rings. After the phone rings four times, the Arduino tells the handset to hang up to avoid leaving a message. If the user picks up before then, the phone will pause and then play the message. When the user hangs up, the Arduino will hear the reorder tone and hang up as well. Since the reorder tone and busy tone have the same frequencies and are both a reason to hang up, there is no need to measure the cadence of the received tone.
Hacking the phone handset
The handset (KX-TGFA51) has pads on its PCB that are configured as a 19.2kbps serial port. The handset can accept commands through its serial port that control the phone or read information from it. A command consists of a 3 letter name followed by zero or more arguments separated by spaces, followed by a newline. Very little information is available about what these commands are or do. Some information can be extracted from the service manuals of similar phone systems. I have compiled a list the commands that I have been able to identify.
Command | Description | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
key <num> |
Simulates a button press on one of the keys.
|
||||||||||||||||||||||||||||||||
epr <addr[1]> <addr[0]> <num> |
Read from the EEPROMaddr[1] : The upper byte of the address as hex stringaddr[0] : The lower byte of the address as a hex stringnum : The number of bytes the be read, as a hex string
|
||||||||||||||||||||||||||||||||
epw <addr[1]> <addr[0]> <num> [<data>...] |
Write to the EEPROMaddr[1] : The upper byte of the address as hex stringaddr[0] : The lower byte of the address as a hex stringnum : The number of bytes to be written, as a hex string[<data>...] : One or more data bytes
|
||||||||||||||||||||||||||||||||
epv | Returns the checksum of the EEPROM. The algorithm is not known. | ||||||||||||||||||||||||||||||||
idr | Returns the ID of the device. Equivalent to epr 00 01 05 |
||||||||||||||||||||||||||||||||
led <val> | led <val> for val < 8 seems to turn the screen backlight off and led a seems to turn the screen backlight on. Aside from these values, I do not know what this command does. |
||||||||||||||||||||||||||||||||
sfr [<val[1]> <val[0]>] | This command is used to calibrate the main oscillator. If no argument is given, this command will return the current calibration value. If an argument is given, the calibration value will be set | ||||||||||||||||||||||||||||||||
vdd [<val>] | This command is used to calibrate the 1.8V power rail. It works similarly to the sfr command, except with only one byte |
||||||||||||||||||||||||||||||||
ad1 | This command is used to measure the charging voltage. Returns one byte as a hex string | ||||||||||||||||||||||||||||||||
tst [<data>...] | This command seems to be used to test the wireless transmitter in conjunction with a DECT tester. |
- crx <p1> <p2>
- pad
- lcd <val>
WARNING: executing the epf
command will brick the handset! If there is a need to use it for some reason, make a backup of the EEPROM contents.
key 12
, which is equivalent to the speakerphone key. If a dial tone is detected, the Arduino sends the command key 13
to hang up the phone. Then, it sends key 4
, then key 2
, then key 3
to select the appropriate entry in the phonebook. Finally, it sends key 12
again to pick up the handset. If no dialtone is detected, or the call is to be ended, then the Arduino sends key 13
to end the call before powering off the handset
Comments
Post a Comment