DieselPunk Cellphone - Walnut Case, Powered by Adafruit Feather Fona:Software
Software
The excellent Adafruit SSD1306/Adafruit_GFX libraries would normally be my go-to display tools: fast and easy-to-use. These libraries can use significant amounts of memory, for good reasons. With so much going on, this project needed to reduce SRAM and program memory. Instead of the Adafruit libs, the project uses u8glib, which thrifty on both kinds of memory. There's a great explanation of the basics of using this lib at Henry's Bench.
Unfortunately, u8glib is no longer being developed by the maintainer. A new u8g2 lib is available. However, after making necessary changes to use the u8g2 lib, the DieselPunk Cellphone sketch uses too much program memory and will not compile. Therefore, I'm only supplying code to work with the u8glib.
A brief tour of the the code - the sketch does the following:
- Sends displays to the SSD1306 using the u8glib library
- Splash Screen first up
- Connects to the carrier network
- Controls the NeoPixel Jewel
- ...and the flashlight function
- Dials, Answers and Hang Up calls
- Pick from Favorite numbers you specify
- Plays FM Radio stations from a list you supply
Splash Screen
Create a bitmap with Inkscape/GIMP or your favorite drawing program. Export to a *.png format.
- Open your picture in GIMP
- Click Colors/Invert for the SD1306, if needed
- white was "pixel on" for me
- Image/Scale Image to your screen dimensions.
- Mine worked well at 80W x 64H pixels
- Image/Mode/Indexed, black & white (1-bit) palette
- Export as XBM (.xbm extension)
- Open the XBM file in a text editor, such as gedit in Linux or notepad in Windows.
- Copy contents of xbm file into your Arduino sketch - load into PROGMEM.
- Adjust the starting cursor position in your software's bitmap display to center the bitmap on screen.
Code
In the following code block, there isn't much error checking going on. The code will hang with "Looking for Service" displayed from the msgNetService call, if it can't connect. Takes 10-20 seconds to connect on T-Mobile, for me.
In the following code block, there isn't much error checking going on. The code will hang with "Looking for Service" displayed from the msgNetService call, if it can't connect. Takes 10-20 seconds to connect on T-Mobile, for me.
u8g.firstPage();
do {
msgConnect();
} while( u8g.nextPage() );
delay(2000);
// Check FONA is there
fonaSS.begin(9600); // if you're using software serial
// See if the FONA is responding
if (! fona.begin(fonaSS)) {
Serial.println(F("Couldn't find FONA :("));
while (1); // <=== Will hang here if Fona unresponsive
}
// Check we can connect to the network
while (fona.getNetworkStatus() != 1) { // <=== Will hang here if no network!
u8g.firstPage();
do {
msgNetService();
} while( u8g.nextPage() );
}
u8g.firstPage();
do {
msgNetConnect();
} while( u8g.nextPage() );
delay(2000);
When connected, "Connected to Network!" text will display for two seconds from msgNetConnect function. After that, the main menu will display.
Most of the time the sketch will just process the loop/main menu display, waiting for a keypress. Updated network signal strength [getRSSI] and battery level [getBattery], along with time and date, will update every 10 seconds. You may see the screen flicker or update slowly if the level updates coincide with screen refresh.
The functions called from the menu are basically just displays wrapped in 'while' loops. The loops only exit on a specified appropriate keypress, usually '*' ("Do it!") or '#' ("Cancel/Go Back/Hang Up!"). They'll remain in that code loop until the proper key is pressed. There are on-screen cues to indicate what the available keypress values are.
Here's a code snippet from the Dial function, callEntry:
void loop()
{
// don't hog the processor!
if (millis() - lastDisplay > 10000)
{
dbi = getRSSI(i_8);
vbat = getBattery(i_16);
cellDate();
cellTime();
lastDisplay = millis();
}
u8g.firstPage();
do {
dispMenu(dbi, vbat);
keyPress();
} while( u8g.nextPage() );
}
When a keypress event does happen, the key will trigger one of the following actions:- Flashlight function ('*' from main menu) toggles all LEDs on the Jewel full power/off; off is still 3 middle LEDs on, backlighting the speaker bezel
- Answer incoming call ('#' from main menu)
- Enter a number to Dial from the keypad (menu choice '1')
- Select a stored Favorite to Dial (menu choice '2')
- Select an FM radio station (menu choice '3') to play
void keyPress()
{
char key = keypad.getKey();
// NeoPixel Flashlight
if (key == '*')
{ flashlight_on = !flashlight_on;
flashlight();
return;
}
// Answer an incoming call
if (key == '#')
{ answerPhone();
return;
}
// convert a single character to int
int ikey = key - '0';
switch (ikey) {
case 1:
callEntry();
break;
case 2:
callFavorites();
break;
case 3:
callFMfavs();
break;
default:
// if nothing else matches, do the default
// default is optional
break;
}
}
The functions called from the menu are basically just displays wrapped in 'while' loops. The loops only exit on a specified appropriate keypress, usually '*' ("Do it!") or '#' ("Cancel/Go Back/Hang Up!"). They'll remain in that code loop until the proper key is pressed. There are on-screen cues to indicate what the available keypress values are.
Here's a code snippet from the Dial function, callEntry:
while ((key != '*') and (key != '#'))
{
key = keypad.getKey();
if (key)
{
phoneNumber[i] = key;
i++;
u8g.firstPage();
do {
callEntryDisplay(phoneNumber);
} while( u8g.nextPage() );
}
}
Comments
Post a Comment