RA8875 from Buydisplay

Status
Not open for further replies.
Thank you for your help.I'm getting this error, when I'm trying to compile

T4_RA8875_pictureEmbed:58: error: 'enable_layers' was not declared in this scope
if (enable_layers) tft.writeTo(layer);
^
T4_RA8875_pictureEmbed:113: error: 'enable_layers' was not declared in this scope
if (enable_layers)tft.layerEffect((layer == L1) ? LAYER1 : LAYER2);

Any idea why?
Thank you
 
I probably need to look at the layers stuff again at some point, but for example it can only work on 800x.. at 8 bits per pixel...
But did not appear to actually do it...

So in the test it was trying to use the two layers, update the display and then tell the display to switch to the other layer...

But I included the zip again.

Edit: Wonder if I should clean up slightly and add as example?
 

Attachments

  • T4_RA8875_pictureEmbed-200127a.zip
    484.1 KB · Views: 158
You Are a Genius !!!!!!
It Works !!!
Thank you !

One more think,
In old library (drawArray)), we had a option to change image location(x, y),
In this example, to move the image, I'm changing
uint16_t start_x
uint16_t start_y
but what If there is multiple images?
Please tell me, how I can have different coordinates, for multiple images?
Thank you
 
@momosh13 - Not sure if Genius, but simply someone who has been around the block a time or two. Again don't know what you mean by old library...

@mjs513 and ... Again at times I am not sure what to do with these semi-orphaned libraries.
As you know that a few of us are spending some time making this library work, plus actually getting several of our display drivers have reasonably compatible functionality.

But I have been thinking about maybe extracting some of the code in this sketch and maybe potentially maybe add it to RA8875 library
Probably with the same name and functionality as the method: void writeRect(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors);

which is in ILI9341_t3/n ST7735_t3/ST7789_t3, ILI9488_t3...

What the sketch currently does, that I don't believe these member functions do, is if you pass an an image that does not fit in the current orientation, but will in the other orientation, the sketch will rotate the image to fit...

I need to see what the other methods, do. They may simply clip...

With this API, it is up to the caller to figure out the proper X, Y to start drawing at. So if you want it centered you need to pass in:
(tft.width()-image_width)/2 ...

Does this make sense?
 
@mjs513 - I added writeRect
PR: https://github.com/mjs513/RA8875/pull/11

Branch: https://github.com/KurtE/RA8875/tree/write_rect

Updated sketch that uses it and cycles through rotations as well.


One difference so for from other versions of this api...
I currently call it like:
Code:
  tft.writeRect(start_x, start_y, image_width, image_height, image);

But in this case I could also have done it by:
Code:
 tft.writeRect(CENTER, CENTER, image_width, image_height, image);

I may next check to see if 8 bit color mode works and enables using layer...

EDIT: the new branch was screwed up... was based off of .070...
So closed PR, opened new one: https://github.com/mjs513/RA8875/pull/12

https://github.com/KurtE/RA8875/tree/write_rect_write_branch
 

Attachments

  • T4_RA8875_pictureEmbed-200128a.zip
    484.2 KB · Views: 121
Last edited:
Compiling error

Recently @KurtE and I have been working on a modification of the RA8875 library to use the ILI9xxx fonts and Adafruit GFX fonts. We have finished our initial implementation of modifications to the RA8875 library and the ILI9341_font library. Here are some screen shots for the ILI style fonts on the RA8875:
View attachment 18762View attachment 18763View attachment 18764

The updated RA8875 library is on the T4 branch: https://github.com/mjs513/RA8875/tree/RA8875_t4
The fonts are a slightly modified version of the PJRC's ILI9341_fonts library: https://github.com/mjs513/ILI9341_fonts

Feel free to give it a try.

Hello KurtE
I'm having compile error and here is what I'm doing.
1. downloaded and installed library from https://github.com/mjs513/RA8875/tree/RA8875_t4
2. trying compile example from ..\_Teensy3\ILI_Ada_FontTest\ILI_Ada_FontTest.ino
3. getting compile error "C:\Users\HPVIDEO\AppData\Local\Temp\arduino_modified_sketch_334801\ILI_Ada_FontTest.ino:6:41: fatal error: ili9488_t3_font_ComicSansMS.h: No such file or directory"

That is not right because there is ili9488_t3_font_ComicSansMS.h in fonts folder.

Any suggestion?
Thanks in advance.
 
Just looked at the current library at https://github.com/mjs513/RA8875/tree/RA8875_t4 and there is no ili9488_t3_font_ComicSansMS.h in the fonts folder. Unfortunately that particular example was not updated to work with the RA8875 display. That's on us, forgot to update it. It was an early development sketch that we used for initial testing.

However the ILI_Ada_FontTest's will work based on the quick review I just did as a double check. You will need to download the fonts library https://github.com/mjs513/ILI9341_fonts to use the additional fonts then you would just have to include as in the examples.
 
Hi mjs, Kurt, I like to use the Awesome fonts for my RA8875 from buydisplay, I noticed that there are fonts for the ILI9341 display ... Font_Awesome_F000 and how I can use them?
Thanks for helping,
Best,
Johan
 
You might take a look at the current example sketches that were added like: ILI_Aa_FontTest4 that is in the teensy... example sketches.


To use a bunch of the different fonts: @mjs513 has a version of the ILI9341 fonts library which is setup with several of the fonts and these are setup such that they can be included in several of our different display libraries.
https://github.com/mjs513/ILI9341_fonts


You simply need to include the font into your sketch: Something like:
#include "font_OpenSans.h"


You then need to say you wish to use that font: tft.setFont(OpenSans24);

Then you can do things like: tft.print("This is Open Sand 24");
 
@Mike,
It looks like something is wrong at my site ... when running my application the Awesome fonts type font_AwesomeF100.h are scrolling over my RA8875 display.
#include <font_AwesomeF100.h> No errors
tft.setFont(AwesomeF100_48);

In my buttons application : /* Button 0*/{60, 378, 110, 100, 20, 0x100, char(0xf011 ), WHITE, DKGREY, char(0xf011), WHITE, GREY, 0}, // Start stop DeepinScreenshot_select-area_20200301162945.jpg
 
This works fine in a fresh sketch. I think I must look at my application.
Thanks Mike!
/*
Explain the minimal setup and how to use instances...
*/

#include <SPI.h>
#include <RA8875.h>

/*
Teensy3.x
You are using 4 wire SPI here, so:
MOSI: 11
MISO: 12
SCK: 13
*/
#define RA8875_CS 20 //any digital pin
#define RA8875_RESET 255//any pin, if you wnat to disable just set at 255 or not use at all

/*
Teensy3.x has small difference since it can use alternative SPI pins,
essential if you want to use this library with Audio Shield.
You can set alternative SPI pins:
RA8875(CSpin,RSTpin=255,MOSI=11,SCLK=13,MISO=12);//the default configuration
To use with Audio shield:-------------------------------
CS: 2,20,21 because are not used by audio shield
MOSI:7
SCLK:14
RA8875(2,255,7,14);//will not interfere with Audio Shield
Teensy LC
This cpu can use slight different configuration, it can be instanced
with the CS pin only so it will use SPI0 but you can use this:
//RA8875(CSp,RSTp,mosi_pin,sclk_pin,miso_pin);
RA8875 tft = RA8875(RA8875_CS,RA8875_RESET,0,20,1);
This will use the SPI1 (24Mhz)
--------------------------------------------------------
To omit Reset pin, set as 255
For CS you CANNOT use arbitrary pin!
Teensy 3.x can use: 2,6,9,10,15,20,21,22,23
The shorter instance can be: RA8875(CSpin);
*/
RA8875 tft = RA8875(RA8875_CS,RA8875_RESET);//Teensy
//or
//RA8875 tft = RA8875(RA8875_CS);//Teensy (not using rst pin)
//or (for audio board)
//RA8875 tft = RA8875(RA8875_CS,RA8875_RESET,RA8875_MOSI,RA8875_SCLK);//Teensy using alternative SPI pin
//or
//RA8875 tft = RA8875(RA8875_CS,RA8875_RESET,RA8875_MOSI,RA8875_SCLK,RA8875_MISO);//Teensy using alternative SPI pin + alt miso
#include "font_AwesomeF100.h"
#include "font_AwesomeF000.h"

void setup()
{
Serial.begin(38400);
//long unsigned debug_start = millis ();
//while (!Serial && ((millis () - debug_start) <= 5000)) ;
Serial.println("RA8875 start");
/*
If you have an Adafruit RA8875 board + display choose:
Adafruit_480x272 , Adafruit_800x480
If you have any other display you have to choose:
RA8875_480x272 , RA8875_800x480
*/
tft.begin(RA8875_800x480);

/*
By default the library init display at 16bit color depth but
you can optionally force the display to work at 8 bit:

tft.begin(RA8875_480x272,8);//force 8bit color depth
*/

//Now that board it's inited you can use any draw or text command:
tft.setFont(AwesomeF000_48);
tft.setCursor(100,100);
tft.print(char(17 )); // power on icon
}
void loop()
{

}
 
Hi all,

For my hotplate controller and is made with a cheap RPI 9488 type display and a STM32 and works fine, I like to convert this to my fantastic RA8875 display but I use tft.drawBitmap but this is not available in the RA8875 is there a solution?

Thanks for help as always.

Best,
Johan
 
As you said there is no direct function call for tft.drawBitmap however, if you look at the SDfatTest example in the Teensy3 folder it will show you how to read a bmp from a SDCard and display it.

If you want to use bmp files encoded as arrays with PROGMEM you might check out the load2424bitimages example.

In both cases you are going to be reading in the pixels from a file or an array and then drawing the pixels to the screen. My guess is that the STM32 function drawBitmap is following that same basic flow.

Hope this helps
 
Hi Mile,

This not that easy I suppose please read below, is it not possible to use AdafruitGFX for the drawBitmap ?


// draw a button on the screen
Code:
void button(but bx){
  if (bx.draw == 1){// draw a button
    uint8_t byte0 = pgm_read_byte(&bx.bm[0]); // get the button symbol width
    uint8_t byte1 = pgm_read_byte(&bx.bm[1]); // get the button symbol height
    if (bx.in == 0){ //pushbutton
      tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.bacolor);                                              // draw the button background (background color)
      tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor);                                              // draw the button border
      //tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.color);     // draw the button symbol (symbol color)
    } else {
      if (bx.latch == 1){  //pushbutton colors inverted
        tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.color);                                              // draw the button background (symbol color)
        tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor);                                            // draw the button border
        //tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.bacolor); // draw the button symbol (background color)
      }
      if (bx.latch == 2){ //switch
        tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.bacolor);                                             // draw the button background (background color)
        tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor);                                             // draw the button border
        //tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.swcolor);  // draw the button symbol (switch color)
      }
    }
  }
}
 
Last edited by a moderator:
Morning
This not that easy I suppose please read below, is it not possible to use AdafruitGFX for the drawBitmap ?
Unless I have an old version of the adafruit RA8875 library I didn't see a drawBitmap function in their library. I did find a similar function to what I referenced. If you look at the ILI9488 drawBitmap function in the library
Code:
void ILI9488_t3::drawBitmap(int16_t x, int16_t y,
			      const uint8_t *bitmap, int16_t w, int16_t h,
			      uint16_t color) {

  int16_t i, j, byteWidth = (w + 7) / 8;

  for(j=0; j<h; j++) {
    for(i=0; i<w; i++ ) {
      if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
	drawPixel(x+i, y+j, color);
      }
    }
  }
}
its basically doing what was done in the load2424bitimages example as does the Adafruit GFX function:
Code:
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
                              int16_t w, int16_t h, uint16_t color) {
  int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  uint8_t byte = 0;
  startWrite();

  for (int16_t j = 0; j < h; j++, y++) {
    for (int16_t i = 0; i < w; i++) {
      if (i & 7)
        byte <<= 1;
      else
        byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
      if (byte & 0x80)
        writePixel(x + i, y, color);
    }
  }
  endWrite();
}
I would suppose we could add a similar function for drawBitmap. Haven't tried your example yet have to go dig out my RA8875 first.
 
The simple answer is probably no, to using drawBitmap.

Again it would not be that hard roll your own or add it to library.
That is it already has writeRect...

Several of our libraries have some other functions like:
Code:
void writeRect8BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette );

	// writeRect4BPP - 	write 4 bit per pixel paletted bitmap
	//					bitmap data in array at pixels, 4 bits per pixel
	//					color palette data in array at palette
	//					width must be at least 2 pixels
	void writeRect4BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette );
	
	// writeRect2BPP - 	write 2 bit per pixel paletted bitmap
	//					bitmap data in array at pixels, 4 bits per pixel
	//					color palette data in array at palette
	//					width must be at least 4 pixels
	void writeRect2BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette );
	
	// writeRect1BPP - 	write 1 bit per pixel paletted bitmap
	//					bitmap data in array at pixels, 4 bits per pixel
	//					color palette data in array at palette
	//					width must be at least 8 pixels
	void writeRect1BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette );

	// writeRectNBPP - 	write N(1, 2, 4, 8) bit per pixel paletted bitmap
	//					bitmap data in array at pixels
	//  Currently writeRect1BPP, writeRect2BPP, writeRect4BPP use this to do all of the work. 
	// 
	void writeRectNBPP(int16_t x, int16_t y, int16_t w, int16_t h,  uint8_t bits_per_pixel, 
		const uint8_t *pixels, const uint16_t * palette );
All of these could be written to work similar to the writeRect... Note: drawBitmap is more or less the 1BPP one above.

But again you could write your own quick and dirty (note it may not be quick ;) )

Code:
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
                              int16_t w, int16_t h, uint16_t color) {

  int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  uint8_t byte = 0;

  startWrite();
  for (int16_t j = 0; j < h; j++, y++) {
    for (int16_t i = 0; i < w; i++) {
      if (i & 7)
        byte <<= 1;
      else
        byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
      if (byte & 0x80)
        writePixel(x + i, y, color);
    }
  }
  endWrite();
}
Could convert to something as simple as:
Code:
void myDrawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
                              int16_t w, int16_t h, uint16_t color) {

  int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
  uint8_t byte = 0;

  for (int16_t j = 0; j < h; j++, y++) {
    for (int16_t i = 0; i < w; i++) {
      if (i & 7)
        byte <<= 1;
      else
        byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
      if (byte & 0x80)
        tft.drawPixel(x + i, y, color);
    }
  }
}
 
Last edited:
Hi Mike, Kurt,

For me a bit difficult can you look at the code and is it possible to adjust my code with your function see below.
Compile works but not the drawBitmap.
Thanks.


Code:
//#include <Adafruit_GFX.h>
//#include <Adafruit_SPITFT_Macros.h>
//#include <Adafruit_SPITFT.h>
//#include <gfxfont.h>

#include <Adafruit_MAX31856.h>   //Type K thermocouple module
//#include <ILI9486_SPI.h>         //RPI 3.5 inch tft
#include <SPI.h>
#include <RA8875.h>
#include <XPT2046_Touchscreen.h> //Touchscreen 12 bits
#include <PID_v1.h>              //PID controller
#include "symbols.h"             //Keyboard symbols
#include "Monospaced_plain_22.h" //Monospaced font
#include <EEPROM.h>

#define ms22_spacing 14

#define MAX_CS  36   // MAX31856 CS
#define MAX_DI  37  // MAX31856 DI
#define MAX_DO  38  // MAX31856 DO
#define MAX_CLK 39  // MAX31856 CLK

Adafruit_MAX31856 maxtemp = Adafruit_MAX31856(MAX_CS, MAX_DI, MAX_DO, MAX_CLK); 


#define TFT_CS 20 // RPI display CS
#define TFT_DC 18 // RPI display DC
// SCK = PA5, MISO = PA6, MOSI = PA7, RST = +3V3

//ILI9486_SPI tft(/*CS=4*/ TFT_CS, /*DC=*/ TFT_DC, /*RST=*/ 0);


#define RA8875_RESET 255    //Not used
#define RA8875_CS 20
RA8875 tft = RA8875(RA8875_CS, RA8875_RESET, 11, 13, 12);   // 11=MOSI   13=SCLK   12=MISO  10=CS
#define CS_PIN  2 // Touchscreen CS
// SCK = PA5, MISO = PA6, MOSI = PA7

XPT2046_Touchscreen ts(CS_PIN);

// These are the default min and maximum values, set between 0 and 4095 (12 bit)
#define HMIN 230
#define HMAX 3930
#define VMIN 230
#define VMAX 3830

#define WIDTH 800  // Default screen resulution for X axis
#define HEIGHT 480 // Default screen resulution for Y axis
#define BUTTONW 80 // Default button resulution for X axis
#define BUTTONH 80 // Default button resulution for X axis

#define HEATER_PIN  3 //Heater output pin
#define FAN_PIN  4    //Fan output pin
#define BUZZER_PIN 5  //Buzzer output pin (option)


#define LTBLUE    0xB6DF
#define LTTEAL    0xBF5F
#define LTGREEN   0xBFF7
#define LTCYAN    0xC7FF
#define LTRED     0xFD34
#define LTMAGENTA 0xFD5F
#define LTYELLOW  0xFFF8
#define LTORANGE  0xFE73
#define LTPINK    0xFDDF
#define LTPURPLE  0xCCFF
#define LTGREY    0xE71C
#define BLUE      0x001F
#define MDBLUE    0x0016
#define TEAL      0x0438
#define GREEN     0x07E0
#define MDGREEN   0x05E0
#define CYAN      0x07FF
#define RED       0xF800
#define MDRED     0xC800
#define MAGENTA   0xF81F
#define YELLOW    0xFFE0
#define ORANGE    0xFC00
#define PINK      0xF81F
#define PURPLE    0x8010
#define GREY      0xC618
#define MDGREY    0x94B2
#define WHITE     0xFFFF
#define BLACK     0x0000
#define DKBLUE    0x000D
#define DKTEAL    0x020C
#define DKGREEN   0x03E0
#define DKCYAN    0x03EF
#define DKRED     0x6000
#define DKMAGENTA 0x8008
#define DKYELLOW  0x8400
#define DKORANGE  0x8200
#define DKPINK    0x9009
#define DKPURPLE  0x4010
#define DKGREY    0x4A49

uint16_t backcolor = BLUE;      // color of display background
uint16_t txtcolor = WHITE;      // color of text on display
uint16_t bordercolor = BLACK;   // color of borders and lines
uint16_t trendcolor = CYAN;     // color of trenline
uint16_t rastcolor = MDGREY;     // color of the raster lines



int screen = 0;                         // screen = 0 is main screen     screen = 1 is setup screen
int butnr =999;                         // number of touched button
int recipenr = 1;                       // start with recipe number one
int oldrecipenr = 1;                    // start with recipe number one
char rcptxt[6][11]={"          ", "    SAC305", " LEAD_FREE", "    LEADED", "    CURVE1", "    CURVE2"};
//String rcptxt[6];                       // The name of the reflow curve
uint8_t rptxt[6][7];                    // The reflow zone the oven can be in (Stopped, Preheat, Soak, etc)
String rptext = "Stopped";              // The actual reflow zone the oven is in
String oldrptext = "Stopped";           // The actual reflow zone the oven is in
uint8_t xv[480];                        // temperature values
uint16_t T[6][7];                       // recipes temperature --- 5 recipes ---- 6 points per recipe
uint16_t m[6][7];                       // recipes time --- 5 recipes ---- 6 points per recipe
int mt;                                 // calculated total time trend x-axes
int Tt;                                 // highest temoperatuur y-axes
int startcurve = 0;                     // 0 if the curve is not running -- 1 if the curve is running.
int pointcounter = 0;                   // The current point in a recipe
int cur = 2;                            // The current parameter
int valinit = 0;                        // valinit = 0 --- reprint the complete editor window on the setup screen (screen 1)    valinit = 1 --- print only the changes
int redrtop = 1;                        // TRUE if the drawstring text should be completely redrawn
String valuestrm[6];                    // temporarily variable to hold the new recipe values of the current recipe
String valueoldstrm[6];                 // temporarily variable to hold the previous recipe values of the current recipe
String valuestrT[6];                    // temporarily variable to hold the new recipe values of the current recipe
String valueoldstrT[6];                 // temporarily variable to hold the previous recipe values of the current recipe
String valuestrtxt[6];                  // temporarily variable to hold the new recipe values of the current recipe
String valueoldstrtxt[6];               // temporarily variable to hold the previous recipe values of the current recipe
int btnr = 999;                         // Holds the pressed butten number  999 no button is pressed
int blocked = 0;                        // 0 = one puls button         1 = repeat puls button
int starttimer = 0;                     // start the timer for the repeat puls button. If you hold the button longer, the repeatfrequence goes up.
double rate = 1;                        // temperature rise per second
int tchd = 0;                           // 1 if the touchscreen is touched
int elapsedtime = 0;                    // elapsed time between steps in the temperature curve
int stepcounter = 0;                    // next step in the recipecurve
int curtemp, curtemp2;
int rtxtcur = 0;                        // recipe text cursor
int scrltxt = 0;

String zonetxt[6] = {"Stopped", "Preheat", "Soak", "Prereflow", "Reflow", "Cool"};
int maxvaluem[6] = {350, 350, 350, 350, 350, 350}; // maximum adjustable time value
int maxvalueT[6] = {350, 350, 350, 350, 350, 350}; // maximum adjustable temperature value
int xcursor[18] = {0, 0, 241, 20, 123, 216, 20, 123, 216, 20, 123, 216, 20, 123, 216, 20, 123, 216, };        // place of the cursor in the editor window
int ycursor[18] = {0, 0, 20, 110, 110, 110, 135, 135, 135, 160, 160, 160, 185, 185, 185, 210, 210, 210};    // place of the cursor in the editor window
int alphabet[38] = {32, 45, 48, 49, 50, 51, 52, 53, 54, 55 ,56 ,57, 65, 66 ,67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77 ,78, 79 ,80, 81, 82, 83, 84, 85 ,86 ,87 ,88 ,89 ,90};
int alphabetconv[59] = {0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};

//trend variables
int ybegin = 35;
int yend = 215;
int xbegin = 30;
int xend = 450;
int tempdiv = 50;
int timediv = 60;

double temperature, oldtemperature; // heater temperature
double sp = 0;                      // PID running setpoint
double Setpoint;                    // PID end setpiont
double Input;                       // PID input(heater temperature)
double Output;                      // PID output(heater power)

struct but {                // button parameters
  uint8_t draw;             // 1 draw the button    0 draw an empty space
  uint16_t x;               // button x coordinate
  uint16_t y;               // button y coordinate
  const uint8_t *bm;        // button image name
  uint16_t w;               // button width
  uint16_t h;               // button height
  uint16_t color;           // button symbol color
  uint16_t swcolor;         // button active symbol color
  uint16_t bacolor;         // button background color
  uint16_t bocolor;         // button border color
  uint8_t latch;            // 0 push button    1 color inverted pushbutton    2 switch
  uint8_t in;               // 0 button is released   1 button is in
  uint8_t repeat;           // 0 repeat puls button   1 single puls button
};

//int buttons=10; // number of buttons 
but scr[11]={ // button array to draw the buttons
  {1, 0, 240, homesymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,1},
  {1, 80, 240, fansymbol, BUTTONW, BUTTONH, MDGREY, GREEN, backcolor, bordercolor, 2,0,1},
  {1, 160, 240, backwardsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
  {1, 240, 240, forwardsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
  {1, 320, 240, heatersymbol, BUTTONW, BUTTONH, MDGREY, GREEN, backcolor, bordercolor, 2,0,1},
  {1, 400, 240, onoffsymbol, BUTTONW, BUTTONH, txtcolor, GREEN, backcolor, bordercolor, 2,0,1},
  {1, 400, 0, rightsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
  {1, 400, 80, upsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
  {1, 400, 160, downsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
  {1, 0, 240, gearsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,1},
  {1, 400, 240, rightrightsymbol, BUTTONW, BUTTONH, txtcolor, WHITE, backcolor, bordercolor, 0,0,0},
};

int scr0but[7] = {0, 1, 2, 3, 4, 5};
int scr1but[10] = {1, 2, 3, 4, 6, 7, 8, 9, 10};

// define text instead of numbers for the buttons
#define gear 0
#define fan 1
#define backward 2
#define forward 3
#define heater 4
#define onoff 5
#define right 6
#define up 7
#define down 8
#define home 9
#define tab 10

unsigned long windowStartTime;
int WindowSize = 2000; // output limit for the PID controller

unsigned long meastime = 0;
int measwindow = 1000; //time in ms temperature measurement

unsigned long touchtime = 0;
int touchwindow = 0; //time in ms button touch delay

unsigned long drawtime = 0;
int drawwindow = 1000;




//Specify the links and initial tuning parameters
//double Kp=2, Ki=5, Kd=1;
double Kp=100, Ki=5, Kd=1;
PID myPID(&Input, &Output, &sp, Kp, Ki, Kd, DIRECT);



void setup()
{
  //disableDebugPorts(); //Release PB4 (FAN_PIN) so we can used it as an output

  tft.begin(RA8875_800x480);
  tft.setRotation(0);
  pinMode(HEATER_PIN, OUTPUT); 
  pinMode(FAN_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  windowStartTime = millis();
  myPID.SetOutputLimits(0, WindowSize);
  
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  
  Serial.begin(115200);
   
 
  //ts.begin();         // initialize the touchscreen
  //ts.setRotation(1);  // touchscreen the same as the tft

   uint16_t DataWrite = 11111;
  uint16_t AddressWrite = 0x10;
  uint16_t StatusInit;  
  uint16_t StatusRead;
  uint16_t StatusWrite;
  uint16_t Data;
  //delay(3000);
  //StatusInit = EEPROM.init();
  //delay(3000);
  //EEPROM.PageBase0 = 0x801F000;
  //EEPROM.PageBase1 = 0x801F800;
  //EEPROM.PageSize  = 0x800;
  //StatusRead = EEPROM.read(AddressWrite, &Data);
  if (Data != 11111){
    //StatusWrite = EEPROM.write(AddressWrite, DataWrite);
    
    // pre set recipes
    // SAC305
    T[1][0]  = 0;   m[1][0]  =  0; rptxt[1][0] = 0;
    T[1][1]  = 150; m[1][1]  = 90; rptxt[1][1] = 1;
    T[1][2]  = 175; m[1][2]  = 90; rptxt[1][2] = 2;
    T[1][3]  = 217; m[1][3]  = 30; rptxt[1][3] = 3;
    T[1][4]  = 249; m[1][4]  = 30; rptxt[1][4] = 4;
    T[1][5]  = 217; m[1][5]  = 30; rptxt[1][5] = 4;
    T[1][6]  = 20;  m[1][6]  = 90; rptxt[1][6] = 5;

    // Lead-Free
    T[2][0]  =   0; m[2][0]  =  0; rptxt[2][0] = 0;
    T[2][1]  = 150; m[2][1]  = 90; rptxt[2][1] = 1;
    T[2][2]  = 200; m[2][2]  = 90; rptxt[2][2] = 2;
    T[2][3]  = 245; m[2][3]  = 45; rptxt[2][3] = 4;
    T[2][4]  = 200; m[2][4]  = 45; rptxt[2][4] = 4;
    T[2][5]  =  20; m[2][5]  = 90; rptxt[2][5] = 5;
    T[2][6]  =  20; m[2][6]  =  0; rptxt[2][5] = 5;
  
    // Leaded
    T[3][0]  =   0; m[3][0]  =  0; rptxt[3][0] = 0;
    T[3][1]  = 150; m[3][1]  = 90; rptxt[3][1] = 1;
    T[3][2]  = 180; m[3][2]  = 90; rptxt[3][2] = 2;
    T[3][3]  = 219; m[3][3]  = 30; rptxt[3][3] = 4;
    T[3][4]  = 180; m[3][4]  = 30; rptxt[3][4] = 4;
    T[3][5]  =  20; m[3][5]  = 90; rptxt[3][5] = 5;
    T[3][6]  =  20; m[3][6]  =  0; rptxt[3][5] = 5;
  
    // reflow curve
    T[4][0]  =   0; m[4][0]  =  0; rptxt[4][0] = 0;
    T[4][1]  = 150; m[4][1]  = 90; rptxt[4][1] = 1;
    T[4][2]  = 180; m[4][2]  = 90; rptxt[4][2] = 2;
    T[4][3]  = 219; m[4][3]  = 30; rptxt[4][3] = 4;
    T[4][4]  = 180; m[4][4]  = 30; rptxt[4][4] = 4;
    T[4][5]  =  20; m[4][5]  = 90; rptxt[4][5] = 5;
    T[4][6]  =  20; m[4][6]  =  0; rptxt[4][5] = 5;
  
    // reflow curve
    T[5][0]  =   0; m[5][0]  =  0; rptxt[5][0] = 0;
    T[5][1]  = 150; m[5][1]  = 90; rptxt[5][1] = 1;
    T[5][2]  = 180; m[5][2]  = 90; rptxt[5][2] = 2;
    T[5][3]  = 219; m[5][3]  = 30; rptxt[5][3] = 4;
    T[5][4]  = 180; m[5][4]  = 30; rptxt[5][4] = 4;
    T[5][5]  =  20; m[5][5]  = 90; rptxt[5][5] = 5;
    T[5][6]  =  20; m[5][6] =  0;  rptxt[5][5] = 5;

    store();
  } else {
    T[1][0]  = 0;   m[1][0]  =  0; rptxt[1][0] = 0;

    // Lead-Free
    T[2][0]  =   0; m[2][0]  =  0; rptxt[2][0] = 0;
  
    // Leaded
    T[3][0]  =   0; m[3][0]  =  0; rptxt[3][0] = 0;
  
    // reflow curve
    T[4][0]  =   0; m[4][0]  =  0; rptxt[4][0] = 0;
  
    // reflow curve
    T[5][0]  =   0; m[5][0]  =  0; rptxt[5][0] = 0;
    
    for (int ir = 1; ir <= 5; ir++){
      for (int iz = 1; iz <= 6; iz++){
        AddressWrite = AddressWrite + 16;
        //StatusRead = EEPROM.read(AddressWrite, &Data);
        T[ir][iz] = Data;
      }
    }
    for (int ir = 1; ir <= 5; ir++){
      for (int iz = 1; iz <= 6; iz++){
        AddressWrite = AddressWrite + 16;
        //StatusRead = EEPROM.read(AddressWrite, &Data);
        m[ir][iz] = Data;
      }
    }
    for (int ir = 1; ir <= 5; ir++){
      for (int iz = 1; iz <= 6; iz++){
        AddressWrite = AddressWrite + 16;
        //StatusRead = EEPROM.read(AddressWrite, &Data);
        rptxt[ir][iz] = Data;
      }
    }
    for (int ir = 1; ir < 5; ir++){
      for (int iz = 0; iz < 9; iz=iz+2){
        AddressWrite = AddressWrite + 16;        
        //StatusRead = EEPROM.read(AddressWrite, &Data);
        rcptxt[ir][iz+1] = Data/256;
        rcptxt[ir][iz] = Data - rcptxt[ir][iz+1]*256;

      }     
    }
     
  }
  //StatusRead = EEPROM.read(AddressWrite, &Data);


  recalc();

   tft.fillWindow(BLACK);
  tft.setTextColor(txtcolor, backcolor);
  tft.setFont(&Monospaced_plain_22);
    
  maxtemp.begin();    // initialize the temperature measure unit

  drawbuttons(0);                                         // Place the buttons on the bottom of the screen (parameter = 0)
  tft.drawRect(0, 0, WIDTH, HEIGHT-BUTTONH, bordercolor); // Place a rectangle above the buttons on screen 0
  drawaxes();                                             // Draw the vertical and horizontal axes and the raster on screen 0
  drawtraceline();                                        // Draw the recipe 0 trace line on screen 0
  reflowtext(1);                                          // Draw the current reflow zone text on the left top of the screen
  recipetext(1, 335);                                     // draw the recipe name on the right top of the screen

}

void loop() {

  // measure temperature and chang setpoint
  unsigned long measnow = millis();
  if (measnow - meastime > measwindow) {
    meastime = measnow;
    
    oldtemperature = temperature;                          // save the previous temperature
    temperature = maxtemp.readThermocoupleTemperature();   // read the new temperature
    Setpoint = T[recipenr][stepcounter + 1];               // read the first step end setpoint
    
    drawString(redrtop, 110, 20, ms22_spacing, 8, String(oldtemperature) + "C", String(temperature) + "C", 1, txtcolor, backcolor, Monospaced_plain_22); // print the new temperature at the top of the screen
    if (redrtop == 1){redrtop = 0;} // next time only redraw the changes

    if (rate >= 0 && temperature > Setpoint){// if the temperature goes from a lower to a higher setpoint and the setpoint is reached
      if (stepcounter < 5){
        oldrptext = zonetxt[rptxt[recipenr][stepcounter]]; // save the old reflow zone text
        stepcounter++;                                     // go to the next step
        elapsedtime = 0;                                   // reset the elapsed step time
        rptext = zonetxt[rptxt[recipenr][stepcounter]];    // get the new reflow zone text
        reflowtext(1);                                     // print the new reflow zone text at th left top of the screen
      }
    }
    if (rate < 0  && temperature < Setpoint){// if the temperature goes from a higher to a lower setpoint and the setpoint is reached
      if (stepcounter < 5){
        oldrptext = zonetxt[rptxt[recipenr][stepcounter]]; // save the old reflow zone text
        stepcounter++;                                     // go to the next step
        elapsedtime = 0;                                   // reset the elapsed step time
        rptext = zonetxt[rptxt[recipenr][stepcounter]];    // get the new reflow zone text
        reflowtext(1);                                     // print the new reflow zone text at th left top of the screen
      }
    }
    if(startcurve == 1){
      rate = (T[recipenr][stepcounter + 1] - temperature) / (m[recipenr][stepcounter + 1] - elapsedtime); // recalculate the rate (pos or neg rise in degrees per second) 
      if (elapsedtime < m[recipenr][stepcounter + 1] - 1){elapsedtime++;}                  // if the total time between steps is not reached, increase the elapsed time
      if (rate >= 0 && sp < Setpoint) {sp = sp + rate; if (sp > Setpoint){sp = Setpoint;}} // increase the sp with the positive rate until the setpoint is reached
      if (rate < 0  && sp > Setpoint) {sp = sp + rate; if (sp < Setpoint){sp = Setpoint;}} // increase the sp with the negative rate until the setpoint is reached
    }
  }

  // draw reflowcurve
  unsigned long drawnow = millis();
  if (drawnow - drawtime > drawwindow) {
    drawtime = drawnow;
    drawreflowcurve(); // redraw the temperature curve
  }

  // button touch delay
  unsigned long touchnow = millis();
  if (touchnow - touchtime > touchwindow) {
    touchtime = touchnow;
    readbutton();         // check if, and which button is pressed
    if(screen == 1) {editrecipe(recipenr);} //print the edit recipe window on screen 1
    if (starttimer == 1){touchwindow = touchwindow - 40; if(touchwindow < 0){touchwindow = 0;}}  // if a repeat puls button is still pressed, lower the repeat time
  }
  Input = temperature; // connect the current temperature to the PID controller
  myPID.Compute();     // recompute the PID output

  if (millis() - windowStartTime > WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if (Output < millis() - windowStartTime) {digitalWrite(HEATER_PIN, LOW);} else { digitalWrite(HEATER_PIN, HIGH);} // send the PID output(0 or 1) to the heater

}

void recalc(){ // function to recalculate the trend time and temperature scale
  mt = m[recipenr][0]+m[recipenr][1]+m[recipenr][2]+m[recipenr][3]+m[recipenr][4]+m[recipenr][5]+m[recipenr][6];
  Tt = 0; for (int i = 1; i <= 6; i++) {if (Tt < T[recipenr][i]){Tt = T[recipenr][i];}}
  mt = (mt+timediv-1)/timediv; // calculate the next rounded time value on the scale
  Tt = (Tt+tempdiv-1)/tempdiv; // calculate the next rounded temperature value on the scale
  drawwindow = (mt*timediv*1000)/(xend-xbegin);// calculate the redraw time interval per pixel
  
}

void fan_onoff(int pos){ // switch the fan on or off
  if (pos == 0){//fan off
    switchbutton(fan, 0); // switch the fan button symbol off
    digitalWrite(FAN_PIN, LOW); // switch the fan output off
  }
  if (pos == 1){//fan on
    switchbutton(fan, 1); // switch the fan button symbol on
    digitalWrite(FAN_PIN, HIGH); // switch the fan output on
  }
}

void buzzer_onoff(int pos){ // switch the buzzer on or off
  if (pos == 0){//buzzer off
    digitalWrite(BUZZER_PIN, LOW); // switch the buzzer output off
  }
  if (pos == 1){//buzzer on
    digitalWrite(BUZZER_PIN, HIGH); // switch the buzzer output on
  }
}

void on_off(int pos){ // start or stop the reflow
  if (pos == 0){//off
    oldrptext = zonetxt[rptxt[recipenr][stepcounter+1]];    // save the old reflow zone text
    rptext = zonetxt[rptxt[recipenr][stepcounter]];         // get the new reflow zone text
    reflowtext(1);                                          // print the reflow zone text at the left top of the screen
    T[recipenr][0] = 0;                                     // make the first temperature of the recipe 0
    elapsedtime = 0;                                        // reset the elapsed time between zone steps
    stepcounter = 0;                                        // reset the zone step counter
    sp = 0;                                                 // set the sp (PID setpoint) to zero
    if(screen == 0){switchbutton(onoff, 0);}                // switch the onoff button symbol off
    scr[onoff].in = 0;                                      // Set the onoff button.in parameter to zero
    startcurve = 0;                                         // stop the reflow curve
    fan_onoff(1);                                           // Start the cooling fan
  }
  if (pos == 1){//on
    resettemperaturecurve();                                // reset the themperature curve array (make all the elements zero)
    
    oldrptext = zonetxt[rptxt[recipenr][stepcounter]];      // save the old reflow zone text
    rptext = zonetxt[rptxt[recipenr][stepcounter+1]];       // get the new reflow zone text
    rate = (T[recipenr][1] - temperature) / m[recipenr][1]; // calculate the first rate (rise in celcius per second)
    elapsedtime = 0;                                        // reset the elapsed time between zone steps
    stepcounter = 0;                                        // reset the zone step counter
    sp = temperature;                                       // set the sp (PID setpoint) to the current temperature
    T[recipenr][0] = sp;                                    // make the first temperature of the recipe the current temperature
    switchbutton(onoff, 1);                                 // switch the onoff button symbol on
    scr[onoff].in = 1;                                      // Set the onoff button.in parameter to one
    startcurve = 1;                                         // start the reflow curve
    fan_onoff(0);                                           // Stop the cooling fan
/*      screen = 0;
      fillScreen(backcolor);
      tft.setTextColor(txtcolor);
      drawbuttons(1);
      tft.drawRect(0, 0, WIDTH, HEIGHT-BUTTONH, bordercolor);
      recalc();
      drawaxes(); drawtraceline();
      reflowtext(1);
      recipetext(1, 350);
      redrtop = 1;*/
  }
}


void drawreflowcurve(){                                                        // draw the temperature trend
  if (startcurve == 1){                                                        // only draw if the reflow has started
    float pixelsgrd = (float(yend-ybegin) / (Tt*tempdiv)) * temperature;       // calculate te pixels corresponding with the temperature
    if (pixelsgrd > (yend-ybegin)){pixelsgrd = yend-ybegin;}                   // prefent the temperature from going off scale
    xv[pointcounter] = pixelsgrd;                                              // place the pixel value in the temperature array
    if (screen == 0){                                                          // only print the trend if the screen is the main screen
      for (int i = 0; i < (xend-xbegin); i++) {                                // redraw the whole trend every new point
        if (pixelsgrd > 0){tft.drawPixel(i+xbegin, yend - xv[i], trendcolor);} // only print a value if the temperature is larger then zero
      }
    }
    pointcounter++; if (pointcounter > xend-xbegin){pointcounter = 0;}         // set the pointer for the next value
  }
}

void drawaxes(){
  tft.setFont();
  int Ttpix = (yend - ybegin) / Tt;
  int mtpix = (xend - xbegin) / mt;
  tft.fillRect(0, ybegin-5, 480, yend-ybegin+28, backcolor);
  tft.drawLine(xbegin-1, ybegin, xbegin-1, yend+1, txtcolor);                                        // draw the vertical axes
  for (int i = 0; i <= Tt; i++) {
    if (i == Tt){tft.setCursor(xbegin-25, yend - i*Ttpix + Ttpix/2 - 4); tft.print("(C)");}          // print the temperature symbol in the trend
    drawString(1, xbegin-25, yend-i*Ttpix - 4, 6, 3, "", String(i*tempdiv), 1, txtcolor, backcolor, 1); // print the numbers next to the vertical axis
    tft.drawLine(xbegin - 6, yend-i*Ttpix , xbegin-1, yend-i*Ttpix, txtcolor);                       // print the division lines
  }
  tft.drawLine(xbegin-1, yend+1, xend, yend+1, txtcolor);                                            // draw the horizontal axes
  for (int i = 0; i <= mt; i++) {
    if (i == mt){tft.setCursor(xbegin + i*mtpix - mtpix/2 - 9, yend+10); tft.print("(sec)");}        // print the time symbol in the trend
    drawString(1, xbegin+i*mtpix - 9, yend+10, 6, 3, "", String(i*timediv), 1, txtcolor, backcolor, 1); // print the numbers below the horizontal axis
    tft.drawLine(xbegin+i*mtpix, yend+6 , xbegin+i*mtpix, yend+1, txtcolor);                         // print the division lines
  }
  drawraster(); // draw the raster lines
  tft.setFont(&Monospaced_plain_22);
}

void drawraster(){                                                          // draw the trend background and the rasterlines
  int Ttpix = (yend - ybegin) / Tt;                                         // pixels between two horizontal rasterlines
  int mtpix = (xend - xbegin) / mt;                                         // pixels between two vertical rasterlines
  tft.fillRect(xbegin, ybegin, xend-xbegin, yend-ybegin, BLACK);            // make a black trend background
  for (int i = 0; i <= Tt; i++) {
    tft.drawLine(xbegin, yend-i*Ttpix , xend, yend-i*Ttpix, rastcolor);     // draw the horizontal rasterlines
  }
  for (int i = 0; i <= mt; i++) {
    tft.drawLine(xbegin+i*mtpix, ybegin , xbegin+i*mtpix, yend, rastcolor); // draw the vertical rasterlines
  }
}

void drawtraceline(){                                                       // draw the recipe traceline in the trend
  int Ttot0 = 0; int Ttot1 = 0;
  int yrange = Tt*tempdiv; float pixpergrd = float(yend-ybegin)/yrange;
  int xrange = mt*timediv; float pixpersec = float(xend-xbegin)/xrange;
  for (int i = 1; i <= 6; i++) {
    Ttot0 = Ttot0 + m[recipenr][i-1]*pixpersec;
    Ttot1 = Ttot1 + m[recipenr][i]*pixpersec;
    tft.drawLine(xbegin + Ttot0, yend - T[recipenr][i-1]*pixpergrd, xbegin + Ttot1, yend - T[recipenr][i]*pixpergrd, GREY);
  }
}

void reflowtext(int tinit){
  drawString(tinit, 10, 20, ms22_spacing, 8, oldrptext, rptext, 0, txtcolor, backcolor, Monospaced_plain_22); // draw reflow zone text at the left top of the screen
}

void recipetext(int tinit, int pos){
  drawString(tinit, pos, 20, ms22_spacing, 10, rcptxt[oldrecipenr], rcptxt[recipenr], 1, txtcolor, backcolor, Monospaced_plain_22); // draw the recipe text at the right top of the screen
}

void fillScreen(int scolor){// fill the screen above the buttons at the bottom of the screen
  tft.fillRect(0, 0, WIDTH, HEIGHT-BUTTONH, scolor);
}

void drawString(int pinit, int px, int py, int pspacing, int plength, String oldpvalue, String pvalue, int pjust, uint16_t txtcol, uint16_t bckcol, const GFXfont &font){// draw a string or only the changes in a string on the screen
  //&font is the gfx font + fontsize 1
  tft.setFont(&font); tft.setTextSize(1);
  drawStringHelper(pinit, px, py, pspacing, plength, oldpvalue, pvalue, pjust, txtcol, bckcol);
}

void drawString(int pinit, int px, int py, int pspacing, int plength, String oldpvalue, String pvalue, int pjust, uint16_t txtcol, uint16_t bckcol, int fontsize){// draw a string or only the changes in a string on the screen
  //Is the standard font fontsize
  tft.setFont(); tft.setTextSize(fontsize);
  drawStringHelper(pinit, px, py, pspacing, plength, oldpvalue, pvalue, pjust, txtcol, bckcol);
}

void drawStringHelper(int pinit, int px, int py, int pspacing, int plength, String oldpvalue, String pvalue, int pjust, uint16_t txtcol, uint16_t bckcol){// draw a string or only the changes in a string on the screen

  // pinit = 0 prints only changed characters, pinit = 1 prints all the characters
  // px and py are the coordinates on the screen
  // pspacing is the character spacing
  // plength is de total length to print
  // oldpvalue, pvalue is the string to print
  // pjust = 0 is left justify, pjust = 1 is right justify
  // txtcol is the text color
  // bckcol is the text background color

  String spaces = "                    ";                                                  // used for adding spaces in right and left justify
  
  if (pjust == 0){// left justify
    pvalue = pvalue + String(spaces.substring(0, plength - pvalue.length()));              // add spaces to the right of the text until the string length = plength
    oldpvalue = oldpvalue + String(spaces.substring(0, plength - oldpvalue.length()));     // add spaces to the right of the text until the string length = plength
  }
  
  if (pjust == 1){// right justify
    pvalue = String(spaces.substring(0, plength - pvalue.length())) + pvalue;              // add spaces to the left of the text until the string length = plength
    oldpvalue = String(spaces.substring(0, plength - oldpvalue.length())) + oldpvalue;     // add spaces to the left of the text until the string length = plength
  }
  
  for (int i = 0; i < plength; i++) {
    if (pvalue.substring(i, i+1) != oldpvalue.substring(i, i+1) or pinit == 1){// Only print, if de characters in de string are different than in the old string or if pinit =1
      tft.setTextColor(bckcol);            // set the font color the same as the background to erase the old character
      tft.setCursor(px+i*pspacing, py);
      tft.print(oldpvalue.substring(i, i+1)); // erase the old character
      tft.setTextColor(txtcol);             // set the font color the same as the foreground to print the new character
      tft.setCursor(px+i*pspacing, py);
      tft.print(pvalue.substring(i, i+1));    // print the new character
    }
  }
}

void editrecipe(int rnr){
  // valinit = 0 --- reprint the complete editor window on the setup screen (screen 1)
  // valinit = 1 --- print only the changes since the last time it was printed 
    tft.setFont(&Monospaced_plain_22);
    tft.setTextColor(txtcolor);
    if (valinit == 0){ //Print the fixed texts at the top of the values
            tft.setCursor(10, 60); tft.print("Time(s)");
            tft.setCursor(123, 60); tft.print("Temp(C)");
            tft.setCursor(241, 60); tft.print("Zone");
    }
    for (int i = 1; i < 6; i++) {
        curtemp = cur/3; curtemp2 = cur-curtemp*3;
        if (curtemp2 == 0 || valinit == 0 || valinit == 2) {
          if (valinit == 1 || valinit == 2){valueoldstrm[i] = valuestrm[i];}                                       // save the time value from the parameter at the current position
          if (valinit == 0){valueoldstrm[i] = "";}                                                   // clear the old time value to make it different from the new time value
          valuestrm[i] = String(m[recipenr][i]);                                               // get the new time value from the recipe parameter
          drawString(0, 35, 85+i*25, ms22_spacing, 3, valueoldstrm[i], valuestrm[i], 1, txtcolor, backcolor, Monospaced_plain_22); // draw the new time value on the screen
        }
        
        if (curtemp2 == 1 || valinit == 0 || valinit == 2) {
          if (valinit == 1 || valinit == 2){valueoldstrT[i] = valuestrT[i];}                                         // save the temperature value from the parameter at the current position
          if (valinit == 0){valueoldstrT[i] = "";}                                                     // clear the old temperature value to make it different from the new temperature value
          valuestrT[i] = String(T[recipenr][i]);                                                 // get the new temperature value from the recipe parameter
         drawString(0, 148, 85+i*25, ms22_spacing, 3, valueoldstrT[i], valuestrT[i], 1, txtcolor, backcolor, Monospaced_plain_22);  // draw the new temperature value on the screen
        }

        if (curtemp2 == 2 || valinit == 0 || valinit == 2) {
          if (valinit == 1 || valinit == 2){valueoldstrtxt[i] = valuestrtxt[i];}                                         // save the temperature value from the parameter at the current position
          if (valinit == 0){valueoldstrtxt[i] = "";}                                                     // clear the old temperature value to make it different from the new temperature value
          valuestrtxt[i] = zonetxt[rptxt[recipenr][i]];                                                 // get the new temperature value from the recipe parameter
          drawString(0, 241, 85+i*25, ms22_spacing, 10, valueoldstrtxt[i], valuestrtxt[i], 0, txtcolor, backcolor, Monospaced_plain_22);  // draw the new temperature value on the screen
        }

}
valinit = 1;
}

// find the button number that is touched and change the looks of the touched button on the screen
int touchtft(){
  tchd = ts.touched();                       // 0 = not touched, 1 = touched
  if (tchd && btnr == 999){blocked = 0;}     // btnr == 999 is no button pressed, blocked = 0 is one puls button
  TS_Point p = ts.getPoint();                // get values from the touchscreen 
  uint16_t xxn, yyn; 
  btnr = 999;                                // reset the button nr.
    if (tchd) {                              // if touched
    uint16_t X_Raw = p.x;                    // get the raw x coordinate from the touchscreen (0-4095)
    uint16_t Y_Raw = p.y;                    // get the raw y coordinate from the touchscreen (0-4095)
    xxn = map(X_Raw, HMAX, HMIN, 0, WIDTH);  // convert the raw x coordinate to the screen width (0-480)
    yyn = map(Y_Raw, VMIN, VMAX, 0, HEIGHT); // convert the raw y coordinate to the screen height (0-320)

    if (screen == 0){ // the main screen
      for (int i = 0; i <= 6; i++) {
        int ii = scr0but[i];
        if (xxn >= scr[ii].x & xxn <= scr[ii].x+scr[ii].w & yyn >= scr[ii].y & yyn <= scr[ii].y+scr[ii].h){ // compare the touchscreen coordinates with the button coordinates
          btnr = ii; // if the coordinates match, save the button number
        }
      }
    }
    if (screen == 1){// the setup screen
      for (int i = 1; i <= 9; i++) {
        int ii = scr1but[i];
        if (xxn >= scr[ii].x & xxn <= scr[ii].x+scr[ii].w & yyn >= scr[ii].y & yyn <= scr[ii].y+scr[ii].h){ // compare the touchscreen coordinates with the button coordinates
          btnr = ii; // if the coordinates match, save the button number
        }
      }
    }
  }
  return btnr;
}

void resettemperaturecurve(){// make every element of the temperature array zero
  for (int i = 0; i < 480; i++) {
    xv[i]=0;
  }
  pointcounter = 1; // reset the pointcounter
  sp = 0;           // reset the PID setpoint to zero
}

void readbutton(){
  
  butnr = touchtft(); // get the button number from the touchscreen
  
  if (blocked == 0 && btnr != 999 ){
    switchbutton(btnr, 2);

    if (scr[butnr].repeat == 1){blocked = 1;}
    if (blocked == 0){if (starttimer == 0){touchwindow = 500;} starttimer = 1;}
    tft.setFont(&Monospaced_plain_22);

    if (butnr == gear){ // setup
      valinit = 0;
      screen = 1;
      fillScreen(backcolor);
      tft.setTextColor(txtcolor);
      drawbuttons(1);
      tft.drawRect(0, 0, WIDTH-BUTTONW, HEIGHT-BUTTONH, bordercolor);
      tft.setCursor(xcursor[cur], ycursor[cur]); tft.print(">");
      reflowtext(1);
//      if (screen == 0){recipetext(1, 350);}
//      if (screen == 1){recipetext(1, 270);}
      recipetext(1, 255);
      redrtop = 1;
      butnr = 999;
      rtxtcur = 0;
      scrltxt = alphabetconv[int(rcptxt[recipenr][rtxtcur])-32];
      drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 2, "- ", " -", 1, txtcolor, backcolor, Monospaced_plain_22);
    }
    if (butnr == backward){ // backward
      store();
      if (recipenr > 1){
        oldrecipenr = recipenr;
        recipenr--;
        valinit = 2;
        recalc();
        resettemperaturecurve();
        on_off(0);
        if (screen == 0){drawaxes(); drawtraceline();}
        if (screen == 0){recipetext(1, 335);}
        if (screen == 1){recipetext(1, 255);}
      }
    }
    if (butnr == forward){ // forward
      store();
      if (recipenr < 5){
        oldrecipenr = recipenr;
        recipenr++;
        valinit = 2;
        recalc();
        resettemperaturecurve();
        on_off(0);
        if (screen == 0){drawaxes(); drawtraceline();}
        if (screen == 0){recipetext(1, 335);}
        if (screen == 1){recipetext(1, 255);}
      }
    }
    if(butnr == fan){ // down
      fan_onoff(scr[butnr].in);
    }
    if (butnr == onoff){ // onoff
      startcurve = scr[butnr].in;
      on_off(startcurve);
    }

    if(butnr == home){ // home
      store();
      screen = 0;
      fillScreen(backcolor);
      tft.setTextColor(txtcolor);
      tft.drawRect(0, 0, WIDTH, HEIGHT-BUTTONH, bordercolor);
      recalc();
      drawbuttons(0);
      drawaxes(); drawtraceline();
      reflowtext(1);
//      if (screen == 0){recipetext(1, 350);}
//      if (screen == 1){recipetext(1, 270);}
      recipetext(1, 335);
      redrtop = 1;
    }
    if(butnr == tab){ // tab
      tft.setTextColor(backcolor, backcolor); tft.setCursor(xcursor[cur], ycursor[cur]); tft.print(">");
      cur=cur+1; if (cur > 17){cur = 2;}
      tft.setTextColor(txtcolor, backcolor); tft.setCursor(xcursor[cur], ycursor[cur]); tft.print(">");
      if (cur == 2){
        rtxtcur = 0;
        scrltxt = alphabetconv[int(rcptxt[recipenr][rtxtcur])-32];
        drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 2, "- ", " -", 1, txtcolor, backcolor, Monospaced_plain_22);
      }
      if (cur == 3){
        drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 2, " -", "", 1, txtcolor, backcolor, Monospaced_plain_22);
      }
    }
    if(butnr == right){ // right
      rtxtcur++; if (rtxtcur > 9){rtxtcur = 0; drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 11, "-", " ", 1, txtcolor, backcolor, Monospaced_plain_22);}
      scrltxt = alphabetconv[int(rcptxt[recipenr][rtxtcur])-32];
      drawString(1, 241+rtxtcur*ms22_spacing, 30, ms22_spacing, 2, "- ", " -", 1, txtcolor, backcolor, Monospaced_plain_22);
     }
    if(butnr == up){ // up
      if (scr[onoff].in == 1){scr[onoff].in = 0; startcurve = scr[onoff].in; on_off(startcurve);}
      
      if (ycursor[cur]>25){
        curtemp = cur/3; curtemp2 = cur-curtemp*3;
        if(curtemp2 == 0){ // time
          if(m[recipenr][curtemp] < maxvaluem[curtemp]){
            m[recipenr][curtemp]++;
          }
        }
        if(curtemp2 == 1){ // temperature
          if(T[recipenr][curtemp] < maxvalueT[curtemp]){
            T[recipenr][curtemp]++;
          }
        }
        if(curtemp2 == 2){ // temperature
          if(rptxt[recipenr][curtemp] < 5){
            rptxt[recipenr][curtemp]++;
          }
        }
      }else{
        String rcptxtemp = String(rcptxt[recipenr]);
        scrltxt++; if(scrltxt>37){scrltxt=0;}
        rcptxt[recipenr][rtxtcur] = alphabet[scrltxt];
        drawString(0, 255, 20, ms22_spacing, 10, rcptxtemp, String(rcptxt[recipenr]), 1, txtcolor, backcolor, Monospaced_plain_22);
      }
    }
    if(butnr == down){ // down
      if (scr[onoff].in == 1){scr[onoff].in = 0; startcurve = scr[onoff].in; on_off(startcurve);}
      
      if (ycursor[cur]>25){
        curtemp = cur/3; curtemp2 = cur-curtemp*3;
        if(curtemp2 == 0){ // time
          if(m[recipenr][curtemp] > 0){
            m[recipenr][curtemp]--;
          }
        }
        if(curtemp2 == 1){ // temperature
          if(T[recipenr][curtemp] > 0){
            T[recipenr][curtemp]--;
          }
        }
        if(curtemp2 == 2){ // temperature
          if(rptxt[recipenr][curtemp] >0){
            rptxt[recipenr][curtemp]--;
          }
        }
      }else{
        String rcptxtemp = String(rcptxt[recipenr]);
        scrltxt--; if(scrltxt<0){scrltxt=37;}
        rcptxt[recipenr][rtxtcur] = alphabet[scrltxt];
        drawString(0, 255, 20, ms22_spacing, 10, rcptxtemp, String(rcptxt[recipenr]), 1, txtcolor, backcolor, Monospaced_plain_22);
      }
    }
 

  }else{starttimer = 0; touchwindow = 0;}
}

void switchbutton(int btnr, int mod){
  if (btnr<999 & scr[btnr].latch==0){button(scr[btnr]); button(scr[btnr]);}// switch button form positive to negative and back to positive (pushbutton)
  if (btnr<999 & scr[btnr].latch>0){
    if (mod == 0) {scr[btnr].in = 0; button(scr[btnr]);}  // button = off
    if (mod == 1) {scr[btnr].in = 1; button(scr[btnr]);}  // button = on
    if (mod == 2) {
      scr[btnr].in = 1 - scr[btnr].in; button(scr[btnr]); // toggle button
    }
  }
}

void drawbuttons(int part){
    if (part == 0 & screen == 0){button(scr[9]); for (int i = 1; i <= 5; i++) {button(scr[i]);}}  // draw only the bottom row buttons
    if (part == 0 & screen == 1){for (int i = 0; i <= 5; i++) {button(scr[i]);};}                   // draw only the left bottom row button (Home)
    if (part == 1 & screen == 1){for (int i = 6; i <= 8; i++) {button(scr[i]);} button(scr[10]);} // draw the three right side butons
}

// draw a button on the screen
void button(but bx){
  if (bx.draw == 1){// draw a button
    uint8_t byte0 = pgm_read_byte(&bx.bm[0]); // get the button symbol width
    uint8_t byte1 = pgm_read_byte(&bx.bm[1]); // get the button symbol height
    if (bx.in == 0){ //pushbutton
      tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.bacolor);                                              // draw the button background (background color)
      tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor);                                              // draw the button border
      //tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.color);     // draw the button symbol (symbol color)
    } else {
      if (bx.latch == 1){  //pushbutton colors inverted
        tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.color);                                              // draw the button background (symbol color)
        tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor);                                            // draw the button border
        //tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.bacolor); // draw the button symbol (background color)
      }
      if (bx.latch == 2){ //switch
        tft.fillRect(bx.x, bx.y, bx.w, bx.h, bx.bacolor);                                             // draw the button background (background color)
        tft.drawRect(bx.x, bx.y, bx.w, bx.h, bx.bocolor);                                             // draw the button border
        //tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.swcolor);  // draw the button symbol (switch color)
      }
    }
  }
}

void store(){
  //drawBitmap DataWrite;
  uint16_t AddressWrite = 0x10;
  uint16_t StatusWrite;
 
  for (int ir = 1; ir <= 5; ir++){
    for (int iz = 1; iz <= 6; iz++){
      AddressWrite = AddressWrite + 16;
      //DataWrite = T[ir][iz];
      //StatusWrite = EEPROM.write(AddressWrite, DataWrite);        
    }
  }
  for (int ir = 1; ir <= 5; ir++){
    for (int iz = 1; iz <= 6; iz++){
      AddressWrite = AddressWrite + 16;
      //DataWrite = m[ir][iz];
      //StatusWrite = EEPROM.write(AddressWrite, DataWrite);        
    }
  }
  for (int ir = 1; ir <= 5; ir++){
    for (int iz = 1; iz <= 6; iz++){
      AddressWrite = AddressWrite + 16;
      //DataWrite = rptxt[ir][iz];
      //StatusWrite = EEPROM.write(AddressWrite, DataWrite);   
    }     
  }
  for (int ir = 1; ir < 5; ir++){
    for (int iz = 0; iz < 9; iz=iz+2){
      AddressWrite = AddressWrite + 16;        
      //DataWrite = rcptxt[ir][iz]+rcptxt[ir][iz+1]*256;
     // StatusWrite = EEPROM.write(AddressWrite, DataWrite);   
    }     
  }
}
 
Last edited by a moderator:
Note: I put code tags around your code to make it easier to read.... It is the # button in the toolbar...

Did you try simply pasting in the function I mentioned?

And change your commented out calls like:
Code:
       //tft.drawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.swcolor);  // draw the button symbol (
to simply be:
Code:
       mydrawBitmap(bx.x+(bx.w-byte0)/2, bx.y+(bx.h-byte1)/2, bx.bm+2, byte0, byte1, bx.swcolor);  // draw the button symbol (

Note: sometimes Arduino does not always generate the proper forward reference so you might need a definition for it some where earlier up in sketch before first call.

Also note sometimes when typing stuff in on the fly there could be minor typos, like the my function should have the void return value at start...

Code:
extern void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color);
 
This is going to sound funny but where are you defining the bitmaps for the buttons? Looks like the bitmap names are in your scr array but don't see how it gets there?
 
Status
Not open for further replies.
Back
Top