mirror of
https://github.com/usetrmnl/bb_epaper.git
synced 2026-04-29 13:43:26 -07:00
462 lines
11 KiB
C++
462 lines
11 KiB
C++
//
|
|
// bb_eink
|
|
// Copyright (c) 2024 BitBank Software, Inc.
|
|
// Written by Larry Bank (bitbank@pobox.com)
|
|
// Project started 9/11/2024
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#ifdef _LINUX_
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
// convert wire library constants into ArmbianIO values
|
|
#define OUTPUT GPIO_OUT
|
|
#define INPUT GPIO_IN
|
|
#define INPUT_PULLUP GPIO_IN_PULLUP
|
|
#define HIGH 1
|
|
#define LOW 0
|
|
void delay(int);
|
|
#else // Arduino
|
|
|
|
#endif // _LINUX_
|
|
|
|
#include "bb_eink.h"
|
|
#include "arduino_io.inl" // I/O (non-portable) code is in here
|
|
#include "bb_ei.inl" // All of the display interface code is in here
|
|
#include "bb_ei_gfx.inl" // drawing code
|
|
#include "Group5.h" // Group5 data compression library
|
|
#include "bb_font.h" // bitbank compressed font info
|
|
#ifdef __cplusplus
|
|
//
|
|
// C++ Class implementation
|
|
//
|
|
//uint32_t BBEINK::getRefreshTime(void)
|
|
//{
|
|
// return _bbei.iTimeout;
|
|
//}
|
|
|
|
void BBEINK::setPosition(int x, int y, int w, int h)
|
|
{
|
|
bbeiSetPosition(&_bbei, x, y, w, h);
|
|
}
|
|
int BBEINK::setPanelType(int iPanel)
|
|
{
|
|
return bbeiSetPanelType(&_bbei, iPanel);
|
|
}
|
|
void BBEINK::initIO(int iDC, int iReset, int iBusy, int iCS, int iMOSI, int iSCLK, uint32_t u32Speed)
|
|
{
|
|
_bbei.iCSPin = iCS;
|
|
_bbei.iMOSIPin = iMOSI;
|
|
_bbei.iCLKPin = iSCLK;
|
|
_bbei.iDCPin = iDC;
|
|
_bbei.iRSTPin = iReset;
|
|
_bbei.iBUSYPin = iBusy;
|
|
bbeiInitIO(&_bbei, u32Speed);
|
|
bbeiWakeUp(&_bbei);
|
|
bbeiSendCMDSequence(&_bbei, _bbei.pInitFull);
|
|
} /* initIO() */
|
|
|
|
int BBEINK::writePlane(int iPlane)
|
|
{
|
|
return bbeiWritePlane(&_bbei, iPlane);
|
|
} /* writePlane() */
|
|
|
|
int BBEINK::refresh(int iMode, bool bWait)
|
|
{
|
|
int rc;
|
|
rc = bbeiRefresh(&_bbei, iMode);
|
|
if (rc == BBEI_SUCCESS && bWait) {
|
|
bbeiWaitBusy(&_bbei);
|
|
}
|
|
return rc;
|
|
} /* refresh() */
|
|
|
|
//int BBEINK::getFlags(void)
|
|
//{
|
|
// return _bbei.iFlags;
|
|
//}
|
|
|
|
//void BBEINK::setFlags(int iFlags)
|
|
//{
|
|
// _bbei.iFlags = iFlags;
|
|
//}
|
|
|
|
void BBEINK::setBuffer(uint8_t *pBuffer)
|
|
{
|
|
_bbei.ucScreen = pBuffer;
|
|
}
|
|
|
|
int BBEINK::allocBuffer(void)
|
|
{
|
|
int iSize = ((_bbei.native_width+7)>>3) * _bbei.native_height;
|
|
if (_bbei.iFlags & (BBEI_3COLOR | BBEI_4COLOR) || _bbei.chip_type == BBEI_CHIP_UC81xx)
|
|
iSize *= 2; // 2 bit planes
|
|
_bbei.ucScreen = (uint8_t *)malloc(iSize);
|
|
if (_bbei.ucScreen != NULL) {
|
|
return BBEI_SUCCESS;
|
|
}
|
|
return BBEI_ERROR_NO_MEMORY; // failed
|
|
} /* allocBuffer() */
|
|
|
|
void * BBEINK::getBuffer(void)
|
|
{
|
|
return (void *)_bbei.ucScreen;
|
|
} /* getBuffer() */
|
|
|
|
void BBEINK::freeBuffer(void)
|
|
{
|
|
if (_bbei.ucScreen) {
|
|
free(_bbei.ucScreen);
|
|
_bbei.ucScreen = NULL;
|
|
}
|
|
} /* freeBuffer() */
|
|
|
|
uint32_t BBEINK::capabilities(void)
|
|
{
|
|
return _bbei.iFlags;
|
|
}
|
|
|
|
void BBEINK::setRotation(int iRotation)
|
|
{
|
|
// obdSetRotation(&_bbei, iRotation);
|
|
} /* setRotation() */
|
|
|
|
int BBEINK::getRotation(void)
|
|
{
|
|
return _bbei.iOrientation;
|
|
}
|
|
|
|
void BBEINK::fillScreen(int iColor, int iPlane)
|
|
{
|
|
bbeiFill(&_bbei, iColor, iPlane);
|
|
} /* fillScreen() */
|
|
|
|
void BBEINK::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
|
|
{
|
|
bbeiRectangle(&_bbei, x, y, x+w-1, y+h-1, color, 0);
|
|
} /* drawRect() */
|
|
|
|
void BBEINK::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
|
|
{
|
|
bbeiRectangle(&_bbei, x, y, x+w-1, y+h-1, color, 1);
|
|
} /* fillRect() */
|
|
|
|
void BBEINK::setTextWrap(bool bWrap)
|
|
{
|
|
_bbei.wrap = (int)bWrap;
|
|
}
|
|
|
|
void BBEINK::setTextColor(int iFG, int iBG)
|
|
{
|
|
if (iFG > BBEI_RED) iFG = BBEI_BLACK;
|
|
if (iBG > BBEI_RED) iBG = BBEI_BLACK;
|
|
if ((_bbei.iFlags & (BBEI_3COLOR | BBEI_4COLOR)) == 0) {
|
|
if (iFG == BBEI_RED) iFG = BBEI_BLACK; // can't set red color
|
|
if (iBG == BBEI_RED) iBG = BBEI_BLACK;
|
|
}
|
|
_bbei.iFG = iFG;
|
|
_bbei.iBG = (iBG == -1) ? iFG : iBG;
|
|
} /* setTextColor() */
|
|
|
|
void BBEINK::setCursor(int x, int y)
|
|
{
|
|
if (x >= 0)
|
|
_bbei.iCursorX = x;
|
|
if (y >= 0)
|
|
_bbei.iCursorY = y;
|
|
} /* setCursor() */
|
|
|
|
int BBEINK::loadBMP(const uint8_t *pBMP, int x, int y, int iFG, int iBG)
|
|
{
|
|
return bbeiLoadBMP(&_bbei, pBMP, x, y, iFG, iBG);
|
|
} /* loadBMP() */
|
|
|
|
int BBEINK::loadBMP3(const uint8_t *pBMP, int x, int y)
|
|
{
|
|
return bbeiLoadBMP3(&_bbei, pBMP, x, y);
|
|
} /* loadBMP3() */
|
|
|
|
void BBEINK::setFont(int iFont)
|
|
{
|
|
_bbei.iFont = iFont;
|
|
_bbei.pFont = NULL;
|
|
} /* setFont() */
|
|
|
|
void BBEINK::setFont(const void *pFont)
|
|
{
|
|
_bbei.iFont = -1;
|
|
_bbei.pFont = (void *)pFont;
|
|
} /* setFont() */
|
|
|
|
//void BBEINK::setFreeFont(const GFXfont *pFont)
|
|
//{
|
|
// _bbei.pFreeFont = (GFXfont *)pFont;
|
|
//} /* setFreeFont() */
|
|
|
|
void BBEINK::drawLine(int x1, int y1, int x2, int y2, int iColor)
|
|
{
|
|
bbeiDrawLine(&_bbei, x1, y1, x2, y2, iColor);
|
|
} /* drawLine() */
|
|
|
|
#ifdef _LINUX_
|
|
void BBEINK::print(const string &str)
|
|
{
|
|
print(str.c_str());
|
|
} /* print() */
|
|
|
|
void BBEINK::println(const string &str)
|
|
{
|
|
char ucTemp[4];
|
|
|
|
print(str);
|
|
ucTemp[0] = '\n';
|
|
ucTemp[1] = '\r';
|
|
ucTemp[2] = 0;
|
|
print((const char *)ucTemp);
|
|
} /* print() */
|
|
|
|
void BBEINK::print(const char *pString)
|
|
{
|
|
uint8_t *s = (uint8_t *)pString;
|
|
|
|
while (*s != 0) {
|
|
write(*s++);
|
|
}
|
|
} /* print() */
|
|
|
|
void BBEINK::println(const char *pString)
|
|
{
|
|
char ucTemp[4];
|
|
|
|
print(pString);
|
|
ucTemp[0] = '\n';
|
|
ucTemp[1] = '\r';
|
|
ucTemp[2] = 0;
|
|
print((const char *)ucTemp);
|
|
} /* println() */
|
|
void BBEINK::print(int value, int format)
|
|
{
|
|
char c, ucTemp[32];
|
|
char *d = &ucTemp[31];
|
|
|
|
if (value) {
|
|
d[0] = 0;
|
|
switch(format) {
|
|
case DEC:
|
|
while (value) {
|
|
d--;
|
|
*d = '0' + (value % 10);
|
|
value /= 10;
|
|
}
|
|
break;
|
|
case HEX:
|
|
while (value) {
|
|
d--;
|
|
c = value & 0xf;
|
|
if (c < 10)
|
|
*d = '0' + c;
|
|
else
|
|
*d = 'A' + (c-10);
|
|
value >>= 4;
|
|
}
|
|
break;
|
|
case OCT:
|
|
while (value) {
|
|
d--;
|
|
*d = '0' + (value & 7);
|
|
value >>= 3;
|
|
}
|
|
break;
|
|
case BIN:
|
|
while (value) {
|
|
d--;
|
|
*d = '0' + (value & 1);
|
|
value >>= 1;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else { // if zero value
|
|
d--;
|
|
*d = '0';
|
|
}
|
|
print((const char *)d);
|
|
} /* print() */
|
|
|
|
void BBEINK::println(int value, int format)
|
|
{
|
|
char ucTemp[4];
|
|
|
|
print(value, format);
|
|
ucTemp[0] = '\n';
|
|
ucTemp[1] = '\r';
|
|
ucTemp[2] = 0;
|
|
print((const char *)ucTemp);
|
|
} /* println() */
|
|
|
|
#endif // _LINUX_
|
|
//
|
|
// write (Arduino Print friend class)
|
|
//
|
|
#ifndef __AVR__
|
|
size_t BBEINK::write(uint8_t c) {
|
|
char szTemp[2]; // used to draw 1 character at a time to the C methods
|
|
int w, h;
|
|
|
|
szTemp[0] = c; szTemp[1] = 0;
|
|
if (_bbei.pFont == NULL) { // use built-in fonts
|
|
if (_bbei.iFont == FONT_8x8 || _bbei.iFont == FONT_6x8) {
|
|
h = 8;
|
|
w = (_bbei.iFont == FONT_8x8) ? 8 : 6;
|
|
} else if (_bbei.iFont == FONT_12x16) {
|
|
h = 16;
|
|
w = 12;
|
|
}
|
|
|
|
if (c == '\n') { // Newline?
|
|
_bbei.iCursorX = 0; // Reset x to zero,
|
|
_bbei.iCursorY += h; // advance y one line
|
|
} else if (c != '\r') { // Ignore carriage returns
|
|
if (_bbei.wrap && ((_bbei.iCursorX + w) > _bbei.width)) { // Off right?
|
|
_bbei.iCursorX = 0; // Reset x to zero,
|
|
_bbei.iCursorY += h; // advance y one line
|
|
}
|
|
bbeiWriteString(&_bbei, -1, -1, szTemp, _bbei.iFont, _bbei.iFG);
|
|
}
|
|
} else { // Custom font
|
|
BB_FONT *pBBF = (BB_FONT *)_bbei.pFont;
|
|
if (c == '\n') {
|
|
_bbei.iCursorX = 0;
|
|
_bbei.iCursorY += pBBF->height;
|
|
} else if (c != '\r') {
|
|
if (c >= pBBF->first && c <= pBBF->last) {
|
|
BB_GLYPH *pBBG = &pBBF->glyphs[c-pBBF->first];
|
|
w = pBBG->width;
|
|
h = pBBG->height;
|
|
if ((w > 0) && (h > 0)) { // Is there an associated bitmap?
|
|
int16_t xo = pBBG->xOffset;
|
|
w += xo; // xadvance
|
|
h = pBBF->height;
|
|
if (_bbei.wrap && ((_bbei.iCursorX + w) > _bbei.width)) {
|
|
_bbei.iCursorX = 0;
|
|
_bbei.iCursorY += h;
|
|
}
|
|
bbeiWriteStringCustom(&_bbei, (BB_FONT *)_bbei.pFont, -1, -1, szTemp, _bbei.iFG, _bbei.iPlane);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
} /* write() */
|
|
#endif // !__AVR__
|
|
|
|
void BBEINK::drawPixel(int16_t x, int16_t y, uint8_t color)
|
|
{
|
|
bbeiSetPixel(&_bbei, x, y, color);
|
|
}
|
|
int16_t BBEINK::getCursorX(void)
|
|
{
|
|
return _bbei.iCursorX;
|
|
}
|
|
int16_t BBEINK::getCursorY(void)
|
|
{
|
|
return _bbei.iCursorY;
|
|
}
|
|
void BBEINK::getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
|
|
{
|
|
if (_bbei.pFont) {
|
|
int width, top, bottom;
|
|
bbeiGetStringBox((BB_FONT *)_bbei.pFont, string, &width, &top, &bottom);
|
|
*x1 = x;
|
|
*w = width;
|
|
*y1 = y + top;
|
|
*h = (bottom - top + 1);
|
|
}
|
|
}
|
|
void BBEINK::getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
|
|
{
|
|
getTextBounds(str.c_str(), x, y, x1, y1, w, h);
|
|
}
|
|
int BBEINK::dataTime(void)
|
|
{
|
|
return _bbei.iDataTime;
|
|
}
|
|
int BBEINK::opTime(void)
|
|
{
|
|
return _bbei.iOpTime;
|
|
}
|
|
int16_t BBEINK::width(void)
|
|
{
|
|
return _bbei.width;
|
|
}
|
|
int16_t BBEINK::height(void)
|
|
{
|
|
return _bbei.height;
|
|
}
|
|
void BBEINK::drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color)
|
|
{
|
|
bbeiEllipse(&_bbei, x, y, r, r, color, 0);
|
|
}
|
|
void BBEINK::fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color)
|
|
{
|
|
bbeiEllipse(&_bbei, x, y, r, r, color, 1);
|
|
}
|
|
void BBEINK::drawEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color)
|
|
{
|
|
bbeiEllipse(&_bbei, x, y, rx, ry, color, 0);
|
|
}
|
|
void BBEINK::fillEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color)
|
|
{
|
|
bbeiEllipse(&_bbei, x, y, rx, ry, color, 1);
|
|
}
|
|
|
|
void BBEINK::sleep(int bDeep)
|
|
{
|
|
bbeiSleep(&_bbei, bDeep);
|
|
}
|
|
void BBEINK::wait(bool bQuick)
|
|
{
|
|
bbeiWaitBusy(&_bbei);
|
|
}
|
|
void BBEINK::drawString(const char *pText, int x, int y)
|
|
{
|
|
if (_bbei.pFont) {
|
|
bbeiWriteStringCustom(&_bbei, (BB_FONT *)_bbei.pFont, x, y, (char *)pText, _bbei.iFG, 0); // iPlane);
|
|
} else if (_bbei.iFont >= FONT_6x8 && _bbei.iFont < FONT_COUNT) {
|
|
bbeiWriteString(&_bbei, x, y, (char *)pText, _bbei.iFont, _bbei.iFG);
|
|
}
|
|
} /* drawString() */
|
|
|
|
void BBEINK::setPlane(int iPlane)
|
|
{
|
|
_bbei.iPlane = iPlane;
|
|
}
|
|
int BBEINK::getPlane(void)
|
|
{
|
|
return _bbei.iPlane;
|
|
}
|
|
|
|
int BBEINK::getChip(void)
|
|
{
|
|
return _bbei.chip_type;
|
|
}
|
|
void BBEINK::drawSprite(const uint8_t *pSprite, int cx, int cy, int iPitch, int x, int y, uint8_t iColor)
|
|
{
|
|
bbeiDrawSprite(&_bbei, pSprite, cx, cy, iPitch, x, y, iColor);
|
|
}
|
|
#endif // __cplusplus
|