Stairs/module/src/display.cpp

198 lines
4.7 KiB
C++

/*
* Stairs lighting
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include "display.h"
#include <Fonts/FreeSans12pt7b.h>
#include "global.h"
#include "icons.h"
#define WaitAnimationInterval 150
void Display::init()
{
mDisplay = new Adafruit_SSD1306(128, 32, &Wire, -1);
mDisplay->begin(SSD1306_SWITCHCAPVCC, 0x3C);
}
void Display::show(Screen screen)
{
switch (screen)
{
case Screen::Blank:
off();
break;
case Screen::WaitingForComm:
drawWaitingForComm();
break;
case Screen::ModuleIndex:
drawModuleIndex();
break;
}
}
void Display::drawWaitingForComm()
{
uint32_t currentTime = millis();
if (mLastScreen == Screen::WaitingForComm && currentTime - mLastWaiting < WaitAnimationInterval)
return;
checkOn();
mDisplay->clearDisplay();
drawTitle("Waiting for signal");
uint8_t xOffset = (mWaitAnimationStep == 1 || mWaitAnimationStep == 2) ? WaitCursorSegmentWidth : 0;
uint8_t yOffset = (mWaitAnimationStep == 2 || mWaitAnimationStep == 3) ? WaitCursorSegmentHeight : 0;
drawRotatedBitmap(xOffset, mDisplay->height() - (WaitCursorSegmentHeight * 2) + yOffset, WaitCursorSegment, WaitCursorSegmentWidth, WaitCursorSegmentHeight, mWaitAnimationStep);
mDisplay->display();
mWaitAnimationStep++;
if (mWaitAnimationStep > 3)
mWaitAnimationStep = 0;
mLastScreen = Screen::WaitingForComm;
mLastWaiting = currentTime;
}
void Display::drawModuleIndex()
{
uint8_t moduleIndex = settings.getModuleIndex();
if (mLastScreen == Screen::ModuleIndex && mLastModuleIndex == moduleIndex)
return;
checkOn();
mDisplay->clearDisplay();
drawTitle("Steps");
drawCommIcon();
mDisplay->setFont(&FreeSans12pt7b);
mDisplay->setCursor(0, mDisplay->height());
// ToDo show numbers based on module index
uint8_t firstStep = (moduleIndex * 2) + 1;
mDisplay->print(firstStep);
mDisplay->print(" - ");
mDisplay->print(firstStep + 1);
mDisplay->display();
mLastScreen = Screen::ModuleIndex;
mLastModuleIndex = moduleIndex;
}
void Display::off()
{
if (mLastScreen != Screen::Blank)
{
mDisplay->ssd1306_command(SSD1306_DISPLAYOFF);
mLastScreen = Screen::Blank;
}
}
void Display::checkOn()
{
if (mLastScreen == Screen::Blank)
mDisplay->ssd1306_command(SSD1306_DISPLAYON);
}
void Display::drawTitle(const char* title)
{
mDisplay->setTextSize(1);
mDisplay->setTextColor(WHITE);
mDisplay->setFont(NULL);
mDisplay->setCursor(0, 0);
mDisplay->print(title);
}
void Display::drawCommIcon()
{
// ToDo show actual state depending on last received message (should never be more than half a second ago)
mDisplay->drawBitmap(mDisplay->width() - IconCommWidth, 0, IconCommOff, IconCommWidth, IconCommHeight, 1);
}
typedef void (*WritePixelProc)(Adafruit_SSD1306* display, int8_t boundsX, int8_t boundsY, int8_t boundsW, int8_t boundsH, int8_t relativeX, int8_t relativeY);
void writePixel0(Adafruit_SSD1306* display, int8_t boundsX, int8_t boundsY, int8_t boundsW, int8_t boundsH, int8_t relativeX, int8_t relativeY)
{
display->writePixel(boundsX + relativeX, boundsY + relativeY, 1);
}
void writePixel90(Adafruit_SSD1306* display, int8_t boundsX, int8_t boundsY, int8_t boundsW, int8_t boundsH, int8_t relativeX, int8_t relativeY)
{
display->writePixel(boundsX + boundsW - relativeY, boundsY + relativeX, 1);
}
void writePixel180(Adafruit_SSD1306* display, int8_t boundsX, int8_t boundsY, int8_t boundsW, int8_t boundsH, int8_t relativeX, int8_t relativeY)
{
display->writePixel(boundsX + boundsW - relativeX, boundsY + boundsH - relativeY, 1);
}
void writePixel270(Adafruit_SSD1306* display, int8_t boundsX, int8_t boundsY, int8_t boundsW, int8_t boundsH, int8_t relativeX, int8_t relativeY)
{
display->writePixel(boundsX + relativeY, boundsY + boundsH - relativeX, 1);
}
void Display::drawRotatedBitmap(int8_t x, int8_t y, const uint8_t bitmap[], int8_t w, int8_t h, uint8_t rotation)
{
int16_t byteWidth = (w + 7) / 8;
int8_t byte = 0;
mDisplay->startWrite();
WritePixelProc writePixel;
switch (rotation)
{
case 1: // 90 degrees
writePixel = writePixel90;
break;
case 2: // 180 degrees
writePixel = writePixel180;
break;
case 3: // 270 degrees
writePixel = writePixel270;
break;
default: // 0 degrees
writePixel = writePixel0;
break;
}
for(int8_t relativeY = 0; relativeY < h; relativeY++)
{
for(int8_t relativeX = 0; relativeX < w; relativeX++)
{
if(relativeX & 7)
byte <<= 1;
else
byte = pgm_read_byte(&bitmap[relativeY * byteWidth + relativeX / 8]);
if (byte & 0x80)
writePixel(mDisplay, x, y, w, h, relativeX, relativeY);
}
}
mDisplay->endWrite();
}