// Header files -- start
#include <Arduino.h>
#include <U8g2lib.h> //U8G2 Library
#include <Wire.h> //For I2C connection
#include <vector>
// Header files -- end
// Store images as bitmaps here
/*
In Arduino programming, a "bitmap" typically refers to a graphical representation
of an image or pattern in a 2D grid of pixels. Each pixel in the grid is
represented by a binary value (0 or 1), indicating whether the pixel
is turned on (1) or off (0). Bitmaps are commonly used in applications
where you need to display graphics on devices like LCD screens or LED matrices.
*/
static const unsigned char SDCardIcon[] U8X8_PROGMEM = {0xfc, 0x0f, 0x06, 0x10, 0xaa, 0x22, 0xaa, 0x42, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0xfa, 0x5f, 0x0a, 0x50, 0x0a, 0x50, 0x0a, 0x50, 0x0a, 0x50, 0xfa, 0x5f, 0x06, 0x60, 0xfc, 0x3f};
static const unsigned char WiFiIcon[] U8X8_PROGMEM = {0xf0, 0x07, 0xfe, 0x3f, 0x0f, 0x78, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0xf8, 0x0f, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01};
static const unsigned char BluetoothIcon[] U8X8_PROGMEM = {0x60, 0x00, 0xe0, 0x00, 0xe0, 0x03, 0x60, 0x07, 0x7c, 0x0e, 0x7c, 0x0e, 0x78, 0x07, 0xf0, 0x01, 0xf0, 0x01, 0x78, 0x07, 0x7c, 0x0e, 0x7c, 0x0e, 0x60, 0x07, 0xe0, 0x01, 0xe0, 0x00, 0x60, 0x00};
static const unsigned char BatteryEmptyIcon[] U8X8_PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0xfe, 0x3f, 0xff, 0x7f, 0x07, 0x60, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0x60, 0xff, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char BatteryLowIcon[] U8X8_PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0xfe, 0x3f, 0xff, 0x7f, 0x37, 0x60, 0x37, 0xe0, 0x37, 0xe0, 0x37, 0x60, 0xff, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char BatteryMidIcon[] U8X8_PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0xfe, 0x3f, 0xff, 0x7f, 0xb7, 0x61, 0xb7, 0xe1, 0xb7, 0xe1, 0xb7, 0x61, 0xff, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char BatteryFullIcon[] U8X8_PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0xfe, 0x3f, 0xff, 0x7f, 0xb7, 0x6d, 0xb7, 0xed, 0xb7, 0xed, 0xb7, 0x6d, 0xff, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// Bitmaps -- end
// Store the names of bitmaps in an array for easy accessibility
const unsigned int bitmapImagesCount = 7;
const unsigned char* bitmapImages[bitmapImagesCount] = {
SDCardIcon,
WiFiIcon,
BluetoothIcon,
BatteryEmptyIcon,
BatteryLowIcon,
BatteryMidIcon,
BatteryFullIcon
};
// Bitmap names in array -- end
// StatusBar - Class to manage StatusBar icons
/*
StatusBar occupies the top-most row of a display to show necessary information
like time, bluetooth, WiFi etc.
*/
class StatusBar {
private:
U8G2 &u8g2_StatusBar; // Reference to the U8G2 object for the status bar
bool wifiEnabled; // Flag indicating whether WiFi is enabled
bool bluetoothEnabled; // Flag indicating whether Bluetooth is enabled
bool sdCardEnabled; // Flag indicating whether the SD card is enabled
int batteryLevel; // Current battery level
// Method to display the time on the status bar
void displayTime() {
/*
Draw string on the display at specified coordinates
Usage: u8g2.drawStr(x, y, "TEXT");
*/
u8g2_StatusBar.drawStr(6, 15, "17:00");
}
// Method to display the SD card icon on the status bar
void displaySdCardIcon() {
if (sdCardEnabled) {
/*
Draw XBM (X BitMap) image on the display at specified coordinates
Usage: u8g2.drawXBMP(x, y, width, height, data);
*/
u8g2_StatusBar.drawXBMP(42, 3, 16, 16, bitmapImages[0]);
}
}
// Method to display the WiFi icon on the status bar
void displayWifiIcon() {
if (wifiEnabled) {
u8g2_StatusBar.drawXBMP(65, 3, 16, 16, bitmapImages[1]);
}
}
// Method to display the Bluetooth icon on the status bar
void displayBluetoothIcon() {
if (bluetoothEnabled) {
u8g2_StatusBar.drawXBMP(86, 3, 16, 16, bitmapImages[2]);
}
}
// Enumeration for battery level states
enum BatteryLevel {
LEVEL_EMPTY,
LEVEL_LOW,
LEVEL_MID,
LEVEL_FULL
};
// Method to display the battery icon based on the battery level
void displayBatteryIcon() {
// Map the battery level to the enum
BatteryLevel batteryEnum = static_cast<BatteryLevel>(batteryLevel);
switch (batteryEnum) {
case LEVEL_EMPTY:
u8g2_StatusBar.drawXBMP(106, 3, 16, 16, bitmapImages[3]);
break;
case LEVEL_LOW:
u8g2_StatusBar.drawXBMP(106, 3, 16, 16, bitmapImages[4]);
break;
case LEVEL_MID:
u8g2_StatusBar.drawXBMP(106, 3, 16, 16, bitmapImages[5]);
break;
case LEVEL_FULL:
u8g2_StatusBar.drawXBMP(106, 3, 16, 16, bitmapImages[6]);
break;
default:
// Default to the empty battery icon
u8g2_StatusBar.drawXBMP(106, 3, 16, 16, bitmapImages[3]);
break;
}
}
public:
// Constructor for the StatusBar class
StatusBar(U8G2 &u8g2_StatusBar) : u8g2_StatusBar(u8g2_StatusBar), batteryLevel(0), wifiEnabled(false), bluetoothEnabled(false), sdCardEnabled(false) {}
// Setup method to initialize the OLED display settings
void setup() {
u8g2_StatusBar.begin();
u8g2_StatusBar.setBitmapMode(1);
u8g2_StatusBar.setFontMode(0);
u8g2_StatusBar.setDrawColor(1);
u8g2_StatusBar.setFont(u8g2_font_courB08_tn);
}
// Turn icons on/off
void setSdCardIcon(bool on) {
sdCardEnabled = on;
}
void setWifiIcon(bool on) {
wifiEnabled = on;
}
void setBluetoothIcon(bool on) {
bluetoothEnabled = on;
}
// Set battery level (0-3)
void setBatteryLevel(int level) {
if (level >= 0 && level <= 3) {
batteryLevel = level;
}
}
// Method to display icons on the status bar
void displayIcons() {
// Display icons from left to right
displayTime();
displaySdCardIcon();
displayWifiIcon();
displayBluetoothIcon();
displayBatteryIcon();
u8g2_StatusBar.drawFrame(1, 1, 126, 62);
u8g2_StatusBar.drawLine(1, 20, 126, 20);
}
};
// StatusBar class -- end
// Menu class for managing menu items
class Menu {
private:
int numberOfMenuItems; // Total number of menu items
std::vector<const char*> &menuItems; // Vector to store menu items
int selectedItem; // Index of the currently selected item
int nextItem; // Index of the next item in the menu
public:
// Constructor for the Menu class
Menu(int numberOfMenuItems, std::vector<const char*> &menuItems) : numberOfMenuItems(numberOfMenuItems), menuItems(menuItems), selectedItem(0), nextItem(1) {}
// Move to next item
void moveToNextItem() {
selectedItem = (selectedItem + 1) % numberOfMenuItems;
nextItem = (selectedItem + 1) % numberOfMenuItems;
}
// Move to previous item
void moveToPrevItem() {
selectedItem = selectedItem - 1;
if (selectedItem < 0)
selectedItem = numberOfMenuItems - 1;
nextItem = (selectedItem + 1) % numberOfMenuItems;
}
// Return currently selected item
const char* getCurrentItem() {
return menuItems[selectedItem];
}
// Return next item
const char* getNextItem() {
return menuItems[nextItem];
}
};
// OLED class for controlling the OLED screen
class OLED {
U8G2 u8g2_OLED; // U8G2 object for the OLED display
StatusBar statusBar; // StatusBar object
Menu mainMenu; // Menu object
const int BUTTON_DOWN_PIN = 2; // Pin for the down button
const int BUTTON_UP_PIN = 4; // Pin for the up button
public:
// Constructor for the OLED class
OLED(U8G2 &u8g2_OLED, StatusBar &sb, Menu &m) : u8g2_OLED(u8g2_OLED), statusBar(sb), mainMenu(m) {}
// Setup method to initialize the OLED display and button pins
void setup() {
statusBar.setup();
u8g2_OLED.begin();
u8g2_OLED.setBitmapMode(1);
u8g2_OLED.setFontMode(1);
pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP);
pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
}
// Loop method to handle OLED display updates
void loop() {
// Check if the up button is pressed and move to the previous menu item
if (digitalRead(BUTTON_UP_PIN) == LOW) {
mainMenu.moveToPrevItem();
}
// Check if the down button is pressed and move to the next menu item
if (digitalRead(BUTTON_DOWN_PIN) == LOW) {
mainMenu.moveToNextItem();
}
// Start rendering on the OLED display
u8g2_OLED.firstPage();
// Set various status bar properties
statusBar.setSdCardIcon(true);
statusBar.setWifiIcon(true);
statusBar.setBluetoothIcon(true);
statusBar.setBatteryLevel(2);
// Loop through the pages and render the status bar and menu
do {
statusBar.displayIcons();
displayMenu();
} while (u8g2_OLED.nextPage());
// Delay to control the update rate
delay(500);
}
// Method to display the menu on the OLED display
void displayMenu() {
u8g2_OLED.setFont(u8g2_font_courB10_tf);
u8g2_OLED.setDrawColor(2);
u8g2_OLED.drawBox(6, 24, 115, 16);
// Get the current item and next item
const char* currentItem = mainMenu.getCurrentItem();
const char* nextItem = mainMenu.getNextItem();
// Get the length of items to dynamically center the text wrto the screen
int x_offset_current = u8g2_OLED.getStrWidth(currentItem);
int x_offset_next = u8g2_OLED.getStrWidth(nextItem);
// Calculation of x offsets
x_offset_current = (118 - x_offset_current) / 2;
x_offset_next = (118 - x_offset_next) / 2;
// Display the current menu item
u8g2_OLED.drawStr(x_offset_current, 36, currentItem);
// Display the next menu item
u8g2_OLED.setFont(u8g2_font_courB10_tf);
u8g2_OLED.setDrawColor(1);
u8g2_OLED.drawStr(x_offset_next, 55, nextItem);
}
};
// Definition of constructors
// Two constructors to manage StatusBar and Menu separately
//Use for Wowki online simulator
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2_OLED(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2_StatusBar(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
//Use for hardware
// U8G2_SH1106_128X64_NONAME_F_SW_I2C u8g2_OLED(U8G2_R0, SCL, SDA,U8X8_PIN_NONE);
// U8G2_SH1106_128X64_NONAME_F_SW_I2C u8g2_StatusBar(U8G2_R0, SCL, SDA,U8X8_PIN_NONE);
// Constructors -- end
// Populate the menu items here
std::vector<const char*> menuItems = {"Read RFID", "Settings", "About"};
//Initialize the StatusBar class
StatusBar sb(u8g2_StatusBar);
// Initialize the Menu class
Menu menu(menuItems.size(), menuItems);
// Initialize OLED class
OLED oled(u8g2_OLED, sb, menu);
void setup(void) {
oled.setup();
}
void loop(void) {
oled.loop();
}