#include #include #include #include "Arduino.h" #include "U8g2lib.h" #include "logos.h" #include "utils.h" #include "vars.h" #include "oled.h" #include "readers.h" OLED::OLED(U8G2 u8g2) { this->u8g2 = std::move(u8g2); } void OLED::begin() { u8g2.begin(); // default value is 0x80, clock divide ratio (0x00=1) and oscillator frequency (0x8) u8g2.sendF("ca", 0xd5, 0xF0); // set the clock divider to something faster (so we get a better framerate) u8g2.setFont(u8g2_font_bpixel_te); u8g2_uint_t maxLength = 127 - u8g2.getUTF8Width("00:00:00 "); if (u8g2.getUTF8Width(AFRAPAY_GIT_BRANCH "-" AFRAPAY_GIT_COMMIT) < maxLength) { revision = AFRAPAY_GIT_BRANCH "-" AFRAPAY_GIT_COMMIT; } else if (u8g2.getUTF8Width(AFRAPAY_GIT_BRANCH) < maxLength) { revision = AFRAPAY_GIT_BRANCH; } else if (u8g2.getUTF8Width(AFRAPAY_GIT_COMMIT) < maxLength) { revision = AFRAPAY_GIT_COMMIT; } drawLogo(LOGO_MATECARD); u8g2.sendBuffer(); } void OLED::drawCurvedLineV(int xStart, int yStart, int vert, int horiz) { u8g2.drawVLine(xStart, yStart + 1, vert); u8g2.drawVLine(xStart + 1, yStart, vert); u8g2.drawHLine(xStart, yStart + vert, horiz); u8g2.drawHLine(xStart + 1, yStart + vert + 1, horiz); } void OLED::drawCurvedLine(int xStart, int yStart, int horiz, int vert) { u8g2.drawHLine(xStart, yStart, horiz); u8g2.drawHLine(xStart, yStart + 1, horiz); u8g2.drawVLine(xStart + horiz, yStart, vert); u8g2.drawVLine(xStart + horiz + 1, yStart + 1, vert); } void OLED::drawLogoAfraPay() { u8g2.setFontMode(1); u8g2.setFontDirection(0); int xOffset = 12; int yOffset = 23; u8g2.setFont(u8g2_font_maniac_tr); u8g2.drawStr(xOffset, yOffset, "AfRA"); u8g2.setFont(u8g2_font_tenthinguys_tr); u8g2.drawStr(xOffset + 73, yOffset + 3, "pay"); // uncomment to verify distance to screen gap is equal on both sides //u8g2.drawHLine(0, yOffset-12, xOffset); //u8g2.drawHLine(127-xOffset-1, yOffset, xOffset); drawCurvedLineV(xOffset + 69, yOffset, 7, 32); drawCurvedLine(xOffset + 73, yOffset - 8, 28, 15); u8g2.drawPixel(xOffset + 101, yOffset + 7); } void OLED::drawLogoBitmap(int width, int height, unsigned char bits[], int yOffset) { int offset = (128 - width) / 2; u8g2.drawXBM(offset, yOffset, width, height, bits); } void OLED::drawLogo(e_logo logo) { switch (logo) { case LOGO_AFRAPAY: drawLogoAfraPay(); break; case LOGO_CONTACTLESS: drawLogoBitmap( contactless_width, contactless_height, contactless_bits); break; case LOGO_FELICA: drawLogoBitmap( felica_width, felica_height, felica_bits); break; case LOGO_MATECARD: drawLogoBitmap(matecard_width, matecard_height, matecard_bits, 5); u8g2.setFont(u8g2_font_bpixeldouble_tr); u8g2.drawStr((126 - u8g2.getStrWidth("matecard")) / 2, 57, "matecard"); break; case LOGO_PENDING: drawLogoBitmap(pending_width, pending_height, pending_bits, 5); break; case LOGO_SUCCESS: drawLogoBitmap(success_width, success_height, success_bits, 5); break; case LOGO_FAILURE: drawLogoBitmap(failure_width, failure_height, failure_bits, 5); break; } } void OLED::drawStatusText(const String& status, const String& statusRightAligned, bool japan) { if (japan) u8g2.setFont(u8g2_font_b12_t_japanese2); else u8g2.setFont(u8g2_font_bpixel_te); u8g2.drawUTF8(0, 61, status.c_str()); if (!statusRightAligned.isEmpty()) { if (japan) u8g2.setFont(u8g2_font_bpixel_te); int textWidth = u8g2.getUTF8Width(statusRightAligned.c_str()); u8g2.drawUTF8(126 - textWidth, 61, statusRightAligned.c_str()); } } void OLED::drawFullScreenText(const String& textTop, const String& textBottom) { u8g2.setFont(u8g2_font_chargen_92_tr); u8g2.drawUTF8((127-u8g2.getUTF8Width(textTop.c_str()))/2, 13, textTop.c_str()); u8g2.setFont(u8g2_font_maniac_te); u8g2.drawUTF8((127-u8g2.getUTF8Width(textBottom.c_str()))/2, 45, textBottom.c_str()); } void OLED::updateOLED(e_state state, const String& statusText, const String& statusTextRightAligned, bool japan) { u8g2.clearBuffer(); switch (state) { case STATE_IDLE: drawLogo(LOGO_AFRAPAY); break; case STATE_TRANSACT_CARDSCAN: case STATE_BALANCE_CARDSCAN: case STATE_LINK_CARD_SCAN: case STATE_LINK_CARD_RESCAN: if (PN532Reader::mode == PN532_MIFARE_ISO14443A) drawLogo(LOGO_CONTACTLESS); else drawLogo(LOGO_FELICA); break; case STATE_RESULT_SUCCESS: drawLogo(LOGO_SUCCESS); break; case STATE_RESULT_FAILURE: drawLogo(LOGO_FAILURE); break; case STATE_RESULT_DISPLAY: if (japan) { String balance = splitString(statusText, ':', 1); balance.replace(",", ""); if (balance.startsWith("-")) { balance.replace("-00", "-"); balance.replace("-0", "-"); balance.replace("-", "-¥"); } else { if (balance.startsWith("00")) balance = balance.substring(2); else if (balance.startsWith("0")) balance = balance.substring(1); balance = "¥" + balance; } drawFullScreenText(splitString(statusText, ':', 0), balance); } else drawFullScreenText(splitString(statusText, ':', 0), splitString(statusText, ':', 1) + "€"); drawStatusText(splitString(statusText, ':', 2), statusTextRightAligned); u8g2.sendBuffer(); return; case STATE_TRANSACT_VERIFY: case STATE_BALANCE_VERIFY: case STATE_LINK_VERIFY: drawLogo(LOGO_PENDING); break; } drawStatusText(statusText, statusTextRightAligned, japan); u8g2.sendBuffer(); } void OLED::updateOLED(e_state state) { String time = DateTime.format(DateFormatter::TIME_ONLY); if (!digitalRead(PIN_INTERRUPT_CANCEL) || millis()%20000 < 10000) { updateOLED(state, time, revision); } else { updateOLED(state, time, WiFi.localIP().toString()); } }