Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • avn/swd/third-party/mxgui
1 result
Show changes
Commits on Source (20)
Showing
with 1415 additions and 77 deletions
......@@ -2,7 +2,7 @@
## Makefile for mxgui
## This makefile builds libmxgui.a
##
MAKEFILE_VERSION := 1.09
MAKEFILE_VERSION := 1.10
GCCMAJOR := $(shell arm-miosix-eabi-gcc --version | \
perl -e '$$_=<>;/\(GCC\) (\d+)/;print "$$1"')
## KPATH and CONFPATH are forwarded by the parent Makefile
......@@ -40,7 +40,8 @@ drivers/display_stm32f4discovery.cpp \
drivers/event_stm32f4discovery.cpp \
drivers/display_generic_1bpp.cpp \
drivers/display_generic_4bpp.cpp \
drivers/display_st7735.cpp
drivers/display_st7735.cpp \
drivers/display_st25dvdiscovery.cpp
ifeq ("$(VERBOSE)","1")
Q :=
......
/***************************************************************************
* Copyright (C) 2021 by Terraneo Federico *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or use *
* macros or inline functions from this file, or you compile this file *
* and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with the GNU General *
* Public License. This exception does not invalidate any other reasons *
* why a work based on this file might be covered by the GNU General *
* Public License. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#include "display_er_oledm015.h"
#include <miosix.h>
#include <kernel/scheduler/scheduler.h>
#include <interfaces/endianness.h>
#include <algorithm>
#include <line.h>
using namespace std;
using namespace miosix;
using namespace mxgui;
#ifndef _BOARD_STM32F411CE_BLACKPILL
#warning "The SPI driver has only been tested on an STM32F411CE_BLACKPILL"
#endif
//Display connection
using cs = Gpio<GPIOB_BASE,7>;
using sck = Gpio<GPIOB_BASE,3>; //Used as HW SPI
using mosi = Gpio<GPIOB_BASE,5>; //Used as HW SPI
using dc = Gpio<GPIOB_BASE,6>;
using res = Gpio<GPIOB_BASE,4>;
/**
* Send and receive a byte, thus returning only after transmission is complete
* \param x byte to send
* \return the received byte
*/
static unsigned char spi1sendRecv(unsigned char x=0)
{
SPI1->DR=x;
while((SPI1->SR & SPI_SR_RXNE)==0) ;
return SPI1->DR;
}
/**
* Send a byte only.
* NOTE: this function requires special care to use as
* - it returns before the byte has been transmitted, and if this is the last
* byte, you have to wait with spi1waitCompletion() before deasserting cs
* - as the received byte is ignored, the overrun flag gets set and it must be
* cleared (spi1waitCompletion() does that as well)
*/
static void spi1sendOnly(unsigned char x)
{
//NOTE: data is sent after the function returns, watch out!
while((SPI1->SR & SPI_SR_TXE)==0) ;
SPI1->DR=x;
}
/**
* Must be called after using spi1sendOnly(), complete the last byte transmission
*/
static void spi1waitCompletion()
{
while(SPI1->SR & SPI_SR_BSY) ;
//Reading DR and then SR clears overrun flag
[[gnu::unused]] volatile int unused;
unused=SPI1->DR;
unused=SPI1->SR;
}
/**
* DMA TX end of transfer
* NOTE: conflicts with SDIO driver but this board does not have an SD card
*/
void __attribute__((naked)) DMA2_Stream3_IRQHandler()
{
saveContext();
asm volatile("bl _Z20SPI1txDmaHandlerImplv");
restoreContext();
}
static Thread *waiting=nullptr;
static bool error;
void __attribute__((used)) SPI1txDmaHandlerImpl()
{
if(DMA2->LISR & (DMA_LISR_TEIF3 | DMA_LISR_DMEIF3 | DMA_LIFCR_CFEIF3))
error=true;
DMA2->LIFCR=DMA_LIFCR_CTCIF3
| DMA_LIFCR_CTEIF3
| DMA_LIFCR_CDMEIF3
| DMA_LIFCR_CFEIF3;
waiting->IRQwakeup();
if(waiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority())
Scheduler::IRQfindNextThread();
waiting=nullptr;
}
static void spi1SendDMA(const Color *data, int size)
{
error=false;
unsigned short tempCr1=SPI1->CR1;
SPI1->CR1=0;
SPI1->CR2=SPI_CR2_TXDMAEN;
SPI1->CR1=tempCr1;
waiting=Thread::getCurrentThread();
NVIC_ClearPendingIRQ(DMA2_Stream3_IRQn);
NVIC_SetPriority(DMA2_Stream3_IRQn,10);//Low priority for DMA
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
DMA2_Stream3->CR=0;
DMA2_Stream3->PAR=reinterpret_cast<unsigned int>(&SPI1->DR);
DMA2_Stream3->M0AR=reinterpret_cast<unsigned int>(data);
DMA2_Stream3->NDTR=2*size; //Size is at the peripheral side (8bit)
DMA2_Stream3->FCR=DMA_SxFCR_FEIE
| DMA_SxFCR_DMDIS;
DMA2_Stream3->CR=DMA_SxCR_CHSEL_0 //Channel 3 SPI1
| DMA_SxCR_CHSEL_1
//| DMA_SxCR_MSIZE_0 //Memory size 16 bit
| DMA_SxCR_MINC //Increment memory pointer
| DMA_SxCR_DIR_0 //Memory to peripheral
| DMA_SxCR_TCIE //Interrupt on transfer complete
| DMA_SxCR_TEIE //Interrupt on transfer error
| DMA_SxCR_DMEIE //Interrupt on direct mode error
| DMA_SxCR_EN; //Start DMA
{
FastInterruptDisableLock dLock;
while(waiting!=nullptr)
{
waiting->IRQwait();
{
FastInterruptEnableLock eLock(dLock);
Thread::yield();
}
}
}
NVIC_DisableIRQ(DMA2_Stream3_IRQn);
spi1waitCompletion();
SPI1->CR1=0;
SPI1->CR2=0;
SPI1->CR1=tempCr1;
//if(error) puts("SPI1 DMA tx failed"); //TODO: look into why this fails
}
/**
* Send a command to the display
* \param c command
*/
static void cmd(unsigned char c)
{
dc::low();
cs::low();
spi1sendRecv(c);
cs::high();
delayUs(1);
}
/**
* Send data to the display
* \param d data
*/
static void dat(unsigned char d)
{
dc::high();
cs::low();
spi1sendRecv(d);
cs::high();
delayUs(1);
}
static const int width=128, height=128; ///< Display size
/**
* Set cursor to desired location
* \param point where to set cursor (0<=x<128, 0<=y<128)
*/
static void setCursor(Point p)
{
#ifdef MXGUI_ORIENTATION_VERTICAL
cmd(0x15); dat(p.x()); dat(0x7f); // Set column address
cmd(0x75); dat(p.y()); dat(0x7f); // Set row address
#else //MXGUI_ORIENTATION_HORIZONTAL
cmd(0x15); dat(p.y()); dat(0x7f); // Set column address
cmd(0x75); dat(p.x()); dat(0x7f); // Set row address
#endif //Hardware doesn't seem to support mirroring
}
/**
* Set a hardware window on the screen, optimized for writing text.
* The GRAM increment will be set to up-to-down first, then left-to-right which
* is the correct increment to draw fonts
* \param p1 upper left corner of the window
* \param p2 lower right corner of the window
*/
static void textWindow(Point p1, Point p2)
{
#ifdef MXGUI_ORIENTATION_VERTICAL
cmd(0x15); dat(p1.x()); dat(p2.x()); // Set column address
cmd(0x75); dat(p1.y()); dat(p2.y()); // Set row address
cmd(0xa0); dat(0x67);
#else //MXGUI_ORIENTATION_HORIZONTAL
cmd(0x15); dat(p1.y()); dat(p2.y()); // Set column address
cmd(0x75); dat(p1.x()); dat(p2.x()); // Set row address
cmd(0xa0); dat(0x64);
#endif //Hardware doesn't seem to support mirroring
}
/**
* Set a hardware window on the screen, optimized for drawing images.
* The GRAM increment will be set to left-to-right first, then up-to-down which
* is the correct increment to draw images
* \param p1 upper left corner of the window
* \param p2 lower right corner of the window
*/
static inline void imageWindow(Point p1, Point p2)
{
#ifdef MXGUI_ORIENTATION_VERTICAL
cmd(0x15); dat(p1.x()); dat(p2.x()); // Set column address
cmd(0x75); dat(p1.y()); dat(p2.y()); // Set row address
cmd(0xa0); dat(0x66);
#else //MXGUI_ORIENTATION_HORIZONTAL
cmd(0x15); dat(p1.y()); dat(p2.y()); // Set column address
cmd(0x75); dat(p1.x()); dat(p2.x()); // Set row address
cmd(0xa0); dat(0x65);
#endif //Hardware doesn't seem to support mirroring
}
//
// class DisplayErOledm015
//
namespace mxgui {
DisplayErOledm015::DisplayErOledm015() : buffer(nullptr), buffer2(nullptr)
{
{
FastInterruptDisableLock dLock;
cs::mode(Mode::OUTPUT); cs::high();
sck::mode(Mode::ALTERNATE); sck::alternateFunction(5);
mosi::mode(Mode::ALTERNATE); mosi::alternateFunction(5);
dc::mode(Mode::OUTPUT);
res::mode(Mode::OUTPUT);
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
RCC_SYNC();
}
SPI1->CR1=SPI_CR1_SSM //No HW cs
| SPI_CR1_SSI
| SPI_CR1_SPE //SPI enabled
| SPI_CR1_BR_0 //SPI clock 50/4=12.5 MHz (Fmax=20MHz)
| SPI_CR1_MSTR;//Master mode
res::high();
Thread::sleep(1);
res::low();
delayUs(100);
res::high();
delayUs(100);
static const unsigned char grayTable[]=
{
0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 42, 45, 48,
51, 54, 57, 60, 63, 66, 69, 72, 76, 80, 84, 88, 92, 96,100,104,
108,112,116,120,125,130,135,140,145,150,155,160,165,170,175,180
};
cmd(0xfd); dat(0x12); // Disable command lock
cmd(0xfd); dat(0xb1); // Enable all commands
cmd(0xae); // Display OFF
cmd(0xa1); dat(0x00); // Set display start line
cmd(0xa2); dat(0x00); // Set display offset
cmd(0xa6); // Normal display mode
cmd(0xab); dat(0x01); // 8bit iface, 2.5V regulator ON
cmd(0xb1); dat(0x32); // Precharge phase2=3 phase1=5
cmd(0xb3); dat(0xf1); // Oscillator 0xf divide by 2
cmd(0xb4); dat(0xa0); dat(0xb5); dat(0x55); // External VSL
cmd(0xb6); dat(0x01); // Second precharge 1 DCLKS
cmd(0xb8); // Set gray table
for(unsigned int i=0;i<sizeof(grayTable);i++) dat(grayTable[i]);
cmd(0xbb); dat(0x17); // Precharge voltage ~0.5VCC
cmd(0xbe); dat(0x05); // VCOMH
cmd(0xc1); dat(0x88); dat(0x70); dat(0x88); // A B C brightness
cmd(0xc7); dat(0x0f); // Master brightness
cmd(0xca); dat(0x7f); // Duty 1:128
clear(0);
cmd(0xaf); // Display ON
setTextColor(make_pair(Color(0xffff),Color(0x0)));
}
void DisplayErOledm015::doTurnOn()
{
cmd(0xaf);
}
void DisplayErOledm015::doTurnOff()
{
cmd(0xae);
}
void DisplayErOledm015::doSetBrightness(int brt)
{
cmd(0xc7); dat(max(0,min(15,brt/6)));
}
pair<short int, short int> DisplayErOledm015::doGetSize() const
{
return make_pair(height,width);
}
void DisplayErOledm015::write(Point p, const char *text)
{
font.draw(*this,textColor,p,text);
}
void DisplayErOledm015::clippedWrite(Point p, Point a, Point b, const char *text)
{
font.clippedDraw(*this,textColor,p,a,b,text);
}
void DisplayErOledm015::clear(Color color)
{
clear(Point(0,0),Point(width-1,height-1),color);
}
void DisplayErOledm015::clear(Point p1, Point p2, Color color)
{
imageWindow(p1,p2);
doBeginPixelWrite();
int numPixels=(p2.x()-p1.x()+1)*(p2.y()-p1.y()+1);
for(int i=0;i<numPixels;i++) doWritePixel(color);
doEndPixelWrite();
}
void DisplayErOledm015::beginPixel() {}
void DisplayErOledm015::setPixel(Point p, Color color)
{
//Can't move boilerplate to beginPixel, as can't do setCursor in between
setCursor(p);
doBeginPixelWrite();
doWritePixel(color);
doEndPixelWrite();
}
void DisplayErOledm015::line(Point a, Point b, Color color)
{
//Horizontal line speed optimization
if(a.y()==b.y())
{
imageWindow(Point(min(a.x(),b.x()),a.y()),
Point(max(a.x(),b.x()),a.y()));
doBeginPixelWrite();
int numPixels=abs(a.x()-b.x());
for(int i=0;i<=numPixels;i++) doWritePixel(color);
doEndPixelWrite();
return;
}
//Vertical line speed optimization
if(a.x()==b.x())
{
textWindow(Point(a.x(),min(a.y(),b.y())),
Point(a.x(),max(a.y(),b.y())));
doBeginPixelWrite();
int numPixels=abs(a.y()-b.y());
for(int i=0;i<=numPixels;i++) doWritePixel(color);
doEndPixelWrite();
return;
}
//General case
Line::draw(*this,a,b,color);
}
void DisplayErOledm015::scanLine(Point p, const Color *colors, unsigned short length)
{
if(buffer2==nullptr) buffer2=new Color[buffer2Size];
length=min<unsigned short>(length,width-p.x());
imageWindow(p,Point(length-1,p.y()));
cmd(0x5c);
dc::high();
cs::low();
for(int i=0;i<length;i++) buffer2[i]=toBigEndian16(colors[i]);
spi1SendDMA(buffer2,length);
cs::high();
delayUs(1);
}
Color *DisplayErOledm015::getScanLineBuffer()
{
//getWidth() would be enough as size, but we reuse the buffer for DMA
if(buffer==nullptr) buffer=new Color[getWidth()];
return buffer;
}
void DisplayErOledm015::scanLineBuffer(Point p, unsigned short length)
{
scanLine(p,buffer,length);
}
void DisplayErOledm015::drawImage(Point p, const ImageBase& img)
{
const Color *imgData=img.getData();
if(imgData!=0)
{
if(buffer2==nullptr) buffer2=new Color[buffer2Size];
short int xEnd=p.x()+img.getWidth()-1;
short int yEnd=p.y()+img.getHeight()-1;
imageWindow(p,Point(xEnd,yEnd));
cmd(0x5c);
dc::high();
cs::low();
//Unfortunately the DMA requires the endianness to be swapped, the
//pointer we get is read-only (can be in flash), and we may not have
//enough memory to allocate a large enough buffer to hold the entire
//image, so we'll have to split it in chunks
int imgSize=img.getHeight()*img.getWidth();
while(imgSize>0)
{
int chunkSize=min(imgSize,buffer2Size);
for(int i=0;i<chunkSize;i++) buffer2[i]=toBigEndian16(imgData[i]);
spi1SendDMA(buffer2,chunkSize);
imgSize-=chunkSize;
imgData+=chunkSize;
}
cs::high();
delayUs(1);
} else img.draw(*this,p);
}
void DisplayErOledm015::clippedDrawImage(Point p, Point a, Point b, const ImageBase& img)
{
img.clippedDraw(*this,p,a,b);
}
void DisplayErOledm015::drawRectangle(Point a, Point b, Color c)
{
line(a,Point(b.x(),a.y()),c);
line(Point(b.x(),a.y()),b,c);
line(b,Point(a.x(),b.y()),c);
line(Point(a.x(),b.y()),a,c);
}
DisplayErOledm015::pixel_iterator DisplayErOledm015::begin(Point p1, Point p2,
IteratorDirection d)
{
if(p1.x()<0 || p1.y()<0 || p2.x()<0 || p2.y()<0) return pixel_iterator();
if(p1.x()>=width || p1.y()>=height || p2.x()>=width || p2.y()>=height)
return pixel_iterator();
if(p2.x()<p1.x() || p2.y()<p1.y()) return pixel_iterator();
if(d==DR) textWindow(p1,p2);
else imageWindow(p1,p2);
doBeginPixelWrite();
unsigned int numPixels=(p2.x()-p1.x()+1)*(p2.y()-p1.y()+1);
return pixel_iterator(numPixels);
}
DisplayErOledm015::~DisplayErOledm015() {}
void DisplayErOledm015::doBeginPixelWrite()
{
cmd(0x5c);
dc::high();
cs::low();
}
void DisplayErOledm015::doWritePixel(Color c)
{
spi1sendOnly(c>>8);
spi1sendOnly(c);
}
void DisplayErOledm015::doEndPixelWrite()
{
spi1waitCompletion();
cs::high();
delayUs(1);
}
} //namespace mxgui
/***************************************************************************
* Copyright (C) 2021 by Terraneo Federico *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or use *
* macros or inline functions from this file, or you compile this file *
* and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with the GNU General *
* Public License. This exception does not invalidate any other reasons *
* why a work based on this file might be covered by the GNU General *
* Public License. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#pragma once
#include <config/mxgui_settings.h>
#include "display.h"
#include "point.h"
#include "color.h"
#include "iterator_direction.h"
#include <cstdio>
#include <cstring>
#include <algorithm>
namespace mxgui {
//This display is 16 bit per pixel, check that the color depth is properly
//configured
#ifndef MXGUI_COLOR_DEPTH_16_BIT
#error The SSD1351 driver requires a color depth of 16bit per pixel
#endif
class DisplayErOledm015 : public Display
{
public:
/**
* Constructor.
*/
DisplayErOledm015();
/**
* Turn the display On after it has been turned Off.
* Display initial state is On.
*/
void doTurnOn() override;
/**
* Turn the display Off. It can be later turned back On.
*/
void doTurnOff() override;
/**
* Set display brightness. Depending on the underlying driver,
* may do nothing.
* \param brt from 0 to 100
*/
void doSetBrightness(int brt) override;
/**
* \return a pair with the display height and width
*/
std::pair<short int, short int> doGetSize() const override;
/**
* Write text to the display. If text is too long it will be truncated
* \param p point where the upper left corner of the text will be printed
* \param text, text to print.
*/
void write(Point p, const char *text) override;
/**
* Write part of text to the display
* \param p point of the upper left corner where the text will be drawn.
* Negative coordinates are allowed, as long as the clipped view has
* positive or zero coordinates
* \param a Upper left corner of clipping rectangle
* \param b Lower right corner of clipping rectangle
* \param text text to write
*/
void clippedWrite(Point p, Point a, Point b, const char *text) override;
/**
* Clear the Display. The screen will be filled with the desired color
* \param color fill color
*/
void clear(Color color) override;
/**
* Clear an area of the screen
* \param p1 upper left corner of area to clear
* \param p2 lower right corner of area to clear
* \param color fill color
*/
void clear(Point p1, Point p2, Color color) override;
/**
* This backend does not require it, so it is a blank.
*/
void beginPixel() override;
/**
* Draw a pixel with desired color. You have to call beginPixel() once
* before calling setPixel()
* \param p point where to draw pixel
* \param color pixel color
*/
void setPixel(Point p, Color color) override;
/**
* Draw a line between point a and point b, with color c
* \param a first point
* \param b second point
* \param c line color
*/
void line(Point a, Point b, Color color) override;
/**
* Draw an horizontal line on screen.
* Instead of line(), this member function takes an array of colors to be
* able to individually set pixel colors of a line.
* \param p starting point of the line
* \param colors an array of pixel colors whoase size must be b.x()-a.x()+1
* \param length length of colors array.
* p.x()+length must be <= display.width()
*/
void scanLine(Point p, const Color *colors, unsigned short length) override;
/**
* \return a buffer of length equal to this->getWidth() that can be used to
* render a scanline.
*/
Color *getScanLineBuffer() override;
/**
* Draw the content of the last getScanLineBuffer() on an horizontal line
* on the screen.
* \param p starting point of the line
* \param length length of colors array.
* p.x()+length must be <= display.width()
*/
void scanLineBuffer(Point p, unsigned short length) override;
/**
* Draw an image on the screen
* \param p point of the upper left corner where the image will be drawn
* \param i image to draw
*/
void drawImage(Point p, const ImageBase& img) override;
/**
* Draw part of an image on the screen
* \param p point of the upper left corner where the image will be drawn.
* Negative coordinates are allowed, as long as the clipped view has
* positive or zero coordinates
* \param a Upper left corner of clipping rectangle
* \param b Lower right corner of clipping rectangle
* \param i Image to draw
*/
void clippedDrawImage(Point p, Point a, Point b, const ImageBase& img) override;
/**
* Draw a rectangle (not filled) with the desired color
* \param a upper left corner of the rectangle
* \param b lower right corner of the rectangle
* \param c color of the line
*/
void drawRectangle(Point a, Point b, Color c) override;
/**
* Pixel iterator. A pixel iterator is an output iterator that allows to
* define a window on the display and write to its pixels.
*/
class pixel_iterator
{
public:
/**
* Default constructor, results in an invalid iterator.
*/
pixel_iterator(): pixelLeft(0) {}
/**
* Set a pixel and move the pointer to the next one
* \param color color to set the current pixel
* \return a reference to this
*/
pixel_iterator& operator= (Color color)
{
pixelLeft--;
DisplayErOledm015::doWritePixel(color);
if(pixelLeft==0) DisplayErOledm015::doEndPixelWrite();
return *this;
}
/**
* Compare two pixel_iterators for equality.
* They are equal if they point to the same location.
*/
bool operator== (const pixel_iterator& itr)
{
return this->pixelLeft==itr.pixelLeft;
}
/**
* Compare two pixel_iterators for inequality.
* They different if they point to different locations.
*/
bool operator!= (const pixel_iterator& itr)
{
return this->pixelLeft!=itr.pixelLeft;
}
/**
* \return a reference to this.
*/
pixel_iterator& operator* () { return *this; }
/**
* \return a reference to this. Does not increment pixel pointer.
*/
pixel_iterator& operator++ () { return *this; }
/**
* \return a reference to this. Does not increment pixel pointer.
*/
pixel_iterator& operator++ (int) { return *this; }
/**
* Must be called if not all pixels of the required window are going
* to be written.
*/
void invalidate()
{
DisplayErOledm015::doEndPixelWrite();
}
private:
/**
* Constructor
* \param start Upper left corner of window
* \param end Lower right corner of window
* \param direction Iterator direction
* \param disp Display we're associated
*/
pixel_iterator(unsigned int pixelLeft): pixelLeft(pixelLeft) {}
unsigned int pixelLeft; ///< How many pixels are left to draw
friend class DisplayErOledm015; //Needs access to ctor
};
/**
* Specify a window on screen and return an object that allows to write
* its pixels.
* Note: a call to begin() will invalidate any previous iterator.
* \param p1 upper left corner of window
* \param p2 lower right corner (included)
* \param d increment direction
* \return a pixel iterator
*/
pixel_iterator begin(Point p1, Point p2, IteratorDirection d);
/**
* \return an iterator which is one past the last pixel in the pixel
* specified by begin. Behaviour is undefined if called before calling
* begin()
*/
pixel_iterator end() const
{
//Default ctor: pixelLeft is zero.
return pixel_iterator();
}
/**
* Destructor
*/
~DisplayErOledm015();
private:
static void doBeginPixelWrite();
static void doWritePixel(Color c);
static void doEndPixelWrite();
Color *buffer; ///< For scanLineBuffer
Color *buffer2; ///< For DMA transfers
static const int buffer2Size=512; ///< DMA buffer size
};
} //namespace mxgui
#include <cstdio>
#include "miosix.h"
#include "mxgui/display.h"
#include "mxgui/misc_inst.h"
#include "display_er_oledm015.h"
using namespace std;
using namespace miosix;
using namespace mxgui;
//NOTE: to try this example, you have to connect the display to the board as
//written in display_er_oledm015.cpp
/*
* On boards which do not have a built-in display, MXGUI requires you to
* implement the registerDisplayHook callback to tell MXGUI which display to
* use. If you want to adapt this example for a board that already has a
* display, you can register a secondary display in the main with the following
* line
* \code
* DisplayManager::instance().registerDisplay(new DisplayLy091wg14<sda,scl,reset>);
* \endcode
* And then get the display with DisplayManager::instance().getDisplay(1).
* Note that 0 is the default display, 1 would be the secondary one.
*/
namespace mxgui {
void registerDisplayHook(DisplayManager& dm)
{
dm.registerDisplay(new DisplayErOledm015);
}
} //namespace mxgui
int main()
{
auto& display=DisplayManager::instance().getDisplay();
{
DrawingContext dc(display);
dc.setFont(tahoma);
dc.write(Point(0,0),"Miosix OS");
dc.write(Point(0,tahoma.getHeight()),"MXGUI graphics library");
}
for(int i=0;;i++)
{
{
DrawingContext dc(display);
char s[16];
sniprintf(s,15,"%02d:%02d",i/60,i%60);
dc.write(Point(0,2*tahoma.getHeight()),s);
}
Thread::sleep(1000);
}
}
/***************************************************************************
* Copyright (C) 2021 by Terraneo Federico *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or use *
* macros or inline functions from this file, or you compile this file *
* and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with the GNU General *
* Public License. This exception does not invalidate any other reasons *
* why a work based on this file might be covered by the GNU General *
* Public License. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#include "display_er_oledm024.h"
#include <miosix.h>
#include <algorithm>
using namespace std;
using namespace miosix;
#ifndef _BOARD_STM32F411CE_BLACKPILL
#warning "The SPI driver has only been tested on an STM32F411CE_BLACKPILL"
#endif
//Display connection
using cs = Gpio<GPIOB_BASE,7>;
using sck = Gpio<GPIOB_BASE,3>; //Used as HW SPI
using mosi = Gpio<GPIOB_BASE,5>; //Used as HW SPI
using dc = Gpio<GPIOB_BASE,6>;
using res = Gpio<GPIOB_BASE,4>;
/**
* Send and receive a byte, thus returning only after transmission is complete
* \param x byte to send
* \return the received byte
*/
static unsigned char spi1sendRecv(unsigned char x=0)
{
SPI1->DR=x;
while((SPI1->SR & SPI_SR_RXNE)==0) ;
return SPI1->DR;
}
/**
* Send a byte only.
* NOTE: this function requires special care to use as
* - it returns before the byte has been transmitted, and if this is the last
* byte, you have to wait with spi1waitCompletion() before deasserting cs
* - as the received byte is ignored, the overrun flag gets set and it must be
* cleared (spi1waitCompletion() does that as well)
*/
static void spi1sendOnly(unsigned char x)
{
//NOTE: data is sent after the function returns, watch out!
while((SPI1->SR & SPI_SR_TXE)==0) ;
SPI1->DR=x;
}
/**
* Must be called after using spi1sendOnly(), complete the last byte transmission
*/
static void spi1waitCompletion()
{
while(SPI1->SR & SPI_SR_BSY) ;
//Reading DR and then SR clears overrun flag
[[gnu::unused]] volatile int unused;
unused=SPI1->DR;
unused=SPI1->SR;
}
/**
* Send a command to the display
* \param c command
*/
static void cmd(unsigned char c)
{
dc::low();
cs::low();
spi1sendRecv(c);
cs::high();
delayUs(1);
}
//
// class DisplayErOledm024
//
namespace mxgui {
DisplayErOledm024::DisplayErOledm024() : DisplayGeneric1BPP(128,64)
{
{
FastInterruptDisableLock dLock;
cs::mode(Mode::OUTPUT); cs::high();
sck::mode(Mode::ALTERNATE); sck::alternateFunction(5);
mosi::mode(Mode::ALTERNATE); mosi::alternateFunction(5);
dc::mode(Mode::OUTPUT);
res::mode(Mode::OUTPUT);
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
RCC_SYNC();
}
SPI1->CR1=SPI_CR1_SSM //No HW cs
| SPI_CR1_SSI
| SPI_CR1_SPE //SPI enabled
| SPI_CR1_BR_1 //SPI clock 50/8=6.25 MHz (Fmax=10MHz)
| SPI_CR1_MSTR;//Master mode
res::high();
Thread::sleep(1);
res::low();
delayUs(100);
res::high();
delayUs(100);
//VCC=13.4V VCOMH=10.4V IREF~11uA SPI_fmax=10MHz
/*
* Power save mode reduces frame rate and precharge time to reduce current
* consumption from the VCC side. Power consumption from the VDD side is
* < 100uA and thus negligible.
* Measured current [mA] as a function of #pixel active
* pixel_on default_current power_save_current
* 0 0.70 0.49 (off current)
* 128 1.23 0.85
* ...
* 15*128 6.88 4.98
*
* Further tried to reduce scanlines to 16 with
* cmd(0xd5); cmd(0x03); // Oscillator 0x0, /4 (75Hz)
* cmd(0xa8); cmd(15); // Number of rows 16
* and got off current down to 0.15mA but per pixel current significantly
* increased and bug in cmd(0x81) set brightness did not allow to correct
*/
#define POWER_SAVE //Active by default
#ifndef POWER_SAVE
const unsigned char oscCfg=0xa0; // 120Hz refresh rate
const unsigned char prcgCfg=0x25;// Precharge phase2=2 phase1=5
#else //POWER_SAVE
const unsigned char oscCfg=0x00; // 78Hz -30% off current 0.7 -> 0.48mA
const unsigned char prcgCfg=0x13;// 1,3 -22% on current 3.1 -> 2.4uA/pix
#endif //POWER_SAVE
cmd(0xfd); cmd(0x12); // Disable command lock
cmd(0xae); // Display OFF
cmd(0xd5); cmd(oscCfg); // Oscillator
cmd(0xa8); cmd(height-1); // Number of rows 64
cmd(0xd3); cmd(0x00); // Display offset 0
cmd(0x40); // Display start line 0
cmd(0x20); cmd(0x00); // Memory addrressing horizontal
cmd(0xa1);
cmd(0xc8); // Scan direction 64 to 1
cmd(0xda); cmd(0x12); // Alternate COM, no COM left/right
cmd(0x81); cmd(0x32); // Brightness 1.1uA/pixel
cmd(0xd9); cmd(prcgCfg); // Precharge phase2=2 phase1=5
cmd(0xdb); cmd(0x34); // VCOMH=.78*VCC
cmd(0xa6); // Normal display mode
cmd(0xa4); // Disable test mode
clear(0);
update();
cmd(0xaf); // Display ON
setTextColor(std::make_pair(Color(0xf),Color(0x0)));
}
void DisplayErOledm024::doTurnOn()
{
cmd(0xaf);
}
void DisplayErOledm024::doTurnOff()
{
cmd(0xae);
}
void DisplayErOledm024::doSetBrightness(int brt)
{
int brightness=max(0,min(50,brt/2));
cmd(0x81); cmd(brightness);
}
void DisplayErOledm024::update()
{
cmd(0x21); cmd(0); cmd(127);
cmd(0x22); cmd(0); cmd(7);
dc::high();
cs::low();
for(int i=0;i<fbSize;i++) spi1sendOnly(backbuffer[i]);
spi1waitCompletion();
cs::high();
delayUs(1);
}
} //namespace mxgui
/***************************************************************************
* Copyright (C) 2021 by Terraneo Federico *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or use *
* macros or inline functions from this file, or you compile this file *
* and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with the GNU General *
* Public License. This exception does not invalidate any other reasons *
* why a work based on this file might be covered by the GNU General *
* Public License. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#pragma once
#include <mxgui/drivers/display_generic_1bpp.h>
namespace mxgui {
class DisplayErOledm024 : public DisplayGeneric1BPP
{
public:
/*
* Constructor
*/
DisplayErOledm024();
/**
* Turn the display On after it has been turned Off.
* Display initial state is On.
*/
void doTurnOn() override;
/**
* Turn the display Off. It can be later turned back On.
*/
void doTurnOff() override;
/**
* Set display brightness. Depending on the underlying driver,
* may do nothing.
* \param brt from 0 to 100
*/
void doSetBrightness(int brt) override;
/**
* Make all changes done to the display since the last call to update()
* visible. Backends that require it may override this.
*/
void update() override;
};
} //namespace mxgui
#include <cstdio>
#include "miosix.h"
#include "mxgui/display.h"
#include "mxgui/misc_inst.h"
#include "display_er_oledm024.h"
using namespace std;
using namespace miosix;
using namespace mxgui;
//NOTE: to try this example, you have to connect the display to the board as
//written in display_er_oledm024.cpp
/*
* On boards which do not have a built-in display, MXGUI requires you to
* implement the registerDisplayHook callback to tell MXGUI which display to
* use. If you want to adapt this example for a board that already has a
* display, you can register a secondary display in the main with the following
* line
* \code
* DisplayManager::instance().registerDisplay(new DisplayLy091wg14<sda,scl,reset>);
* \endcode
* And then get the display with DisplayManager::instance().getDisplay(1).
* Note that 0 is the default display, 1 would be the secondary one.
*/
namespace mxgui {
void registerDisplayHook(DisplayManager& dm)
{
dm.registerDisplay(new DisplayErOledm024);
}
} //namespace mxgui
int main()
{
auto& display=DisplayManager::instance().getDisplay();
{
DrawingContext dc(display);
dc.setFont(tahoma);
dc.write(Point(0,0),"Miosix OS");
dc.write(Point(0,tahoma.getHeight()),"MXGUI graphics library");
}
for(int i=0;;i++)
{
{
DrawingContext dc(display);
char s[16];
sniprintf(s,15,"%02d:%02d",i/60,i%60);
dc.write(Point(0,2*tahoma.getHeight()),s);
}
Thread::sleep(1000);
}
}
......@@ -38,61 +38,74 @@ using namespace miosix;
//Display connection
typedef Gpio<GPIOB_BASE,3> sck;
typedef Gpio<GPIOB_BASE,4> miso; //Not used
typedef Gpio<GPIOB_BASE,5> mosi;
typedef Gpio<GPIOB_BASE,7> cs;
typedef Gpio<GPIOB_BASE,8> dc;
typedef Gpio<GPIOB_BASE,15> reset;
static void spiInit()
using cs = Gpio<GPIOB_BASE,7>; //Display pin 16
using sck = Gpio<GPIOB_BASE,3>; //Display pin 4, used as HW SPI
using mosi = Gpio<GPIOB_BASE,5>; //Display pin 5, used as HW SPI
using dc = Gpio<GPIOB_BASE,8>; //Display pin 14
using res = Gpio<GPIOB_BASE,15>; //Display pin 15
//Display pin 2 is Vbat (3.3..5V), while display pins 1,7,8,9,10,11,12,13 are GND
/**
* Send and receive a byte, thus returning only after transmission is complete
* \param x byte to send
* \return the received byte
*/
static unsigned char spi3sendRecv(unsigned char x=0)
{
sck::mode(Mode::ALTERNATE);
sck::alternateFunction(6);
mosi::mode(Mode::ALTERNATE);
mosi::alternateFunction(6);
cs::mode(Mode::OUTPUT);
cs::high();
SPI3->DR=x;
while((SPI3->SR & SPI_SR_RXNE)==0) ;
return SPI3->DR;
}
{
FastInterruptDisableLock dLock;
RCC->APB1ENR |= RCC_APB1ENR_SPI3EN;
RCC_SYNC();
}
//Master mode no hardware CS pin
//Note: SPI3 is attached on the 42MHz APB2 bus, so the clock is set
//to APB2/2/2=10.5MHz. This overclocking the SSD1332 by 500KHz
SPI3->CR1=SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR | SPI_CR1_BR_0;
SPI3->CR2=0;
SPI3->CR1 |= SPI_CR1_SPE; //Set enable bit
/**
* Send a byte only.
* NOTE: this function requires special care to use as
* - it returns before the byte has been transmitted, and if this is the last
* byte, you have to wait with spi3waitCompletion() before deasserting cs
* - as the received byte is ignored, the overrun flag gets set and it must be
* cleared (spi1waitCompletion() does that as well)
*/
static void spi3sendOnly(unsigned char x)
{
//NOTE: data is sent after the function returns, watch out!
while((SPI3->SR & SPI_SR_TXE)==0) ;
SPI3->DR=x;
}
static unsigned char spiSendRecv(unsigned char data)
/**
* Must be called after using spi3sendOnly(), complete the last byte transmission
*/
static void spi3waitCompletion()
{
SPI3->DR=data;
while((SPI3->SR & SPI_SR_RXNE)==0) ;
return SPI3->DR;
while(SPI3->SR & SPI_SR_BSY) ;
//Reading DR and then SR clears overrun flag
[[gnu::unused]] volatile int unused;
unused=SPI3->DR;
unused=SPI3->SR;
}
/**
* Send a command to the display
* \param c command
*/
static void cmd(unsigned char c)
{
dc::low();
cs::low();
delayUs(1);
spiSendRecv(c);
spi3sendRecv(c);
cs::high();
delayUs(1);
}
/**
* Send data to the display
* \param d data
*/
static void data(unsigned char d)
{
dc::high();
cs::low();
delayUs(1);
spiSendRecv(d);
spi3sendRecv(d);
cs::high();
delayUs(1);
}
......@@ -105,15 +118,29 @@ namespace mxgui {
DisplayErOledm028::DisplayErOledm028() : DisplayGeneric4BPP(256,64)
{
spiInit();
dc::mode(Mode::OUTPUT);
reset::mode(Mode::OUTPUT);
{
FastInterruptDisableLock dLock;
cs::mode(Mode::OUTPUT); cs::high();
sck::mode(Mode::ALTERNATE); sck::alternateFunction(6);
mosi::mode(Mode::ALTERNATE); mosi::alternateFunction(6);
dc::mode(Mode::OUTPUT);
res::mode(Mode::OUTPUT);
RCC->APB1ENR |= RCC_APB1ENR_SPI3EN;
RCC_SYNC();
}
SPI3->CR1=SPI_CR1_SSM //No HW cs
| SPI_CR1_SSI
| SPI_CR1_SPE //SPI enabled
| SPI_CR1_BR_1 //SPI clock 42/8=5.25MHz (Fmax=10MHz)
| SPI_CR1_MSTR;//Master mode
reset::high();
res::high();
Thread::sleep(1);
reset::low();
res::low();
delayUs(100);
reset::high();
res::high();
delayUs(100);
cmd(0xfd); data(0x12); // Disable command lock
......@@ -167,8 +194,8 @@ void DisplayErOledm028::update()
dc::high();
cs::low();
delayUs(1);
for(int i=0;i<fbSize;i++) spiSendRecv(backbuffer[i]);
for(int i=0;i<fbSize;i++) spi3sendOnly(backbuffer[i]);
spi3waitCompletion();
cs::high();
delayUs(1);
}
......
......@@ -41,5 +41,14 @@ int main()
dc.setFont(tahoma);
dc.write(Point(0,droid21.getHeight()),"MXGUI graphics library");
}
for(;;) Thread::sleep(100);
for(int i=0;;i++)
{
{
DrawingContext dc(display);
char s[16];
sniprintf(s,15,"%02d:%02d",i/60,i%60);
dc.write(Point(0,droid21.getHeight()+tahoma.getHeight()),s);
}
Thread::sleep(1000);
}
}
......@@ -5,10 +5,10 @@ if [ ! -d freetype-2.4.3 ]; then
echo "Building freetype 2.4.3"
tar xjvf ../libs/freetype-2.4.3.tar.bz2
cd freetype-2.4.3
./configure
./configure --enable-static --disable-shared
make
# We want to forcefully link statically, and a possible way is to remove
# the dynamic libraries
cd objs/.libs
rm libfreetype.so libfreetype.la libfreetype.lai
rm -f libfreetype.so libfreetype.la libfreetype.lai
fi
File mode changed from 100644 to 100755
......@@ -53,7 +53,7 @@ or, for people w/o outgoing svn:
Online documentation can be found here:
http://www.nongnu.org/pngpp/doc/html/index.html
http://www.nongnu.org/pngpp/doc/
Help
......
? add output transformations
+ support for non-8bit data
+ stream exceptions: badbit only
+ adjust png::image for non-memory back end buffer + row-by-row io
+ use doxygen
- add optional and unknown chunks handling
+ change bit_depth to size_t
+ move tests sources to test/, examples to examples/
+ extract common code from generator/consumer
+ update pixel traits to detect channels count
+ unify template parameters naming
+ make sure all headers compile on their own
+ add compilation dependency detection
+ add pixel_buffer/image::operator[]
+ improve docs and README
? endianness in expand_8_to_16()
- unify error messages (capitalization, etc.)
+ move stream template parameter from class to function level in
generator and consumer
+ make all tests run even if any of them fails
......@@ -100,7 +100,7 @@ namespace png
strerror_s(buf, ERRBUF_SIZE, errnum);
return std::string(buf);
#else
#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE
#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || (!__GLIBC__)
strerror_r(errnum, buf, ERRBUF_SIZE);
return std::string(buf);
#else
......
......@@ -164,7 +164,7 @@ namespace png
*/
void put_row(size_t index, row_const_access r)
{
row_access row = get_row();
row_access row = get_row(index);
for (uint_32 i = 0; i < m_width; ++i)
*row++ = *r++;
}
......
......@@ -73,17 +73,17 @@ include_directories(../..)
include_directories(../../..)
add_definitions(-DMXGUI_LIBRARY)
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
qt4_wrap_cpp(FOO_HEADERS_MOC ${FOO_HEADERS})
find_package(Qt5 COMPONENTS Widgets REQUIRED)
qt5_wrap_cpp(FOO_HEADERS_MOC ${FOO_HEADERS})
if(APPLE)
add_executable(qtsimulator MACOSX_BUNDLE ${LIB_SRCS} ${FOO_SRCS} ${IMG_OUT} ${FOO_HEADERS_MOC})
else()
add_executable(qtsimulator ${LIB_SRCS} ${FOO_SRCS} ${IMG_OUT} ${FOO_HEADERS_MOC})
endif()
target_link_libraries(qtsimulator ${QT_LIBRARIES})
target_link_libraries(qtsimulator Qt5::Widgets)
set(BOOST_LIBS thread filesystem system)
find_package(Boost COMPONENTS ${BOOST_LIBS} REQUIRED)
target_link_libraries(qtsimulator ${Boost_LIBRARIES})
target_include_directories(qtsimulator PRIVATE ${Boost_INCLUDE_DIRS})
find_package(Threads REQUIRED)
target_link_libraries(qtsimulator ${CMAKE_THREAD_LIBS_INIT})
#include <QtGui/QApplication>
#include <QtWidgets/QApplication>
#include <boost/filesystem.hpp>
#include "window.h"
......
......@@ -63,7 +63,7 @@ Window::Window(QWidget *parent): QWidget(parent),
this->setWindowTitle(tr("Mxgui simulator"));
this->show();
QTBackend& qb=QTBackend::instance();
std::memcpy(image.bits(),qb.getFrameBuffer().getData(),image.byteCount());
std::memcpy(image.bits(),qb.getFrameBuffer().getData(),image.sizeInBytes());
this->update();
qb.start(sender);
}
......@@ -71,7 +71,7 @@ Window::Window(QWidget *parent): QWidget(parent),
void Window::updateFrameBuffer()
{
FrameBuffer& buffer=QTBackend::instance().getFrameBuffer();
std::memcpy(image.bits(),buffer.getData(),image.byteCount());
std::memcpy(image.bits(),buffer.getData(),image.sizeInBytes());
this->update();
}
......@@ -140,7 +140,7 @@ void Window::keyPressEvent(QKeyEvent *event)
}
QString s=event->text();
if(s.size()==0) return;
char k=s[0].toAscii();
char k=s[0].toLatin1();
addEvent(Event(EventType::KeyDown,k));
}
......@@ -154,6 +154,6 @@ void Window::keyReleaseEvent(QKeyEvent *event)
}
QString s=event->text();
if(s.size()==0) return;
char k=s[0].toAscii();
char k=s[0].toLatin1();
addEvent(Event(EventType::KeyUp,k));
}
# Copyright (C) 2023 by Skyward
#
# This program is free software; you can redistribute it and/or
# it under the terms of the GNU General Public License as published
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# As a special exception, if other files instantiate templates or use
# macros or inline functions from this file, or you compile this file
# and link it with other works to produce a work based on this file,
# this file does not by itself cause the resulting work to be covered
# by the GNU General Public License. However the source code for this
# file must still be made available in accordance with the GNU
# Public License. This exception does not invalidate any other
# why a work based on this file might be covered by the GNU General
# Public License.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>
set(MXGUI_BOARDS_OPTIONS_FILES
${KPATH}/config/arch/cortexM4_stm32f4/stm32f429zi_stm32f4discovery/board_options.cmake
)
# Copyright (C) 2023 by Skyward
#
# This program is free software; you can redistribute it and/or
# it under the terms of the GNU General Public License as published
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# As a special exception, if other files instantiate templates or use
# macros or inline functions from this file, or you compile this file
# and link it with other works to produce a work based on this file,
# this file does not by itself cause the resulting work to be covered
# by the GNU General Public License. However the source code for this
# file must still be made available in accordance with the GNU
# Public License. This exception does not invalidate any other
# why a work based on this file might be covered by the GNU General
# Public License.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>
# Load in MXGUI_PATH the project path
cmake_path(GET CMAKE_CURRENT_LIST_DIR PARENT_PATH MXGUI_PATH)
cmake_path(GET MXGUI_PATH PARENT_PATH MXGUI_PARENT_PATH)
# Include board list
include(${MXGUI_PATH}/cmake/boards.cmake)
# MxGui source files
set(MXGUI_SRC
${MXGUI_PATH}/display.cpp
${MXGUI_PATH}/font.cpp
${MXGUI_PATH}/misc_inst.cpp
${MXGUI_PATH}/tga_image.cpp
${MXGUI_PATH}/resourcefs.cpp
${MXGUI_PATH}/resource_image.cpp
${MXGUI_PATH}/level2/input.cpp
${MXGUI_PATH}/level2/application.cpp
${MXGUI_PATH}/level2/drawing_context_proxy.cpp
${MXGUI_PATH}/level2/label.cpp
${MXGUI_PATH}/level2/simple_plot.cpp
${MXGUI_PATH}/drivers/display_stm32f4discovery.cpp
${MXGUI_PATH}/drivers/event_stm32f4discovery.cpp
)
# Creates the MxGui::${BOARD_NAME} library
function(add_mxgui_library BOARD_OPTIONS_FILE)
# Get board options
include(${BOARD_OPTIONS_FILE})
# Create a library for the board
set(MXGUI_LIB mxgui-${BOARD_NAME})
add_library(${MXGUI_LIB} STATIC EXCLUDE_FROM_ALL ${MXGUI_SRC})
# Include MxGui directories
target_include_directories(${MXGUI_LIB} PUBLIC
${KPATH}
${KPATH}/arch/common
${ARCH_PATH}
${BOARD_PATH}
${BOARD_CONFIG_PATH}
${MXGUI_PARENT_PATH}
${MXGUI_PATH}
)
# Set include path where to find config/miosix_settings.h
if(DEFINED BOARD_MIOSIX_SETTINGS_PATH)
target_include_directories(${MXGUI_LIB} PRIVATE ${BOARD_MIOSIX_SETTINGS_PATH})
else()
target_include_directories(${MXGUI_LIB} PRIVATE ${KPATH}/default)
endif()
# Define MXGUI_LIB (only for C and C++)
target_compile_definitions(${MXGUI_LIB} PRIVATE $<$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>:MXGUI_LIBRARY>)
# Require cpp14 target_compile_features (this will add the -std=c++14 flag)
target_compile_features(${MXGUI_LIB} PUBLIC cxx_std_14)
# Configure compiler flags
target_compile_options(${MXGUI_LIB} PRIVATE
$<$<COMPILE_LANGUAGE:ASM>:${AFLAGS_BASE}>
$<$<COMPILE_LANGUAGE:C>:${DFLAGS} ${CFLAGS_BASE}>
$<$<COMPILE_LANGUAGE:CXX>:${DFLAGS} ${CXXFLAGS_BASE}>
)
# Create a nice alias for the library
add_library(MxGui::${BOARD_NAME} ALIAS ${MXGUI_LIB})
endfunction()
# Create MxGui libraries for the supported boards
foreach(BOARD_OPTIONS_FILE ${MXGUI_BOARDS_OPTIONS_FILES})
add_mxgui_library(${BOARD_OPTIONS_FILE})
endforeach()