// simple project using Arduino UNO and 128x64 OLED Display for parking sensor
// created by upir, 2022
// youtube channel: https://www.youtube.com/upir_upir

// youtube video: https://youtu.be/sEWw087KOj0
// youtube full video: https://youtu.be/gg08H-6Z1Lo
// Github: https://github.com/upiir/arduino_parking_sensor

// u8g fonts (fonts available for u8g library): https://nodemcu-build.com/u8g-fonts.php
// u8g documentation: https://github.com/olikraus/u8glib/wiki/userreference
// Wokwi starting project: https://wokwi.com/arduino/projects/300867986768527882
// Wokwi starting project distance sensor: https://wokwi.com/projects/304444938977804866
// Photopea (online Photoshop-like tool): https://www.photopea.com/
// image2cpp (convert images into C code): https://javl.github.io/image2cpp/

// useful links:
// OLED Display: https://s.click.aliexpress.com/e/_AWSVnt
// 128x64 SSD1306 OLED Display: https://s.click.aliexpress.com/e/_DCKdvnh
// Transparent OLED display: https://s.click.aliexpress.com/e/_Dns6eLz
// u8g documentation: https://github.com/olikraus/u8glib/wiki/userreference
// Arduino UNO: https://s.click.aliexpress.com/e/_AXDw1h
// Arduino UNO MINI: https://store.arduino.cc/products/uno-mini-le
// Big OLED Display: https://s.click.aliexpress.com/e/_ADL0T9
// Arduino breadboard prototyping shield: https://s.click.aliexpress.com/e/_ApbCwx

// Related videos:
// Turbo pressure gauge with Arduino and OLED display - https://youtu.be/JXmw1xOlBdk
// Arduino Car Cluster with OLED Display - https://youtu.be/El5SJelwV_0
// Knob over OLED Display - https://youtu.be/SmbcNx7tbX8
// Arduino + OLED = 3D ? - https://youtu.be/kBAcaA7NAlA
// Arduino OLED Gauge - https://youtu.be/xI6dXTA02UQ



#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI


// 'car_image', 56x15px
const unsigned char bitmap_car_image [] PROGMEM = {
	0xc0, 0x40, 0x00, 0x00, 0x00, 0x02, 0x03, 0xc0, 0x8f, 0xff, 0xff, 0xff, 0xf1, 0x03, 0xe0, 0x70, 
	0x00, 0x00, 0x00, 0x0e, 0x07, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xc0, 0xff, 0x00, 0x00, 
	0x00, 0xff, 0x03, 0xc0, 0x00, 0x05, 0x75, 0xc0, 0x00, 0x03, 0x47, 0xf8, 0x05, 0x51, 0x40, 0x1f, 
	0xe2, 0x47, 0xfc, 0x05, 0x65, 0x80, 0x3f, 0xe2, 0x40, 0x78, 0x06, 0x45, 0x40, 0x1e, 0x02, 0x30, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1e, 0x01, 0xff, 0xff, 0xff, 0x80, 0x78, 0x07, 0xe2, 0x00, 
	0x00, 0x00, 0x47, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 
	0xfd, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00
};
// 'sensor_01_a_off', 32x14px
const unsigned char bitmap_sensor_01_a_off [] PROGMEM = {
	0x00, 0x40, 0x00, 0x00, 0x02, 0xa8, 0x00, 0x00, 0x05, 0x55, 0x00, 0x00, 0x02, 0xaa, 0xa0, 0x00, 
	0x05, 0x55, 0x54, 0x00, 0x0a, 0xaa, 0xaa, 0xa0, 0x15, 0x55, 0x55, 0x50, 0x0a, 0xaa, 0xaa, 0xa0, 
	0x01, 0x55, 0x55, 0x40, 0x00, 0x2a, 0xaa, 0xa0, 0x00, 0x15, 0x55, 0x40, 0x00, 0x02, 0xaa, 0xa0, 
	0x00, 0x00, 0x15, 0x40, 0x00, 0x00, 0x02, 0xa0
};
// 'sensor_01_a_on', 32x14px
const unsigned char bitmap_sensor_01_a_on [] PROGMEM = {
	0x00, 0xc0, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 
	0x0f, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 
	0x03, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xe0, 
	0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00, 0x03, 0xe0
};
// 'sensor_01_b_off', 32x16px
const unsigned char bitmap_sensor_01_b_off [] PROGMEM = {
	0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x05, 0x54, 0x00, 0x00, 
	0x0a, 0xaa, 0x80, 0x00, 0x15, 0x55, 0x50, 0x00, 0x0a, 0xaa, 0xaa, 0x80, 0x15, 0x55, 0x55, 0x50, 
	0x0a, 0xaa, 0xaa, 0xa8, 0x05, 0x55, 0x55, 0x50, 0x00, 0xaa, 0xaa, 0xa8, 0x00, 0x15, 0x55, 0x50, 
	0x00, 0x02, 0xaa, 0xa0, 0x00, 0x00, 0x55, 0x50, 0x00, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x50
};
// 'sensor_01_b_on', 32x16px
const unsigned char bitmap_sensor_01_b_on [] PROGMEM = {
	0x02, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 
	0x0f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xf8, 
	0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xf8, 
	0x00, 0x07, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xf0
};
// 'sensor_01_c_off', 32x17px
const unsigned char bitmap_sensor_01_c_off [] PROGMEM = {
	0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x15, 0x50, 0x00, 0x00, 
	0x2a, 0xaa, 0x00, 0x00, 0x15, 0x55, 0x40, 0x00, 0x2a, 0xaa, 0xaa, 0x00, 0x55, 0x55, 0x55, 0x40, 
	0x2a, 0xaa, 0xaa, 0xaa, 0x15, 0x55, 0x55, 0x54, 0x02, 0xaa, 0xaa, 0xa8, 0x00, 0x55, 0x55, 0x54, 
	0x00, 0x0a, 0xaa, 0xa8, 0x00, 0x01, 0x55, 0x54, 0x00, 0x00, 0x2a, 0xa8, 0x00, 0x00, 0x05, 0x54, 
	0x00, 0x00, 0x00, 0x28
};
// 'sensor_01_c_on', 32x17px
const unsigned char bitmap_sensor_01_c_on [] PROGMEM = {
	0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 
	0x3f, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xe0, 
	0x7f, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xfc, 
	0x00, 0x1f, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x07, 0xfc, 
	0x00, 0x00, 0x00, 0x3c
};
// 'sensor_01_d_off', 32x18px
const unsigned char bitmap_sensor_01_d_off [] PROGMEM = {
	0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x2a, 0x80, 0x00, 0x00, 
	0x55, 0x50, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x55, 0x55, 0x50, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 
	0x55, 0x55, 0x55, 0x50, 0x2a, 0xaa, 0xaa, 0xaa, 0x05, 0x55, 0x55, 0x54, 0x02, 0xaa, 0xaa, 0xaa, 
	0x00, 0x55, 0x55, 0x54, 0x00, 0x0a, 0xaa, 0xaa, 0x00, 0x01, 0x55, 0x54, 0x00, 0x00, 0x2a, 0xa8, 
	0x00, 0x00, 0x01, 0x54, 0x00, 0x00, 0x00, 0x08
};
// 'sensor_02_a_off', 32x9px
const unsigned char bitmap_sensor_02_a_off [] PROGMEM = {
	0x05, 0x55, 0x55, 0x40, 0x0a, 0xaa, 0xaa, 0xa0, 0x05, 0x55, 0x55, 0x40, 0x0a, 0xaa, 0xaa, 0xa0, 
	0x05, 0x55, 0x55, 0x40, 0x0a, 0xaa, 0xaa, 0xa0, 0x05, 0x55, 0x55, 0x40, 0x0a, 0xaa, 0xaa, 0xa0, 
	0x15, 0x55, 0x55, 0x50
};
// 'sensor_01_d_on', 32x18px
const unsigned char bitmap_sensor_01_d_on [] PROGMEM = {
	0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 
	0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xfe, 0x00, 
	0x7f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xfe, 
	0x00, 0x7f, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xfc, 
	0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x1c
};
// 'sensor_02_a_on', 32x9px
const unsigned char bitmap_sensor_02_a_on [] PROGMEM = {
	0x07, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 
	0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 
	0x1f, 0xff, 0xff, 0xf0
};
// 'sensor_02_b_off', 32x9px
const unsigned char bitmap_sensor_02_b_off [] PROGMEM = {
	0x15, 0x55, 0x55, 0x50, 0x0a, 0xaa, 0xaa, 0xa0, 0x15, 0x55, 0x55, 0x50, 0x0a, 0xaa, 0xaa, 0xa0, 
	0x15, 0x55, 0x55, 0x50, 0x2a, 0xaa, 0xaa, 0xa8, 0x15, 0x55, 0x55, 0x50, 0x2a, 0xaa, 0xaa, 0xa8, 
	0x05, 0x55, 0x55, 0x40
};
// 'sensor_02_b_on', 32x9px
const unsigned char bitmap_sensor_02_b_on [] PROGMEM = {
	0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 
	0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 
	0x0f, 0xff, 0xff, 0xe0
};
// 'sensor_02_c_off', 32x10px
const unsigned char bitmap_sensor_02_c_off [] PROGMEM = {
	0x10, 0x00, 0x00, 0x04, 0x0a, 0xaa, 0xaa, 0xa8, 0x15, 0x55, 0x55, 0x54, 0x2a, 0xaa, 0xaa, 0xaa, 
	0x15, 0x55, 0x55, 0x54, 0x2a, 0xaa, 0xaa, 0xaa, 0x15, 0x55, 0x55, 0x54, 0x2a, 0xaa, 0xaa, 0xaa, 
	0x15, 0x55, 0x55, 0x54, 0x0a, 0xaa, 0xaa, 0xa8
};
// 'sensor_02_c_on', 32x10px
const unsigned char bitmap_sensor_02_c_on [] PROGMEM = {
	0x18, 0x00, 0x00, 0x0c, 0x1f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfe, 
	0x3f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfe, 
	0x3f, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf8
};
// 'sensor_02_d_off', 40x10px
const unsigned char bitmap_sensor_02_d_off [] PROGMEM = {
	0x02, 0x80, 0x00, 0x00, 0x28, 0x01, 0x55, 0x55, 0x55, 0x50, 0x02, 0xaa, 0xaa, 0xaa, 0xa8, 0x01, 
	0x55, 0x55, 0x55, 0x50, 0x02, 0xaa, 0xaa, 0xaa, 0xa8, 0x05, 0x55, 0x55, 0x55, 0x54, 0x02, 0xaa, 
	0xaa, 0xaa, 0xa8, 0x05, 0x55, 0x55, 0x55, 0x54, 0x02, 0xaa, 0xaa, 0xaa, 0xa8, 0x00, 0x55, 0x55, 
	0x55, 0x40
};
// 'sensor_02_d_on', 40x10px
const unsigned char bitmap_sensor_02_d_on [] PROGMEM = {
	0x03, 0x80, 0x00, 0x00, 0x38, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x03, 
	0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 
	0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 
	0xff, 0xe0
};
// 'sensor_03_a_off', 32x14px
const unsigned char bitmap_sensor_03_a_off [] PROGMEM = {
	0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2a, 0x80, 0x00, 0x01, 0x55, 0x40, 0x00, 0x0a, 0xaa, 0x80, 
	0x00, 0x55, 0x55, 0x40, 0x0a, 0xaa, 0xaa, 0xa0, 0x15, 0x55, 0x55, 0x50, 0x0a, 0xaa, 0xaa, 0xa0, 
	0x05, 0x55, 0x55, 0x00, 0x0a, 0xaa, 0xa8, 0x00, 0x05, 0x55, 0x50, 0x00, 0x0a, 0xaa, 0x80, 0x00, 
	0x05, 0x50, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00
};
// 'sensor_03_b_on', 32x16px
const unsigned char bitmap_sensor_03_b_on [] PROGMEM = {
	0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x3f, 0xf0, 
	0x00, 0x01, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xfc, 
	0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xfc, 0x00, 
	0x0f, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00
};
// 'sensor_03_a_on', 32x14px
const unsigned char bitmap_sensor_03_a_on [] PROGMEM = {
	0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x0f, 0xff, 0xc0, 
	0x00, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 
	0x0f, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0x80, 0x00, 
	0x0f, 0xf8, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00
};
// 'sensor_03_b_off', 32x16px
const unsigned char bitmap_sensor_03_b_off [] PROGMEM = {
	0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x2a, 0xa0, 
	0x00, 0x01, 0x55, 0x50, 0x00, 0x0a, 0xaa, 0xa8, 0x01, 0x55, 0x55, 0x50, 0x0a, 0xaa, 0xaa, 0xa8, 
	0x15, 0x55, 0x55, 0x50, 0x0a, 0xaa, 0xaa, 0xa0, 0x15, 0x55, 0x55, 0x00, 0x0a, 0xaa, 0xa8, 0x00, 
	0x05, 0x55, 0x40, 0x00, 0x0a, 0xaa, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00
};
// 'sensor_03_c_off', 32x17px
const unsigned char bitmap_sensor_03_c_off [] PROGMEM = {
	0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x0a, 0xa8, 
	0x00, 0x00, 0x55, 0x54, 0x00, 0x02, 0xaa, 0xa8, 0x00, 0x55, 0x55, 0x54, 0x02, 0xaa, 0xaa, 0xaa, 
	0x55, 0x55, 0x55, 0x54, 0x2a, 0xaa, 0xaa, 0xa8, 0x15, 0x55, 0x55, 0x40, 0x2a, 0xaa, 0xaa, 0x00, 
	0x15, 0x55, 0x50, 0x00, 0x2a, 0xaa, 0x80, 0x00, 0x15, 0x54, 0x00, 0x00, 0x2a, 0xa0, 0x00, 0x00, 
	0x14, 0x00, 0x00, 0x00
};
// 'sensor_03_d_on', 32x18px
const unsigned char bitmap_sensor_03_d_on [] PROGMEM = {
	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x07, 0xfc, 
	0x00, 0x00, 0x3f, 0xfe, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xfe, 
	0x1f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x80, 
	0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 
	0x7f, 0x80, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00
};
// 'sensor_03_d_off', 32x18px
const unsigned char bitmap_sensor_03_d_off [] PROGMEM = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x01, 0x54, 0x00, 0x00, 0x02, 0xa8, 
	0x00, 0x00, 0x15, 0x54, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x15, 0x55, 0x54, 0x00, 0xaa, 0xaa, 0xaa, 
	0x15, 0x55, 0x55, 0x54, 0xaa, 0xaa, 0xaa, 0xa8, 0x55, 0x55, 0x55, 0x40, 0xaa, 0xaa, 0xaa, 0x80, 
	0x55, 0x55, 0x54, 0x00, 0xaa, 0xaa, 0xa0, 0x00, 0x55, 0x55, 0x00, 0x00, 0x2a, 0xa8, 0x00, 0x00, 
	0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00
};
// 'sensor_03_c_on', 32x17px
const unsigned char bitmap_sensor_03_c_on [] PROGMEM = {
	0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 
	0x00, 0x00, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xfe, 
	0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0x00, 
	0x3f, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00, 
	0x3c, 0x00, 0x00, 0x00
};
// 'sound_on', 24x10px
const unsigned char bitmap_sound_on [] PROGMEM = {
	0x03, 0xc0, 0x0f, 0x02, 0x0c, 0x01, 0x02, 0x1c, 0x11, 0x02, 0x3c, 0x49, 0x00, 0x7d, 0x28, 0x00, 
	0x7d, 0x28, 0x02, 0x3c, 0x49, 0x02, 0x1c, 0x11, 0x02, 0x0c, 0x01, 0x03, 0xc0, 0x0f
};
// 'unit_cm', 24x10px
const unsigned char bitmap_unit_cm [] PROGMEM = {
	0xf0, 0x03, 0xc0, 0x80, 0x00, 0x40, 0xbe, 0xff, 0x40, 0xb6, 0xdb, 0x40, 0x30, 0xdb, 0x00, 0x30, 
	0xdb, 0x00, 0xb6, 0xdb, 0x40, 0xbe, 0xdb, 0x40, 0x80, 0x00, 0x40, 0xf0, 0x03, 0xc0
};

/*
  Fontname: gamer_digits
  Copyright: Created with Fony 1.4.7
  Capital A Height: 0, '1' Height: 6
  Calculated Max Values w= 5 h= 6 x= 1 y= 0 dx= 6 dy= 0 ascent= 0 len= 6
  Font Bounding box     w= 9 h= 5 x= 0 y=-6
  Calculated Min Values           x= 0 y=-6 dx= 0 dy= 0
  Pure Font   ascent = 6 descent= 0
  X Font      ascent = 6 descent= 0
  Max Font    ascent = 0 descent=-6
*/
const u8g_fntpgm_uint8_t gamer_digits[137] U8G_FONT_SECTION("gamer_digits") = {
  0,9,5,0,250,6,0,0,0,0,48,57,0,0,250,6,
  0,5,6,6,6,0,250,248,216,216,216,216,248,4,6,6,
  6,1,250,224,96,96,96,96,240,5,6,6,6,0,250,248,
  24,120,192,192,248,5,6,6,6,0,250,248,24,248,24,216,
  248,5,6,6,6,0,250,56,120,216,248,24,24,5,6,6,
  6,0,250,248,192,248,24,24,248,5,6,6,6,0,250,248,
  192,248,216,216,248,5,6,6,6,0,250,248,24,24,24,24,
  24,5,6,6,6,0,250,248,216,248,216,216,248,5,6,6,
  6,0,250,248,216,216,248,24,248};




// set the correct pins for the distance sensors, we can (probably) use any digital pins
#define sensor_01_ECHO_PIN 6
#define sensor_01_TRIG_PIN 7
#define sensor_02_ECHO_PIN 4
#define sensor_02_TRIG_PIN 5
#define sensor_03_ECHO_PIN 2
#define sensor_03_TRIG_PIN 3

// number of sensors - note that adding a new sensor is not as simple as changing the number, as the image drawing is hardcoded
#define NUMBER_OF_SENSORS 3

struct sensor_data { // structure for the sensor data
  int echo_pin; // ECHO pin for the ultrasonic distance sensor
	int trig_pin; // TRIG pin for the ultrasonic distance sensor
	int measured_distance_cm; // measured distance in CM
	int label_xpos; // x position of the distance label 
	int label_ypos; // y position of the distance label
	int label_width; // calculated width of the distance string
	int label_startpos_x; // start X position for the label
	int label_startpos_y; // start Y position for the label
	int label_endpos_x; // end X position for the label
	int label_endpos_y; // end Y position for the label
};

char buffer[10]; // helper C-style array of characters to store integers converted to strings

struct sensor_data sensor[NUMBER_OF_SENSORS]; // we have 3 sensors for now

int min_dist = 2;  // minimum distance to display in cm, this is also the minimum measurable distance for the used sensor
int max_dist = 100; // maximum distance to display in cm with the tile images, maximum measurable distance is 400cm = 4m

int dist_step_01; // distance for the first tile (there are 4 tiles for each sensor)
int dist_step_02; // distance for the 2nd tile
int dist_step_03; // distance for the 3rd tile
int dist_step_04; // distance for the 4th tile



void setup() {
  // calculate individual steps for the 4 tiles
	dist_step_01 = min_dist + round((max_dist - min_dist) / 4.0 * 1.0);
	dist_step_02 = min_dist + round((max_dist - min_dist) / 4.0 * 2.0);
	dist_step_03 = min_dist + round((max_dist - min_dist) / 4.0 * 3.0);
	dist_step_04 = min_dist + round((max_dist - min_dist) / 4.0 * 4.0);			

	// initialize pins for sensors
  sensor[0].echo_pin = sensor_01_ECHO_PIN;
  sensor[0].trig_pin = sensor_01_TRIG_PIN;	
  sensor[1].echo_pin = sensor_02_ECHO_PIN;
  sensor[1].trig_pin = sensor_02_TRIG_PIN;	
  sensor[2].echo_pin = sensor_03_ECHO_PIN;
  sensor[2].trig_pin = sensor_03_TRIG_PIN;	

  // set pins to outputs and inputs  - trigger is output, echo is input
  pinMode(sensor[0].trig_pin, OUTPUT);
  pinMode(sensor[0].echo_pin, INPUT);		
  pinMode(sensor[1].trig_pin, OUTPUT);
  pinMode(sensor[1].echo_pin, INPUT);		
  pinMode(sensor[2].trig_pin, OUTPUT);
  pinMode(sensor[2].echo_pin, INPUT);	

  // initialize label position data
  // those are manualy defined in the Photoshop/Photopea file, since it´s just easier to do it that way instead of guessing the numbers
	sensor[0].label_startpos_x = 41;		
	sensor[0].label_startpos_y = 20;	
	sensor[0].label_endpos_x = 30;		
	sensor[0].label_endpos_y = 58;		
	sensor[1].label_startpos_x = 63;		
	sensor[1].label_startpos_y = 23;	
	sensor[1].label_endpos_x = 63;		
	sensor[1].label_endpos_y = 60;			
	sensor[2].label_startpos_x = 85;		
	sensor[2].label_startpos_y = 20;	
	sensor[2].label_endpos_x = 97;		
	sensor[2].label_endpos_y = 57;		

  u8g.setFont(gamer_digits); // gamer digits font - manually generated, only includes digits
  u8g.setColorIndex(1); // white color

	Serial.begin(115200); // debug only
}

void loop() {

  for (int i=0; i<NUMBER_OF_SENSORS; i++) { // for each sensor
	  // MEASURE DISTANCES

		// trigger the trigger pin for at least 10 microseconds
		digitalWrite(sensor[i].trig_pin, HIGH);
		delayMicroseconds(10);
		digitalWrite(sensor[i].trig_pin, LOW);

		// Read the result:
		sensor[i].measured_distance_cm = pulseIn(sensor[i].echo_pin, HIGH); // pulseIn command will measure the time for the pulse on a defined pin
		sensor[i].measured_distance_cm = round(sensor[i].measured_distance_cm * 0.0343 / 2.0); // speed of sound = 343m/s, has to travel back and forth, that´s why we divide it by 2

		//Serial.print("Sensor ");
		//Serial.print(i);		
		//Serial.print("  ");				
		//Serial.println(sensor[i].measured_distance_cm);		

		// calculate string width			
		itoa(sensor[i].measured_distance_cm, buffer, 10); // convert integer to C-style string
		sensor[i].label_width = u8g.getStrWidth(buffer);

    // calculate label positions
		sensor[i].label_xpos = map(constrain(sensor[i].measured_distance_cm, min_dist, max_dist), min_dist, max_dist, sensor[i].label_startpos_x, sensor[i].label_endpos_x);
		sensor[i].label_ypos = map(constrain(sensor[i].measured_distance_cm, min_dist, max_dist), min_dist, max_dist, sensor[i].label_startpos_y, sensor[i].label_endpos_y);		
	}

	//delay(500);

  u8g.firstPage();
  do {
    u8g.drawBitmapP( 36, 0, 56/8, 15, bitmap_car_image); // car image on top of the display
    u8g.drawBitmapP( 104, 0, 24/8, 10, bitmap_sound_on); // sound on indicator - not doing anything for now
    u8g.drawBitmapP( 0, 0, 24/8, 10, bitmap_unit_cm);    // cm unit indicator - not doing anything for now    

    // individual pieces of the distance measurement in the 3*4 grid
    u8g.drawBitmapP( 24, 17, 32/8, 14, sensor[0].measured_distance_cm > dist_step_01 ? bitmap_sensor_01_a_on : bitmap_sensor_01_a_off);        
    u8g.drawBitmapP( 21, 25, 32/8, 16, sensor[0].measured_distance_cm > dist_step_02 ? bitmap_sensor_01_b_on : bitmap_sensor_01_b_off);        
    u8g.drawBitmapP( 18, 34, 32/8, 17, sensor[0].measured_distance_cm > dist_step_03 ? bitmap_sensor_01_c_on : bitmap_sensor_01_c_off);        
    u8g.drawBitmapP( 16, 43, 32/8, 18, sensor[0].measured_distance_cm > dist_step_04 ? bitmap_sensor_01_d_on : bitmap_sensor_01_d_off);                    

    u8g.drawBitmapP( 48, 23, 32/8,  9, sensor[1].measured_distance_cm > dist_step_01 ? bitmap_sensor_02_a_on : bitmap_sensor_02_a_off);        
    u8g.drawBitmapP( 48, 33, 32/8,  9, sensor[1].measured_distance_cm > dist_step_02 ? bitmap_sensor_02_b_on : bitmap_sensor_02_b_off);        
    u8g.drawBitmapP( 47, 42, 32/8, 10, sensor[1].measured_distance_cm > dist_step_03 ? bitmap_sensor_02_c_on : bitmap_sensor_02_c_off);        
    u8g.drawBitmapP( 42, 52, 40/8, 10, sensor[1].measured_distance_cm > dist_step_04 ? bitmap_sensor_02_d_on : bitmap_sensor_02_d_off);                        

    u8g.drawBitmapP( 72, 17, 32/8, 14, sensor[2].measured_distance_cm > dist_step_01 ? bitmap_sensor_03_a_on : bitmap_sensor_03_a_off);        
    u8g.drawBitmapP( 74, 25, 32/8, 16, sensor[2].measured_distance_cm > dist_step_02 ? bitmap_sensor_03_b_on : bitmap_sensor_03_b_off);        
    u8g.drawBitmapP( 77, 34, 32/8, 17, sensor[2].measured_distance_cm > dist_step_03 ? bitmap_sensor_03_c_on : bitmap_sensor_03_c_off);        
    u8g.drawBitmapP( 80, 43, 32/8, 18, sensor[2].measured_distance_cm > dist_step_04 ? bitmap_sensor_03_d_on : bitmap_sensor_03_d_off);                            

		for (int i=0; i<NUMBER_OF_SENSORS; i++) { // for all the sensors
		    u8g.setColorIndex(0); // black color

				// draw box below the label
				u8g.drawBox((sensor[i].label_xpos - sensor[i].label_width / 2) - 1 ,sensor[i].label_ypos - 4,sensor[i].label_width + 2, 8);

				itoa(sensor[i].measured_distance_cm, buffer, 10); // convert integer to C-style string
				u8g.setColorIndex(1); // white color

				// draw the distance label
				u8g.drawStr(sensor[i].label_xpos - sensor[i].label_width / 2, sensor[i].label_ypos - 3, buffer); // draw the label
		}


  } while ( u8g.nextPage() );

}