Demo of RA8875 TFT touch display on Freescale FRDM-K64F Forked from David Smart https://developer.mbed.org/users/WiredHome/

Dependencies:   RA8875 menu SDFileSystem mbed

Fork of PUB_RA8875_mPaint by David Smart

main.cpp

Committer:
unix_guru
Date:
2015-10-02
Revision:
5:3afc5780b966
Parent:
3:3b214426761d

File content as of revision 5:3afc5780b966:

/// mPaint is a simple drawing program, used to explore the touch
/// APIs of the RA8875 display library.
///
/// @note Copyright © 2015 by Smartware Computing, all rights reserved.
///     Individuals may use this application for evaluation or non-commercial
///     purposes. Within this restriction, changes may be made to this application
///     as long as this copyright notice is retained. The user shall make
///     clear that their work is a derived work, and not the original.
///     Users of this application and sources accept this application "as is" and
///     shall hold harmless Smartware Computing, for any undesired results while
///     using this application - whether real or imagined.
///
/// @author David Smart, Smartware Computing
//
// +----------------------------------------------------+
// | File Edit Pen Tools  [sample](o)[rrrr][gggg][bbbb] |
// +----------------------------------------------------+ 16
// |                                                    |
// |      canvas                                        |
// |                                                    |
// |                                                    |
// |                                                    |
// |                                                    |
// |                                                    |
// |                                                    |
// |                                                    |
// |                                                    |
// +----------------------------------------------------+
// | (xxx,yyy) - (xxx,yyy)               rgb (RR,GG,BB) |
// +----------------------------------------------------+ 271
// 0                                                  479
//
#include "mbed.h"           // tested with v92
#include "RA8875.h"         // tested with v80
#include "menu.h"
#include "SDFileSystem.h" 
#include "FATFileSystem.h" 


#define DEBUG "mPaint"
// ...
// INFO("Stuff to show %d", var); // new-line is automatically appended
//
#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
#define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
#else
#define INFO(x, ...)
#define WARN(x, ...)
#define ERR(x, ...)
#define HexDump(a, b, c)
#endif

// Local File System:
// - Store the touch screen calibration
// - Capture works of art in BMP format.
//  LocalFileSystem local("local");
SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd");

// The display interface
//RA8875 lcd(p5, p6, p7, p12, NC, "tft");    // MOSI, MISO, SCK, /ChipSelect, /reset, name
RA8875 lcd(PTD2, PTD3, PTD1, PTD0, NC, "tft");    // FRDM-K64F   MOSI, MISO, SCK, /ChipSelect, /reset, name



// A monitor port for the SW developer.
Serial pc(USBTX, USBRX);

// list of tools (dots, lines, joined lines).
typedef enum {
    dot,                            // draw dots at the point
    line,                           // connected line from touch(point) to release(point)
    join                            // connected lines while held(point)
} tooltype_t;                       // what tool are we using to draw

color_t rgb = Black;                // the composite color value to draw in.
uint8_t rgbVal[3] = { 0, 0, 0 };    // hosts each of the individual values
uint32_t pensize = 1;               // pensize is user selectable within a small range.
tooltype_t selectedtooltype = dot;  // 0:dot, 1:line, 2:join
point_t origin = { 0, 0};           // tracks origin when drawing a line


// Adjust the following if using the 800x600 display
const rect_t RGBList[] = {          // regions on the display for special tools
    { 309,0, 359,15 },    // R
    { 369,0, 419,15 },    // G
    { 429,0, 479,15 },    // B
    { 249,0, 299,15 }     // show selected color
};
const rect_t canvas_rect = {        // the drawing surface
    0,16, 479,271
};



// File             Pen            Tools
//  New...           Pensize 1      Dot
//  Save...          Pensize 2      Line
//  Calibrate        Pensize 4
//  Reset            Pensize 6
//                   Pensize 8
//
Menu::post_fnc_action_t File(uint32_t v);
Menu::post_fnc_action_t File_New(uint32_t v);
Menu::post_fnc_action_t File_Save(uint32_t v);
Menu::post_fnc_action_t File_Save_All(uint32_t v);
Menu::post_fnc_action_t File_Cal(uint32_t v);
Menu::post_fnc_action_t File_Reset(uint32_t v);
Menu::post_fnc_action_t Edit(uint32_t v);
Menu::post_fnc_action_t Edit_Clear(uint32_t v);
Menu::post_fnc_action_t Tools(uint32_t v);
Menu::post_fnc_action_t Tools_Type(uint32_t v);
Menu::post_fnc_action_t PenSize(uint32_t v);
Menu::post_fnc_action_t HideMenu(uint32_t v);

// Some APIs
extern "C" void mbed_reset();
int GetScreenCapture(void);
void CalibrateTS(void);
void ShowSampleRGB(void);
void InitDisplay(void);

Menu::menu_item_t file_menu[] = {
    // Prompt, onPress, onHold, OnRelease, parameter, child menu
    { "New...", File_New, NULL, NULL, 0, NULL },
    { "Save...", File_Save, NULL, NULL, 0, NULL },
    { "Save all", File_Save_All, NULL, NULL, 0, NULL },
    { "Calibrate", File_Cal, NULL, NULL, 0, NULL },
    { "Reset", NULL, NULL, File_Reset, 0, NULL },
    { NULL, NULL, NULL, NULL, 0, NULL },
};

Menu::menu_item_t pen_menu[] = {
    { "1 pix",  NULL, NULL, PenSize, 1, NULL },
    { "2 pix",  NULL, NULL, PenSize, 2, NULL },
    { "4 pix",  NULL, NULL, PenSize, 4, NULL },
    { "6 pix",  NULL, NULL, PenSize, 6, NULL },
    { "8 pix",  NULL, NULL, PenSize, 8, NULL },
    { NULL, NULL, NULL, NULL, 0, NULL },
};

Menu::menu_item_t tools_menu[] = {
    { "point", NULL, NULL, Tools_Type, dot, NULL },
    { "line",  NULL, NULL, Tools_Type, line, NULL },
    { "join",  NULL, NULL, Tools_Type, join, NULL },
    { NULL, NULL, NULL, NULL, 0, NULL },
};

Menu::menu_item_t menudata[] = {
    { "File", File, NULL, NULL, 0, file_menu },
    { "Pen",  NULL, NULL, NULL, 0, pen_menu },
    { "Tools", NULL, NULL, NULL, 0, tools_menu },
    { "Hide", NULL, NULL, HideMenu, 0, NULL },
    { NULL, NULL, NULL, NULL, 0, NULL },
};

Menu menu(lcd, menudata);

Menu::post_fnc_action_t File(uint32_t v)
{
    (void)v;
    INFO("File");
    return Menu::no_action;
}
Menu::post_fnc_action_t File_New(uint32_t v)
{
    (void)v;
    INFO("File_New");
    InitDisplay();
    return Menu::no_action;
}
Menu::post_fnc_action_t File_Save(uint32_t v)
{
    (void)v;
    INFO("File_Save");
    RA8875::LayerMode_T l = lcd.GetLayerMode();
    lcd.SetLayerMode(RA8875::ShowLayer0);
    GetScreenCapture();
    lcd.SetLayerMode(RA8875::TransparentMode);
    return Menu::close_menu;
}
Menu::post_fnc_action_t File_Save_All(uint32_t v)
{
    (void)v;
    INFO("File_Save_All");
    GetScreenCapture();
    return Menu::close_menu;
}
Menu::post_fnc_action_t File_Cal(uint32_t v)
{
    (void)v;
    INFO("Tools_Cal");
    CalibrateTS();
    return Menu::no_action;
}
Menu::post_fnc_action_t File_Reset(uint32_t v)
{
    (void)v;
    INFO("rebooting now...");
    wait_ms(1000);
    NVIC_SystemReset();                 // Software reset.
    return Menu::no_action;
}
Menu::post_fnc_action_t Edit(uint32_t v)
{
    (void)v;
    INFO("Edit");
    return Menu::no_action;
}
Menu::post_fnc_action_t Tools(uint32_t v)
{
    (void)v;
    INFO("Tools");
    return Menu::no_action;
}
Menu::post_fnc_action_t PenSize(uint32_t v)
{
    pensize = v;
    if (pensize < 1)
        pensize = 1;
    else if (pensize > 8)
        pensize = 8;
    INFO("PenSize(%d)", pensize);
    ShowSampleRGB();
    return Menu::close_menu;
}
Menu::post_fnc_action_t Tools_Type(uint32_t v)
{
    switch (v) {
        case dot:
        case line:
        case join:
            selectedtooltype = (tooltype_t)v;
            break;
        default:
            break;
    }
    ShowSampleRGB();
    return Menu::close_menu;
}
Menu::post_fnc_action_t HideMenu(uint32_t v)
{
    (void)v;
    return Menu::close_menu;
}

void ShowSampleRGB(void)
{
    loc_t middle = (RGBList[3].p1.y + RGBList[3].p2.y)/2;
    lcd.fillrect(RGBList[3], Black);
    lcd.fillrect(RGBList[3], rgb);
    if (selectedtooltype == dot) {
        lcd.fillcircle((RGBList[3].p1.x + RGBList[3].p2.x)/2,
            middle, pensize, rgb);
    } else {
        lcd.fillrect(RGBList[3].p1.x,middle-pensize/2, RGBList[3].p2.x,middle+pensize/2, rgb);
    }
}

void CalibrateTS(void)
{
    FILE * fh;
    tpMatrix_t matrix;
    RetCode_t r;

    r = lcd.TouchPanelCalibrate("Calibrate the touch panel", &matrix);
    INFO("  ret: %d", r);
    if (r == noerror) {
        fh = fopen("/sd/tpcal.cfg", "wb");
        if (fh) {
            fwrite(&matrix, sizeof(tpMatrix_t), 1, fh);
            fclose(fh);
            INFO("  tp cal written.");
        } else {
            WARN("  couldn't open tpcal file.");
        }
    } else {
        ERR("error return: %d", r);
    }
}


void InitTS(void)
{
    FILE * fh;
    tpMatrix_t matrix;

    fh = fopen("/sd/tpcal.cfg", "rb");
    if (fh) {
        fread(&matrix, sizeof(tpMatrix_t), 1, fh);
        fclose(fh);
        lcd.TouchPanelSetMatrix(&matrix);
        INFO("  tp cal loaded.");
    } else {
        CalibrateTS();
    }
}


void InitDisplay(void)
{
    lcd.SelectDrawingLayer(CANVAS);
    lcd.cls();
    lcd.foreground(Blue);
    lcd.background(White);
    lcd.Backlight_u8(255);    
}

int GetScreenCapture(void)
{
    char fqfn[50];
    int i = 0;

    INFO("Screen Capture... ");
    for (i=1; i< 100; i++) {
        snprintf(fqfn, sizeof(fqfn), "/sd/Screen%02d.bmp", i);
        FILE * fh = fopen(fqfn, "rb");
        if (!fh) {
            lcd.PrintScreen(0,0,lcd.width(),lcd.height(),fqfn);
            INFO(" as /sd/Screen%02d.bmp", i);
            return i;
        } else {
            fclose(fh);     // close this and try the next
        }
    }
    return 0;
}

void ShowRGBSelectors(void)
{
    uint16_t curLayer = lcd.GetDrawingLayer();
    lcd.SelectDrawingLayer(MENUS);
    lcd.fillrect(RGBList[0], Red);
    lcd.fillrect(RGBList[1], Green);
    lcd.fillrect(RGBList[2], Blue);
    lcd.SelectDrawingLayer(curLayer);
}

bool SeeIfUserSelectingRGBValues(point_t p, TouchCode_t touchcode)
{
    static bool wasIn = false;
    
    // See if the touch is setting new RGB values
    for (int i=0; i<3; i++) {
        if (lcd.Intersect(RGBList[i], p)) {
            uint8_t mag = (255 * (p.x - RGBList[i].p1.x)) / (RGBList[i].p2.x - RGBList[i].p1.x);
            wasIn = true;
            if (touchcode == touch)
                menu.Show();
            else if (touchcode == release)
                menu.Hide();
            rgbVal[i] = mag;
            // update the RGB values
            lcd.SelectDrawingLayer(MENUS);
            lcd.SetTextCursor(lcd.width() - 80, lcd.height() - 16);
            lcd.foreground(Blue);
            lcd.printf("(%02X,%02X,%02X)", rgbVal[0], rgbVal[1], rgbVal[2]);
            // show sample
            rgb = RGB(rgbVal[0], rgbVal[1], rgbVal[2]);
            ShowSampleRGB();
            //
            lcd.SelectDrawingLayer(CANVAS);
            lcd.foreground(rgb);
            return true;
        }
    }
    if (wasIn)
        menu.Hide();
    return false;
}

void ThickLine(point_t origin, point_t p)
{
    double angleN;
    loc_t dy;
    loc_t dx;
    point_t s = { 0, 0 };
    point_t e = { 0, 0 };

    lcd.line(origin,p, rgb);
    INFO("   End @ (%3d,%3d) - (%3d,%3d) [%d]", origin.x, origin.y, p.x, p.y, pensize);
    #define PI 3.14159
    dy = p.y - origin.y;
    dx = p.x - origin.x;
    INFO("delta (%+3d,%+3d)", dx,dy);
    angleN = atan2((double)(dy), (double)(dx));
    if (pensize == 1) {
        lcd.line(origin, p, rgb);
    } else {
        int thickness = pensize/2;
        for (int l=0; l<=pensize; l++) {
            s.x = origin.x + (l - thickness) * cos(angleN+PI/2);
            s.y = origin.y + (l - thickness) * sin(angleN+PI/2);
            e.x = p.x      + (l - thickness) * cos(angleN+PI/2);
            e.y = p.y      + (l - thickness) * sin(angleN+PI/2);
            lcd.line(s, e, rgb);
            INFO("     %+d @ (%3d,%3d) - (%3d,%3d) a:%+3.2f:%+3.2f",
                      l, s.x,s.y, e.x,e.y, angleN, angleN+PI/2);
        }
    }
}


void SeeIfUserDrawingOnCanvas(point_t p, TouchCode_t touchcode)
{
    if (lcd.Intersect(canvas_rect, p)) {
        switch (selectedtooltype) {
            case dot:
                lcd.fillcircle(p, (pensize == 1) ? pensize : pensize/2, rgb);
                break;
            case line:
                if (touchcode == touch) {
                    lcd.fillcircle(p, 1, rgb);
                    origin = p;
                    INFO("Origin @ (%3d,%3d)", p.x, p.y);
                } else if (touchcode == release) {
                    ThickLine(origin, p);
                }
                break;
            case join:
                if (touchcode == touch) {
                    lcd.fillcircle(p, 1, rgb);
                    origin = p;
                    INFO("Origin @ (%3d,%3d)", p.x, p.y);
                } else if (touchcode == release) {
                    ThickLine(origin, p);
                } else if (touchcode == held) {
                    ThickLine(origin, p);
                    origin = p;
                    INFO("  held @ (%3d,%3d)", p.x, p.y);
                }
                break;            
            default:
                break;
        }
    }
}


int main()
{
    pc.baud(115200);    // I like a snappy terminal, so crank it up!
    pc.printf("\r\nRA8875 Menu - Build " __DATE__ " " __TIME__ "\r\n");

    INFO("Turning on display");
    lcd.init();
    InitTS();
    InitDisplay();
    menu.init();
    ShowRGBSelectors();

    INFO("processing loop...");

    for (;;) {
        point_t p;
        TouchCode_t touchcode = lcd.TouchPanelReadable(&p);

        if (touchcode != no_touch) {
            int curLayer = lcd.GetDrawingLayer();
            lcd.SelectDrawingLayer(MENUS);
            lcd.foreground(Blue);
            lcd.SetTextCursor(0, lcd.height() - 16);
            lcd.printf("(%3d,%3d) - (%3d,%3d)", origin.x, origin.y, p.x, p.y);
            lcd.SelectDrawingLayer(curLayer);

            bool menuHandledIt = menu.HandledTouch(p, touchcode);
            if (menuHandledIt) {
                // menu handled it
            } else if (SeeIfUserSelectingRGBValues(p, touchcode)) {
                // that handled it.
            } else {
                SeeIfUserDrawingOnCanvas(p, touchcode);
            }
        } else {
            //non-touch
        }
    }
}
#include <stdarg.h>
//Custom override for error()
void error(const char* format, ...)
{
    char sprintf_buffer[128];

    va_list arg;
    va_start(arg, format);
    vsprintf(sprintf_buffer, format, arg);
    va_end(arg);

    fprintf(stderr, "SW err: %s", sprintf_buffer);
}

//            Reset_Handler
//            NMI_Handler
//            HardFault_Handler
//            MemManage_Handler
//            BusFault_Handler
//            UsageFault_Handler
extern "C" void HardFault_Handler()
{
    printf("\r\n\r\nHard Fault!\r\n");
    wait_ms(500);
    NVIC_SystemReset();
}
/*
extern "C" void NMI_Handler()
{
    printf("\r\n\r\nNMI Fault!\r\n");
    wait_ms(500);
    NVIC_SystemReset();
}
*/

extern "C" void MemManage_Handler()
{
    printf("\r\n\r\nMemManage Fault!\r\n");
    wait_ms(500);
    NVIC_SystemReset();
}
extern "C" void BusFault_Handler()
{
    printf("\r\n\r\nBusFault Fault!\r\n");
    wait_ms(500);
    NVIC_SystemReset();
}
extern "C" void UsageFault_Handler()
{
    printf("\r\n\r\nUsageFault Fault!\r\n");
    wait_ms(500);
    NVIC_SystemReset();
}