#include <math.h>
#include <Wire.h> // Required for I2C communication (MADE BY AI)
#include <IRLremote.h>
#define WOKWI_SIM true
#define IR_PIN 2
#define SSD1306_I2C_ADDRESS 0x3C
//liste de charactère (pour indexé la bonne lettre/char dans "font")
const char* fontChar = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ1234567890+-.,!";
const char* numAlf = "abcdefghijklmnopqrstuvwxyz";
//uint8_t pour sauvée de la place
const uint8_t font[] = {
B00000000, B00011101, B00101001, B00111101, B11010001, B11111100, B01100011, B00011000, B01000011, B10010010, B10010011, B00111101, B00011111, B01000110, B00111110, B00000000, B00011101, B00001000, B00111001, B11010001, B10000100, B00100010, B11100000, B10000101, B11110001, B10001011, B11111101, B00011000, B11000110, B00111110, B00000011, B10100011, B11101000, B00111011, B11110000, B11100100, B00100001, B11110001, B00010001, B11000100, B00100001, B00111111, B00001110, B01000010, B00010000, B00000011, B10100010, B11110000, B10111001, B11010000, B10000100, B11100010, B11111000, B01000011, B11010001, B10001100, B01100011, B00011111, B11000110, B00110001, B00000001, B00000000, B01000010, B00010001, B11000100, B00100001, B00001000, B11100010, B00000000, B10000100, B00100010, B00111110, B00100001, B00001010, B01001100, B10000100, B00101001, B10001010, B01001010, B00110010, B11000101, B00100101, B00010010, B00010000, B10000100, B00100000, B10100001, B00001000, B01000010, B00011111, B00000000, B00010101, B01011010, B11000111, B01110101, B10101101, B01101011, B01010000, B00000011, B11010001, B10001100, B01100011, B10011010, B11010110, B01110001, B00000000, B00011101, B00011000, B10111001, B11010001, B10001100, B01100010, B11100000, B01111010, B00111110, B10000100, B00111101, B00011000, B11111010, B00010000, B00000011, B11100010, B11110000, B10000101, B11010001, B10001100, B01100110, B11110000, B00000001, B00001110, B01000010, B00111101, B00011111, B01000110, B00110001, B00000001, B10010000, B01000001, B00110001, B11010000, B01100000, B11100010, B11100010, B00111000, B10000100, B00100001, B00111110, B01000010, B00010000, B10000100, B00000000, B00100011, B00011000, B10111110, B00110001, B10001100, B01100010, B11100000, B00000010, B00110001, B01010001, B00100011, B00011000, B10101001, B01000100, B00000000, B00101011, B01011010, B10101010, B10110101, B10101101, B01101010, B10100000, B01000110, B00101110, B10001100, B01100011, B00010111, B01000110, B00110001, B00000100, B01100010, B11110000, B10111010, B00110001, B01110001, B00001000, B01000000, B00000011, B11100010, B01000111, B11111110, B00100010, B00100010, B00011111, B00100011, B00001000, B01000010, B00111001, B11010001, B00010001, B00010001, B11110111, B01000100, B11000001, B10001011, B10100101, B00101111, B10001000, B01000010, B11111100, B00111100, B00011000, B10111001, B11110000, B11110100, B01100010, B11101111, B10000100, B01000100, B01000010, B00011101, B00010111, B01000110, B00101110, B01110100, B01011110, B00010000, B10000101, B11010001, B10101101, B01100010, B11100000, B00010000, B10011111, B00100001, B00000000, B00000000, B01111100, B00000000, B00000000, B00000000, B00000000, B00010000, B00000000, B00000000, B00001000, B01000000
};
//variable qui garde la valeur des pixel sur l'écran
uint8_t screen[128 * 8];
/* exemple de comment screen est disposé :
| col1 | col2 | col3 |...
-----|------|------|------|...
page1| 0 | 1 | 0 |...
| 1 | 0 | 1 |...
| 0 | 1 | 0 |...
x8
-----|------|------|------|...
page2| 0 | 1 | 0 |...
etc...
*/
CNec remote; //télé-commande
void setup()
{
//initiallisé le serial monitor
Serial.begin(9600);
Serial.println("starting...");
initializeDisplay();//initiallisé l'écran
//on commence le ir reciver
if (!remote.begin(IR_PIN))
{
Serial.println("ERROR, failed to start IR reciever");
}
//clear le display
setScreen(0);
displayMessage("SAY MY NAME", 0, 0, 1);
display();
}
void loop()
{
if (remote.available())
{
auto data = remote.read();
setScreen(0);
displayMessage(translate(data.command), 0, 0, 2);
display();
}
}
/*
* =====================================
* FONCTION :
* =====================================
*/
const char* translate(uint8_t data)
{
if(WOKWI_SIM)
{
switch (data)
{
case 162:
return "power";
case 226:
return "menu";
case 34:
return "test";
case 2:
return "+";
case 194:
return "back";
case 224:
return "previous";
case 168:
return "play";
case 144:
return "forward";
case 104:
return "0";
case 152:
return "-";
case 176:
return "c";
case 48:
return "1";
case 24:
return "2";
case 122:
return "3";
case 16:
return "4";
case 56:
return "5";
case 90:
return "6";
case 66:
return "7";
case 74:
return "8";
case 82:
return "9";
default:
return "unkown";
}
}else
{
switch(data)
{
case 98:
return "power";
case 2:
return "vol+";
case 194:
return "func/stop";
case 194:
return ""
}
}
}
void println()
{
Serial.println();
}
//fonction pour print
template<typename T>
void println(T input)
{
Serial.println(input);
}
template<typename T, typename... Args>
void println(T input, Args... other)
{
Serial.print(input);
println(other...);
}
template<typename T>
void println2(T input)
{
Serial.println(input);
}
template<typename T, typename... Args>
void println2(T input, Args... other)
{
Serial.print(input);
Serial.print(", ");
println2(other...);
}
template <typename T>
void printarr(int size, T array)
{
for (int i = 0; i < size; i++)
{
println("[", i, "] = ", array[i]);
}
println();
}
void sendCommand(uint8_t command)
{
Wire.beginTransmission(SSD1306_I2C_ADDRESS); /*AI*/
Wire.write(0x80); // Control byte: 0x80 for a single command /*AI*/
Wire.write(command); /*AI*/
Wire.endTransmission(); /*AI*/
}
void sendData(uint8_t data)
{
Wire.beginTransmission(SSD1306_I2C_ADDRESS); /*AI*/
Wire.write(0x40); // Control byte: 0x40 for a single data byte /*AI*/
Wire.write(data); /*AI*/
Wire.endTransmission(); /*AI*/
}
void initializeDisplay()
{
Wire.begin();
sendCommand(0xAE); // Display OFF
sendCommand(0xD5); // Set Display Clock Divide Ratio
sendCommand(0x80);
sendCommand(0xA8); // Set Multiplex Ratio
sendCommand(0x3F);
sendCommand(0xD3); // Set Display Offset
sendCommand(0x00);
sendCommand(0x40); // Set Display Start Line
sendCommand(0x8D); // Set Charge Pump
sendCommand(0x14); // Enable Charge Pump
sendCommand(0xA1); // Flip horizontal (was 0xA0)
sendCommand(0xC8); // Flip vertical (was 0xC0)
// Horizontal Addressing Mode for Wokwi
sendCommand(0x20);
sendCommand(0x00);
sendCommand(0x21);
sendCommand(0x00);
sendCommand(0x7F);
sendCommand(0x22);
sendCommand(0x00);
sendCommand(0x07);
sendCommand(0xDA); // Set COM Pins (fixed from 0x02!)
sendCommand(0x12);
sendCommand(0x81); // Set Contrast
sendCommand(0xCF);
sendCommand(0xD9); // Set Pre-charge Period
sendCommand(0xF1);
sendCommand(0xDB); // Set VCOMH
sendCommand(0x40);
sendCommand(0xA4); // Resume to RAM content
sendCommand(0xA6); // Normal Display
sendCommand(0x2E); // Deactivate Scroll
sendCommand(0xAF); // Display ON
}
//j'ai été aidé par ai, toute avant /*AI*/ c'est par l'ia le reste c'est moi.
//dans le fon, ça envoie des commande à l'écran.
void display()
{
// Horizontal addressing mode (for Wokwi)
sendCommand(0x21); // Column address
sendCommand(0x00); // Start column 0
sendCommand(0x7F); // End column 127
sendCommand(0x22); // Page address
sendCommand(0x00); // Start page 0
sendCommand(0x07); // End page 7
for (int i = 0; i < 128 * 8; i += 16) {
Wire.beginTransmission(SSD1306_I2C_ADDRESS);
Wire.write(0x40);
for (int j = 0; j < 16 && (i + j) < 1024; j++) {
Wire.write(screen[i + j]);
}
Wire.endTransmission();
}
}
void setPixel(int x, int y, bool v)
{
int page = y / 8;
if (x >= 0 && x < 128 && y >= 0 && y < 64) //si il est pas en dehors de l'écran
{
if (v) //si v est true (donc ont veut activé le pixel)
{
screen[page * 128 + x] = screen[page * 128 + x] | (1 << (y % 8)); //ont set le pixel spécific sans affecté les autre
} else
{
screen[page * 128 + x] = screen[page * 128 + x] & ~(1 << (y % 8));
}
}
}
void setScreen(bool v)
{
for (int page = 0; page < 8; page++)
{
for (int col = 0; col < 128; col++)
{
if (v)
{
screen[page * 128 + col] = B11111111;
} else
{
screen[page * 128 + col] = B00000000;
}
}
}
}
void fillRect(int x, int y, int sx, int sy, bool v)
{
for (int w = 0; w < sx; w++)
{
for (int h = 0; h < sy; h++)
{
setPixel(x + w, y + h, v);
}
}
}
//trouve le bit qui est à l'index spécifié
bool fontUnpacker(int i)
{
int index = i / 8;
bool output = (font[index] & (1 << 7 - (i % 8))) != 0;
return output;
}
//sa sépare le const char* (c-style string) en lettre et ça l'envoie a display letter pour faire apparaitre la lettre
void displayMessage(const char* s, int x, int y, int si)
{
for (int i = 0; i < strlen(s); i++)
{
char sChar = s[i];
displayLetter(sChar, x + i * 6 * si, y, si);
}
}
//sa trouve le symbole corespondant au c et ça le display
void displayLetter(char c, int x, int y, int si)
{
int charIndex = -1;
for (int i = 0; i < strlen(fontChar); i++)
{
if (fontChar[i] == c)
{
charIndex = i;
break;
}
}
//si ont a pas trouvé le charactère (c)
if (charIndex == -1)
{
println("error, couldn't find the character : '", c, "'");
return;
}
//iChar c'est l'index de la lettre. (A,B,C, etc...)
for (int iChar = charIndex; iChar < 1 + charIndex; iChar ++) //ont rajoute charIndex pour modifier où ont itère (trust sa marche)
{
//itération de la position y de la lettre
for (int posY = 0; posY < 6 * si; posY += si) //ont ajoute la position pour déplacé la lettre
{
//itération de la position x de la lettre
for (int posX = 0; posX < 5 * si; posX += si)
{
//ont vas déterminé l'index qu'il faut pour déterminé l'index dans la variables font
int trueIndex = iChar * 5 * 6 + posY / si * 5 + posX / si;
if (fontUnpacker(trueIndex))
{
fillRect(posX + x, posY + y, si, si, 1);
}
}
}
}
}
//ça test la font (pour voir si elle vas fonctionné sur le display)
void testFont()
{
int fontSize = (sizeof(font) / sizeof(font[0]));
for (int i = 0; i < fontSize * 8; i++)
{
Serial.print(fontUnpacker(i));
if (i % 5 == 4)
{
Serial.println();
}
}
}