A general demonstration color etch-a-sketch program using the QVGA TFT with HX8347D controller, Orange Board. Saves touchscreen calibaration data saved in tft.ini. Creates /local/tft.ini if missing. Also included is an Ethernet NTP client to update the RTC. Assumes all other Orange Board devices attached: Text LCD, SDHC Flash, Ethernet.

Dependencies:   EthernetNetIf TextLCD mbed

main.cpp

Committer:
loopsva
Date:
2011-08-01
Revision:
0:e065ca40f28a

File content as of revision 0:e065ca40f28a:

/*
Rev Date        Changes:
------------------------------------------------------------------------------------------------------------------------------------------
100 7/19/11     - initial offering
101 7/25/11     - Adding RTC display-only functions. No provisions for setting the clock
                - Added red "clear_drawing" box to TFT
                - Added multi-color "change_pen_color" box
                - Added blue, pen_fattness circle (1-8)
                - Added "orange" color to pen_color selection
                - Added hidden system_reset function w/pen touch near "TFT" text
102 7/26/11     - Added EthernetNetIF and TinySNTP for updating RTC over Ethernet
                - Added a color choice palette after reset.  Palette goes away after clear_screen
103 7/28/11     - Expqanded NTP service to two possible NTP servers.  In and IP address, the other named
                - Added tube symbol for display
                - Modified the start-up splash screen
104 7/28/11     - Made tube display indepentent of rotation
                - Added more NTP server options
------------------------------------------------------------------------------------------------------------------------------------------
Known issues:
------------------------------------------------------------------------------------------------------------------------------------------
*/
int revision = 104;                     // revision of this code
#include "mbed.h"
#include "SDHCFileSystem.h"             // MUST be before EthernetNetIf.h or compile error occurs!!!!
#include "adc.h"
#include "EthernetNetIf.h"
#include "TinySNTP.h"
#include "TextLCD.h" 
#include "SPI_TFT.h"
#include "Arial12x12.h"
#include "Arial24x23.h"
#include "Arial28x28.h"
#include "font_big.h"
#include "Courier10x13-12B.h"           // kb modified font created by GLCD_Font_Creator.1.20.exe
#include "Verdana22x21-16.h"            // kb modified font created by GLCD_Font_Creator.1.20.exe
#include "BookAntiqua19x19-14.h"        // kb modified font created by GLCD_Font_Creator.1.20.exe
#include "touch_tft.h"

#define DEFAULTHOSTNAME "mbed-c3p1"
char *hostname = DEFAULTHOSTNAME;

//#define RTCCOLOR "Red"
//char *JunkText = RTCCOLOR;
//char *RtcColor = RTCCOLOR;

#define SAMPLE_RATE    150000
#define CLS "\033[2J"
extern "C" void mbed_reset();
#define Orange 0xF9E0

/*--------------------------------------------------------------------------------------------------------------------------------------*/
//I/O Pin Definitions

LocalFileSystem local("local");
PwmOut led1(LED1, "led1");
DigitalOut led2(LED2, "led2");
DigitalOut led3(LED3, "led3");
DigitalOut led4(LED4, "led4");
EthernetNetIf eth;
Serial pc(USBTX, USBRX);                // Serial USB communications over mbed USB port
SDFileSystem sd(p5, p6, p7, p8, "sd");  // mosi, miso, sclk, cs
touch_tft tt(p19, p15, p16, p17, p5, p6, p7, p9, p14,"TFT"); // x+,x-,y+,y-,mosi, miso, sclk, cs, reset
TextLCD lcdt(p24, /*p25, */p26, p27, p28, p29, p30, TextLCD::LCD16x2); // rs, rw, e, d0, d1, d2, d3
DigitalOut LCDrw(p25, "LCDrw");         // new LCD code no longer requries R/W pin - tie low (J5 on Orange Board)

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Global Variables

int gDebug = 1;                         // display debog level (0 - 3)
int OldgDebug = gDebug;                 // copy of gDebug for updating tft.ini
ADC adc(SAMPLE_RATE, 1);
bool use_sd = false;                    // flag for using SDHC file system
bool ZeroMinFlag = false;               // alignment to 00:00:00 flag
float Led1Pwm = 0.01;                   // LED1 brightness
bool Led1Up = true;                     // LED1 auto up-down
float gWait = 0.005;                    // Main loop wait timeout
float const DISP_SLOW(2.0);             // Long wait for LCD display
float const DISP_FAST(0.5);             // Faster wait for LCD
char timebuf[32];                       // local time format buffer
char timebuf_d[32];                     // local time format buffer - date only
char timebufUTC[32];                    // UTC time format buffer
int DST = 0;                            // Daylight Saving Time (or as defined in tft.ini)
int OldDST = DST;                       // Copy of DST for updating tft.ini
int TZone = -8;                         // Time Zone from UTC (or as defined in tft.ini)
int OldTZone = TZone;                   // copy for updating tft.ini
time_t ctTime;                          // get time structure
int StartTime;                          // time we powered up
int SysUpTime;                          // time we've been alive
int RTCstep;                            // value for NTP update interval timer
int NTPUpdateValue = 86400;             // update RTC every 24 hours (or as defined in tft.ini)
int TftCalib = 1;                       // TFT touchpad calibration, 1=yes (as defined in tft.ini)
unsigned int SerialNum[5] = {58,0,0,0,0}; // mbed serial number data
int TftDrawColor = 0;                   // pick pencil color
int PenColor = 0xFFFF;                  // color of pen
int PenWidth = 3;                       // fattness of pen
bool PenSizeUp = true;                  // fatter or skinnier
char pOnce = 0;                         // display the palette only once
int CurRot = 0;                         // object rotation 0-3
int PosX = 120;                         // object X location
int PosY = 160;                         // object Y location

int RTCupdate = 0;                      // parameter update timer
int const RTCUpdateValue = 60; // 600;  // update values every minute
unsigned int Align1Min=0;               // used to align sensor access to exactly every minute, on the minute
unsigned int Align10Min=0;              // same as above for 10 minute (i.e. 0:00min, 10:00min, 20:00min, etc.
int minuteAvg = 0.0;                    // number of minutes between accesses to storage of data

unsigned short pp_txm = 0;              // tft touchscreen calibration values
unsigned short pp_tym = 0;
unsigned short pp_txoff = 0;
unsigned short pp_tyoff = 0;

float Press0Ft = 102.4;                 // altimeter - assumed pressure at sea level
float Saved0Ft = Press0Ft;              // saved for later comparison if changed by HTTP
float OldPress0Ft = Press0Ft;           // another copy for updating tft.ini

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// initialize mbed "ini" configuration file if it doesn't already exist -or- updates the ini file if a change is made in s/w

void InitIniFile() {
    FILE *fp = fopen("/local/tft.ini", "w");
    if (fp == NULL) {
        pc.printf("*** Cannot create tft.ini file!!!\n");
    } else {
//        if(gDebug > 1) pc.printf("*** Updating/Creating tft.ini file...\n");
        fprintf(fp, "# mbed configuration file\r\n");
        fprintf(fp, "\r\n[NTP Servers]\r\n");
//        for (int i=0; i<sntp_num_servers; i++) {
//            fprintf(f, "%s" CRLF, sntp_server_addresses[i]);
//        }
        fprintf(fp, "\r\n[Global]\r\n");
        char *hostname = DEFAULTHOSTNAME;
        fprintf(fp, "xMyName=%s\r\n",hostname);     //***MyName is broken***
        fprintf(fp, "TftCalib=%d\r\n", TftCalib);   // 1= calibration required
        fprintf(fp, "TftCalTxm=%d\r\n", pp_txm);
        fprintf(fp, "TftCalTym=%d\r\n", pp_tym);
        fprintf(fp, "TftCalTxOff=%d\r\n", pp_txoff);
        fprintf(fp, "TftCalTyOff=%d\r\n", pp_tyoff);
//        char *RtcColor = RTCCOLOR;
//        char *JunkText = RTCCOLOR;
//        fprintf(fp, "TftRtcColor=%s\r\n", RtcColor);
        fprintf(fp, "Timezone(hrs)=%d\r\n", TZone);
        fprintf(fp, "DstZone(hrs)=%d\r\n", DST);
        fprintf(fp, "NTPRefresh(sec)=%d\r\n", NTPUpdateValue);
        fprintf(fp, "PressureSeaLevel=%f\r\n", Press0Ft);
        fprintf(fp, "gDebugLevel=%d\r\n", gDebug);
        fprintf(fp, "\r\n##END\r\n");
        fclose(fp);
    }
    OldgDebug = gDebug;
    OldDST = DST;
    OldTZone = TZone;
    OldPress0Ft = Press0Ft;
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Trim whitespace/CRLFs from both ends of a given string
// for use with routine below

char * str_cleanup(char *in) {
    char * out = in;
    // Trim leading spaces and CR/LF
    while (*out == ' ' || *out == '\t' || *out == '\r' || *out == '\n')
        out ++;
    // Trim trailing spaces and CR/LF
    int len = strlen(out)-1;
    while (out[len] == ' ' || out[len] == '\t' || out[len] == '\r' || out[len] == '\n') {
        out[len] = '\0';
        len--;
    }
    return out;
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Simple ini file parser for SNTP configuration (Case-sensitive!)
// This function is intended to be called only before SNTPClientInit().
// Returns: 0 if OK, errno otherwise

enum {
  SECT_NONE,
  SECT_SERVERS,
  SECT_GLOBAL,
};

//int _SNTPClrAddresses();

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// This routine reads the "ini" file and sets the appropriate variables

int SNTPReadIniFile(const char* filename) {
    if (gDebug > 1) pc.printf("Before: tz:%d  dst:%d ntpupd:%d baroZ:%.1f name:%s\n", TZone, DST, NTPUpdateValue, Press0Ft, hostname);
    FILE *f;
    char buf[512];
//    bool addresses_cleared = false;
    bool hname = false;
    f = fopen(filename, "r");
    if (!f)
        return -1;    // errno not used?
    char *buf1, *buf2;
    int section=SECT_NONE;
    int line = 0;
    while (fgets(buf, sizeof(buf)/sizeof(buf[0]), f)) {
        line++;
        buf1 = str_cleanup(buf);
        if (*buf1 == '#' || *buf1 == '\0')
            continue;    // Comment line or empty line - skip
        if (*buf1 == '[') {
            // New section
            if (0 == strncmp(buf1,"[NTP Servers]", sizeof("[NTP Servers]")-1)) {
                section=SECT_SERVERS;
/*                if (!addresses_cleared) {
                    // Clear addresses only once.
                    _SNTPClrAddresses();
                    addresses_cleared = true;
                }
*/            } else if (0 == strncmp(buf1,"[Global]", sizeof("[Global]")-1)) {
                section=SECT_GLOBAL;
            } else {
                section=SECT_NONE;
                fprintf(stderr, "*** File \"%s\", line %d - section \"%s\" is not understood.\r\n", filename, line, buf1);
            }
        } else {
            // Section values
            switch (section) {
            case SECT_SERVERS:
/*                if (_SNTPAddAddress(buf1)) {
                    fprintf(stderr, "File \"%s\", line %d - cannot add server \"%s\" - exceeded allocated slots.\r\n", filename, line, buf1);
                }
                break;
*/            case SECT_GLOBAL:
                buf2 = strchr(buf1, '=');
                if (buf2) {
                    *buf2++ = '\0';     // Now buf1 has variable name, buf2 has value
                    buf2 = str_cleanup(buf2);
                    if (0 == strncmp(buf1, "Timezone(hrs)", sizeof("Timezone(hrs)")-1)) {
                        TZone = strtod(buf2, &buf2);
                    } else if (0 == strncmp(buf1, "NTPRefresh(sec)", sizeof("NTPRefresh(sec)")-1)) {
                        NTPUpdateValue = strtod(buf2, &buf2);
                    } else if (0 == strncmp(buf1, "gDebugLevel", sizeof("gDebugLevel")-1)) {
                        gDebug = strtod(buf2, &buf2);
                    } else if (0 == strncmp(buf1, "TftCalib", sizeof("TftCalib")-1)) {
                        TftCalib = strtod(buf2, &buf2);
                    } else if (0 == strncmp(buf1, "TftCalTxm", sizeof("TftCalTxm")-1)) {
                        pp_txm = strtod(buf2, &buf2);
                    } else if (0 == strncmp(buf1, "TftCalTym", sizeof("TftCalTym")-1)) {
                        pp_tym = strtod(buf2, &buf2);
                    } else if (0 == strncmp(buf1, "TftCalTxOff", sizeof("TftCalTxOff")-1)) {
                        pp_txoff = strtod(buf2, &buf2);
                    } else if (0 == strncmp(buf1, "TftCalTyOff", sizeof("TftCalTyOff")-1)) {
                        pp_tyoff = strtod(buf2, &buf2); 
//                    } else if (0 == strncmp(buf1, "TftRtcColor", sizeof("TftRtcColor")-1)) {
//                        JunkText = buf2; //pp_tyoff = strtod(buf2, &buf2);  
//                        RtcColor = JunkText;
//                        pc.printf("buf2 >>   %s   JunkText >>   %s   RtcColor >>   %s\n", buf2, JunkText, RtcColor);  
                    } else if (0 == strncmp(buf1, "MyName", sizeof("MyName")-1)) {
                        if (hname == false) {
                            hname = true;
                            hostname = buf2;
                            if (gDebug > 1) pc.printf("buf2:%s hn:%s\n", buf2, hostname);
                        }
                    } else if (0 == strncmp(buf1, "PressureSeaLevel", sizeof("PressureSeaLevel")-1)) {
                        Press0Ft = strtof(buf2, &buf2);
                    //} else if (0 == strncmp(buf1, "RtcUtc", sizeof("RtcUtc")-1)) {
                     //   gSntpRtcUtc = (bool)strtol(buf2, &buf2, 10);
                    } else if (0 == strncmp(buf1, "DstZone(hrs)", sizeof("DstZone(hrs)")-1)) {
                        DST = strtod(buf2, &buf2);
                    } else {
                        pc.printf("*** File \"%s\", line %d - unrecognized variable \"%s\" in section [Global]\r\n", filename, line, buf1);
                    }
                } else {
                    pc.printf("*** File \"%s\", line %d - unrecognized statement in section [Global]: %s\r\n", filename, line, buf1);
                }
                break;
            default:
                pc.printf("*** File \"%s\", line %d - unrecognized statement / no section: %s\r\n", filename, line, buf1);
            }
        }
    }
    fclose(f);
    pc.printf("mbed configuration read from \"%s\", %d lines.\r\n", filename, line);
    pc.printf("- gDebug display level: %d\n", gDebug);
    pc.printf("- Time Zone: %d hours\n", TZone);
    if (DST == 0) {
        pc.printf("- Standard Time\n");
    } else {
        pc.printf("- Daylight Saving Time\n");
    }
    pc.printf("- NTC update: %d seconds\n", NTPUpdateValue);
//    pc.printf("- Pressure at Seal Level: %.1f kPa\n", Press0Ft);
    if (TftCalib == 1) {
        pc.printf("- TFT touchpad calibration required\n");
    } else {
        pc.printf("- No TFT touchpad calibration needed\n");
    }
    pc.printf("- Touch Cal X Base %d\n", pp_txm);
    pc.printf("- Touch Cal Y Base %d\n", pp_tym);
    pc.printf("- Touch Cal X Offset %d\n", pp_txoff);
    pc.printf("- Touch Cal Y Offset %d\n", pp_tyoff);
//    pc.printf("- RTC Color %s\n", RtcColor);
    
    if (gDebug > 1) pc.printf("After: tz:%d  dst:%d ntpupd:%d baroZ:%.1f name:%s\n", TZone, DST, NTPUpdateValue, Press0Ft, hostname);

    OldgDebug = gDebug;
    OldDST = DST;
    OldTZone = TZone;
    OldPress0Ft = Press0Ft;
    return 0;
}


/*--------------------------------------------------------------------------------------------------------------------------------------*/
// This routine attempts to update the RTC via an Ethernet NTP server

int SetEthTime() {
    pc.printf("Getting Time from NTP Server\n- Old Time        (UTC): %d %s", ctTime, ctime(&ctTime));
    int ntpFlag = 0;
    if(gDebug) pc.printf("- Trying NTP Server:  time-a.nist.gov...   ");
    ntpFlag = ntpdate("time-a.nist.gov", &ctTime);
    if((gDebug) && (ntpFlag)) pc.printf("failed\n- Trying NTP Server:  pool.ntp.org...      ");
    if(ntpFlag) {
        ntpFlag = 0;
        ntpFlag = ntpdate("pool.ntp.org", &ctTime);
        if((gDebug) && (ntpFlag)) pc.printf("failed\n- Trying NTP Server:  10.77.127.1...       ");
        if(ntpFlag) {
            ntpFlag = 0;
            ntpFlag = ntpdate("10.77.127.1", &ctTime);
            if((gDebug) && (ntpFlag)) pc.printf("failed\n");
        }
    }


//    pc.printf("ntpFlag: %d\n", ntpFlag);
/*
//
// Server selection code from HTTPS_618
//    
    Host server(IpAddr(), 123, "time-a.nist.gov");
    if (gDebug > 1) pc.printf("NTP result 1 : %d time-a.nist.gov\n", ntp.setTime(server));
    if(ntp.setTime(server) == 4) {
        server.setName("time-b.nist.gov");
        if (gDebug > 1) pc.printf("NTP result 2 : %d time-b.nist.gov\n", ntp.setTime(server));
        if(ntp.setTime(server) == 4) {
            server.setName("pool.ntp.org");
            if (gDebug > 1) pc.printf("NTP result 3 : %d pool.ntp.org\n", ntp.setTime(server));
            if(ntp.setTime(server) == 4) {
                server.setName("north-america.pool.ntp.org");
                if (gDebug > 1) pc.printf("NTP result 4 : %d north-america.pool.ntp.org\n", ntp.setTime(server));
                if(ntp.setTime(server) > 2) {
                    server.setName("10.77.127.1");
                    if (gDebug > 1) pc.printf("NTP result 5 : %d 10.77.127.1\n", ntp.setTime(server));
                    if(ntp.setTime(server) > 2) {
                        server.setName("74.218.141.2");
                        if (gDebug > 1) pc.printf("NTP result 6 : %d 74.218.141.2\n", ntp.setTime(server));
                        pc.printf("    No NTP Server found!!!\n");
                        lcdt.locate(15,1);                    //column(0-15), row(0-1)
                        lcdt.printf("x");                     //set no NTP flag on LCD
                    }
                }
            } 
        }
    }
*/    
    
    
    if(ntpFlag == 0) {
        pc.printf("ok\nSuccessful Time Update\n");
        pc.printf("- Time post NTP   (UTC): %d %s", ctTime, ctime(&ctTime));
        StartTime = ctTime;
        set_time(ctTime);
        ctTime = ctTime + ((TZone+DST)*3600);  //timezone and dst offsets
        pc.printf("- Time post NTP (local): %d %s", ctTime, ctime(&ctTime));
        RTCstep = ctTime + NTPUpdateValue;     //next NTP update  
        ctTime = ctTime + NTPUpdateValue;     //next NTP update 
        pc.printf("- Next Update   (local): %d %s", ctTime, ctime(&ctTime)); 
        ctTime = ctTime - NTPUpdateValue;                     
        return 0;
    } else {
        pc.printf("*** NTP Server not Found!!!\n");
        return -1;
    }
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// This routine is used to align "display events" at exactly RTC 60 second and 10 minute intervals

void align_access_time() {
    ctTime = time(NULL);
    ctTime = ctTime + ((TZone+DST)*3600);   //timezone and dst offsets
    float getMod = fmod(ctTime, 600.0);           // modulus count for exact 10 minute adjustments
    Align1Min = (ctTime + (600 - int(getMod)));     // init 10 minute ticker
    minuteAvg = 1 + (Align1Min - ctTime) / 60;    // how many access minutes before 1st store 
    pc.printf("Align10min  ct: %d  gM: %3d  tsA: %d  mA: %d \n", 
        ctTime, int(getMod), Align1Min, minuteAvg);
    getMod = fmod(ctTime,60.0);
    Align10Min = (ctTime + (60 - int(getMod)));
    RTCupdate = Align10Min; //Align1Min;
    pc.printf("Align1min                   gM: %3d  lts: %d\n", int(getMod), Align10Min);
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// This is the initial splash screen for the TEXT LCD

void TextLCDTitle() {
    lcdt.cls();                          //init the LCD
    lcdt.locate(0,0);                    //column(0-15), row(0-1)
    lcdt.printf("TFT Driver %d", revision); //print revision on LCD
    lcdt.locate(0,1);                    //column(0-15), row(0-1)
    lcdt.printf("K Braun");              //print -me- on LCD
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// This is the initial TFT splash screen -and- the follow-on screen if the pen selects the "clear_screen" box

void InitTft() {
    int CurrentColor = PenColor;
    int CurrentTft = TftDrawColor;
    tt.foreground(Yellow);               // set chars to white
    tt.cls();                           // clear the screen
    tt.set_font((unsigned char*) Arial12x12);  // select the font
//    tt.set_font((unsigned char*) FONT8x8);
//    tt.set_font((unsigned char*) Courier10x13);   
//    tt.set_font((unsigned char*) Verdana22x21);
//    tt.set_font((unsigned char*) Book_Antiqua19x19);
//    tt.cls();
    tt.foreground(Yellow);               // set chars to white
    tt.set_orientation(0);
    tt.locate(0,0);
    tt.printf("  TFT Touch Test");
    tt.locate(0,1);
    tt.printf("  K. Braun");
    tt.locate(0,2);
    tt.printf("  Rev: %d", revision);
    tt.locate(13,1);
    tt.printf("%d", PenWidth);
    tt.foreground(White);               // set chars to white
    tt.set_orientation(1);
    tt.rect(5,5,30,30,Red);
    tt.fillrect(5,35,30,60,CurrentColor);
    if(CurrentColor == Black) {
        tt.rect(5,35,30,60,White);          // if black, put on white frame
    }
    tt.circle(16,80,10, Blue);
//    PenColor = 0xFFFF;                  // color of pen
//    TftDrawColor = 0;                   // pick pencil color

// The following draws that color palette, but only once after a reset
    if((gDebug >> 0)  && (pOnce == 0)) {
        pOnce = 1;
        tt.set_orientation(0);
        tt.set_font((unsigned char*) Arial24x23);
        tt.locate(3,3);
        tt.printf("Palette");
        tt.set_font((unsigned char*) Arial12x12); 
        int tX = 17;
        int tY = 90;
        int tB = 25;
        tt.fillrect(tX,tY,tX+tB,tY+tB,White);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Orange);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Yellow);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Magenta);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Red);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Cyan);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Green);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Blue);
        tY = tY+tB+1;
        tX = 17;
        tt.fillrect(tX,tY,tX+tB,tY+tB,LightGrey);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,DarkGrey);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Olive);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Purple);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Maroon);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,DarkCyan);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,DarkGreen);
        tX = tX+tB+1;
        tt.fillrect(tX,tY,tX+tB,tY+tB,Navy);
        tt.set_orientation(1);
    }
    
    PenColor = CurrentColor;
    TftDrawColor = CurrentTft;
    
    //wait for no-touch
    point p;
    do {
        p = tt.get_touch();
        tt.is_touched(p);
    } 
        while (p.y > 0x2000 | p.x > 0x2000); // { // wait for no touch
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// The following draws an object of a triode tube. It's location is set by PosX and PosY and CurRot

void DrawTubeX() {
    int xx = PosX;
    int yy = PosY;
    if((CurRot == 0) || (CurRot == 2)) {
        xx = PosX;
        yy = PosY;
    } else {
        xx = PosY;
        yy = PosX;
    }
    tt.set_orientation(CurRot);
    tt.fillcircle(xx,yy,60,Orange);
    tt.circle(xx,yy,60,Navy);
    tt.circle(xx,yy,59,Blue);
    tt.circle(xx,yy,58,Navy);
    tt.fillrect(xx-2,yy+40,xx+2,yy+70,Purple);
    tt.fillrect(xx-2,yy+10,xx+2,yy+30,Purple);
    tt.fillrect(xx-2,yy-20,xx+2,yy+00,Purple);
    tt.fillrect(xx-2,yy-50,xx+2,yy-30,Purple);
    tt.fillrect(xx-80,yy-2,xx-30,yy+2,DarkGreen);
    tt.fillrect(xx-30,yy-30,xx-25,yy+30,DarkGreen);
    tt.fillrect(xx+25,yy-30,xx+30,yy+30,Maroon);
    tt.fillrect(xx+25,yy-30,xx+40,yy-25,Maroon); 
    tt.fillrect(xx+25,yy+25,xx+75,yy+30,Maroon);
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// The following draws the tube object in all for rotations, based on CurRot

void DrawTube() {
    CurRot = 2;
    DrawTubeX();
    wait(DISP_SLOW);
    wait(DISP_SLOW);
    for(CurRot = 0 ; CurRot < 4 ; CurRot++) {
        tt.cls();
        DrawTubeX();
        wait(DISP_FAST);
//        wait(DISP_SLOW);
    }
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Routine used to change the pen's color palette on the TFT

void TftNewColor() {
//    point p;
    TftDrawColor++;
    if(TftDrawColor >= 17) {
        TftDrawColor = 0;
    }
    switch (TftDrawColor) {
    case 0: {
        tt.fillrect(5,35,30,60,White);
        PenColor = White;
        }
        break;
    case 1: {
        tt.fillrect(5,35,30,60,Orange);
        PenColor = Orange;
        }
        break;
    case 2: {
        tt.fillrect(5,35,30,60,Yellow);
        PenColor = Yellow;
        }
        break;    
    case 3: {
        tt.fillrect(5,35,30,60,Magenta);
        PenColor = 0xF81F;
        }
        break;
    case 4: {
        tt.fillrect(5,35,30,60,Red);
        PenColor = 0xF800;
        }
        break;
    case 5: {
        tt.fillrect(5,35,30,60,Cyan);
        PenColor = 0x07FF;
        }
        break;
    case 6: {
        tt.fillrect(5,35,30,60,Green);
        PenColor = 0x07E0;
        }
        break;
    case 7: {
        tt.fillrect(5,35,30,60,Blue);
        PenColor = 0x001F;
        }
        break;
    case 8: {
        tt.fillrect(5,35,30,60,LightGrey);
        PenColor = 0x7BEF;
        }
        break;
    case 9: {
        tt.fillrect(5,35,30,60,DarkGrey);
        PenColor = 0xC618;
        }
        break;
    case 10: {
        tt.fillrect(5,35,30,60,Olive);
        PenColor = 0x7BE0;
        }
        break;
    case 11: {
        tt.fillrect(5,35,30,60,Purple);
        PenColor = 0x780F;
        }
        break;
    case 12: {
        tt.fillrect(5,35,30,60,Maroon);
        PenColor = 0x7800;
        }
        break;
    case 13: {
        tt.fillrect(5,35,30,60,DarkCyan);
        PenColor = 0x03EF;
        }
        break;
    case 14: {
        tt.fillrect(5,35,30,60,DarkGreen);
        PenColor = 0x03E0;
        }
        break;
    case 15: {
        tt.fillrect(5,35,30,60,Navy);
        PenColor = 0x000F;
        }
        break;
    case 16: {
        tt.fillrect(5,35,30,60,Black);
        tt.rect(5,35,30,60,White);
        PenColor = 0x0000;
        }
        break;

    } // end of switch

//wait for no-touch
    point p;
    do {
        p = tt.get_touch();
        tt.is_touched(p);
//        pc.printf("pr1: %d  %d\n", p.x, p.y);
    } 
        while (p.y > 0x2000 | p.x > 0x2000); // { // wait for no touch
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Find the "secret spot" on the TFT, RESET the mbed

void KillMbed() {
    // text LCD
    lcdt.cls();                                                                     // clear out text LCD
    lcdt.locate(0,0);                                                               // column(0-15), row(0-1)
    lcdt.printf("Pen select\n");
    lcdt.printf("resetting mbed!!");
    // CRT
    pc.printf("### Pen detected reset area.  Resetting mbed!!!! ###\n");
    
    //wait for no-touch
    point p;
    do {
        p = tt.get_touch();
        tt.is_touched(p);
    } 
        while (p.y > 0x2000 | p.x > 0x2000); // { // wait for no touch
    
    // TFT LCD
    tt.cls();
    tt.foreground(Yellow);
    tt.set_orientation(1);
    tt.set_font((unsigned char*) Book_Antiqua19x19);
    tt.locate(2,5);                                                                 // x,y
    tt.printf("### Reset mbed ###");
    
    wait(DISP_SLOW);
    wait(DISP_SLOW);
    mbed_reset();
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// This routing changes the "width" or "fatness" of the drawing pen on the TFT

void TftNewPenSize() {
    PenWidth++;
    if(PenWidth > 8) {
        PenWidth = 1;
    }
    tt.foreground(Yellow);               // set chars to white
    tt.set_orientation(0);
    tt.locate(13,1);
    tt.printf("%d", PenWidth);
    tt.set_orientation(1);
    tt.circle(16,80,10, Blue);
    tt.foreground(PenColor);

//wait for no-touch
    point p;
    do {
        p = tt.get_touch();
        tt.is_touched(p);
//        pc.printf("pr1: %d  %d\n", p.x, p.y);
    } 
        while (p.y > 0x2000 | p.x > 0x2000); // { // wait for no touch
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
//A generic QUICK BROWN FOX routine to check out various fonts

void QuickBrownFox() {
    tt.foreground(Yellow);               // set chars to white
    tt.cls();                           // clear the screen
//    tt.set_font((unsigned char*) Arial12x12);  // select the font
//    tt.set_font((unsigned char*) Courier10x13);  // select the font    
//    tt.set_font((unsigned char*) Verdana22x21);  // select the font  
//    tt.set_font((unsigned char*) Book_Antiqua19x19);  // select the font 
    tt.set_orientation(1);
    tt.locate(0,0);
    tt.printf("THE QUICK BROWN FOX");
    tt.locate(0,1);
    tt.printf("JUMPED OVER THE LAZY");
    tt.locate(0,2);
    tt.printf("DOG'S BACK 0123456789");
    tt.locate(0,3);
    tt.printf("!@#$%^&*(){|}[\]:;<,./?>");
    tt.locate(0,5);
    tt.printf("the quick brown fox");
    tt.locate(0,6);
    tt.printf("jumped over the lazy ");
    tt.locate(0,7);
    tt.printf("dog's back \n");
    tt.foreground(White);               // set chars to white
    tt.set_orientation(1);
}
    
/*--------------------------------------------------------------------------------------------------------------------------------------*/
int main() {
    pc.baud(921600);                    //set up USB serial speed
//    time_t ctTime;
    ctTime = time(NULL);
    StartTime = ctTime;                 //get time we started up
    ctTime = ctTime + ((TZone+DST)*3600);  //timezone and dst offsets
    RTCstep = ctTime;

    pc.printf("\n\n");
    pc.printf("-------------------------------------------------------------------\n");
    pc.printf("TFT and Touch Screen Test Routines  Rev: %d   K Braun\n", revision);    
    TextLCDTitle();
    pc.printf("Graphic elements/text displayed\n");
//    point p;

//    tt.claim(stdout);                   // send stdout to the TFT display
    tt.background(Black);               // set background to black
    tt.foreground(Yellow);               // set chars to white
    tt.cls();                           // clear the screen
    tt.set_font((unsigned char*) Arial12x12);  // select the font
    tt.set_orientation(0);
    tt.locate(0,0);
    tt.printf(" Revision: %d", revision);

    tt.foreground(White);               // set chars to white
    tt.set_orientation(1);
    
    tt.set_font((unsigned char*) Arial24x23);
    tt.locate(3,9);                     // x,y
    tt.printf("Graphic Test");
// some graphics     
    tt.line(0,0,100,200,Green);
    tt.rect(20,40,70,90,Red);
    tt.fillrect(240,25,260,70,Blue);
    tt.fillrect(265,25,285,70,Blue);
    tt.circle(30,180,10,Purple);
    tt.circle(55,175,10,DarkGreen);
    tt.circle(40,155,10,DarkCyan);
    DrawTube();
    CurRot = 1;
    tt.cls();
    DrawTubeX();
    PosX = 40;
    PosY = 50; 
    DrawTubeX();
    PosX = 190;
    PosY = 50; 
    DrawTubeX();
    PosX = 40;
    PosY = 280; 
    DrawTubeX();
    PosX = 190;
    PosY = 280; 
    DrawTubeX();
    wait(DISP_SLOW);
    wait(DISP_SLOW);
    
// Check if we can use modify the http name of the mbed
    FILE *fp = fopen("/local/whoami.ini", "r");
    if (fp == NULL) {
        pc.printf("*** No /local/whoami.ini file, defaulting to:  %s\n",hostname);
    } else {
        char localbuf[64];
        hostname = fgets(localbuf, sizeof(localbuf)-1, fp);
        pc.printf("Found /local/whoami.ini file. my name is:  %s\n",hostname);
        fclose(fp);
    }

// Check for main ini file, create if does not exist    
    FILE *fpi = fopen("/local/tft.ini", "r");
    if (fpi == NULL) {
        InitIniFile();
        pc.printf("*** rebooting after file creation....");
        wait(2.0);
        mbed_reset();
    } else {
        pc.printf("Found /local/tft.ini file...\n");
        fclose(fpi);
        SNTPReadIniFile("/local/tft.ini");
    }

/*See if INDEX.HTM can be created on SD micro drive */
//
//NOTE:  mbed hangs if no SD card installed - need to fix!!!!!!
//    
    lcdt.cls();                          //init the LCD
    lcdt.locate(0,0);                    //column(0-15), row(0-1)
    lcdt.printf("SD Card Missing!");     //---in case SD drive hangs forever---
        
    if (gDebug > 3) {
//        char *WriteTest = "This is a Test!!!";
        fp = fopen("/sd/INDEX.HTM", "w+");
        if (fp == NULL) {
            pc.printf("*** Cannot create INDEX.HTM file\n");
        } else {
//            char localbuf[32];
//            localbuf = WriteTest;
            fprintf(fp, "This is a Test!!!\n");
            pc.printf("Creating /sd/INDEX.HTM file\n");
            fclose(fp);
        }
    }
        
    fp = fopen("/sd/index.htm", "r");
    if (fp == NULL) {
        use_sd = false;
        if (gDebug) pc.printf("*** Found SD card, -no- INDEX.HTM file\n");
    } else {
        use_sd = true;
        fclose(fp);
        if (gDebug) pc.printf("Found SD card with INDEX.HTM file\n");
    }
    
    lcdt.cls();

//    if (0 != SNTPReadIniFile("/sd/sntp.ini") )
//        SNTPReadIniFile("/local/sntp.ini");
//        SNTPWriteIniFile(stdout);
//        fclose(fpi);
//        lcdt.cls();                          //init the LCD     
    if ((use_sd == true) && (gDebug > 3)) pc.printf(" ");  // to get rid of use_sd "never used" warning
    
//Check RTC
    ctTime = time(NULL);
    ctTime = ctTime + ((TZone+DST)*3600);  //timezone and dst offsets
    if (RTCstep == ctTime) {
        pc.printf("*** RTC stopped, initializing the RTC.  !!CHECK BATTERY!!\n");
        pc.printf("*** Note: Time is incorrect, needs to be updated!!!\n");
        set_time(1296473737);
        lcdt.cls();                          //init the LCD
        lcdt.locate(0,0);                    //column(0-15), row(0-1)
        lcdt.printf("RTC Stopped!!");
        wait(DISP_SLOW);

        //    strftime(timebuf, 32, "%H:%M\n", localtime(&ctTime));
    } else {
        lcdt.cls();                          //init the LCD
        lcdt.locate(0,0);                    //column(0-15), row(0-1)
        lcdt.printf("RTC running");
        pc.printf("RTC running\n");
    }       
    tt.cls();
    if(TftCalib == 1) {
        lcdt.locate(0,1);                    //column(0-15), row(0-1)
        lcdt.printf("Cal t-pad...");
        pc.printf("Calibrating touchpad.....");
        tt.calibrate();             // calibrate the touch
        pc.printf("  Updating /local/tft.ini file.....");
        TftCalib = 0;               //set -no cal reqd- flag
        pp_txm = tt.getCalDataX();       //get calibration values
        pp_tym = tt.getCalDataY();
        pp_txoff = tt.getCalOffX();
        pp_tyoff = tt.getCalOffY();
        InitIniFile();              //save in ini file
        pc.printf("  done\n");
        pc.printf("New Touch Cal Values:\n- Touch Cal X Base %d\n- Touch Cal Y Base %d\n- Touch Cal X Offset %d\n- Touch Cal Y Offset %d\n"
                    , pp_txm, pp_tym, pp_txoff, pp_tyoff);
        lcdt.cls();
    } else {
        pc.printf("No touchpad cal needed\n");
        tt.setCalDataX(pp_txm);       //set calibration values
        tt.setCalDataY(pp_tym);
        tt.setCalOffX(pp_txoff);
        tt.setCalOffY(pp_tyoff);
    }
    
    TextLCDTitle();

    tt.cls();
    tt.foreground(Yellow);               // set chars to white
//    tt.cls();                           // clear the screen
//    tt.set_font((unsigned char*) Arial12x12);  // select the font
    tt.set_font((unsigned char*) Courier10x13);  // select the font    
//    tt.set_font((unsigned char*) Verdana22x21);  // select the font  
//    tt.set_font((unsigned char*) Book_Antiqua19x19);  // select the font 
    pc.printf("Quick Brown Fox displayed\n");
    QuickBrownFox();
//    wait(DISP_SLOW);
//    wait(DISP_SLOW);
//    pc.printf("(before)  ctTime %d\n", ctTime);

//Set up Ethernet
    EthernetErr ethErr;
    pc.printf("Starting Ethernet...\n");
    ethErr = eth.setup();
    if(ethErr) {
        pc.printf("*** No Ethernet Link!!!\n");
    } else {
        IpAddr ethIp = eth.getIp();
        pc.printf("IP address : %d.%d.%d.%d\n", ethIp[0], ethIp[1], ethIp[2], ethIp[3]);
        lcdt.cls();
        lcdt.printf("%d.%d.%d.%d\n", ethIp[0], ethIp[1], ethIp[2], ethIp[3]);
        lcdt.locate(0,1);                    //column(0-15), row(0-1)
        lcdt.printf("tft%d", revision);
        SetEthTime();
    }
    InitTft();
    point p;
    int LedDelay = 0;
    int xTime = ctTime;
//    pc.printf("RtcColor  %s\n", RtcColor);
    pc.printf("Ready...\n");
//    pc.printf("(after)   ctTime %d\   xTime %d\n", ctTime, xTime);
    while (1) {
        ctTime = time(NULL);
        SysUpTime = ctTime - StartTime;                 //number of seconds we've been alive
//        if(gDebug > 1) pc.printf("cT: %d   sT: %d   suT: %d\n", ctTime, StartTime, SysUpTime);
        ctTime = ctTime + ((TZone + DST) * 3600);   //timezone and dst offsets
        strftime(timebuf, 32, "%H:%M:%S", localtime(&ctTime));
        if(xTime != ctTime) {
            xTime = ctTime;
            if(gDebug > 1) pc.printf("cT: %d   sT: %d   suT: %d\n", ctTime, StartTime, SysUpTime);
            lcdt.locate(8,1);                       //column(0-15), row(0-1)
            lcdt.printf("%s\n", timebuf);
            lcdt.locate(15,1);
            
            tt.foreground (Cyan);
            tt.set_orientation(0);
            tt.locate(14,25); //25
            tt.printf("%s", timebuf );
            strftime(timebuf, 32, "%m/%d/%y", localtime(&ctTime));
            tt.locate(14,24); //24
            tt.printf("%s", timebuf );
        }
// Winking LED1      
        LedDelay++;
        if(LedDelay >= 24) {
            LedDelay = 0;
            if(Led1Up == true) {
                Led1Pwm = Led1Pwm + 0.005;
                led1 = Led1Pwm;
                if(Led1Pwm >= 0.20) {
                    Led1Up = false;
                }
            } else {
                Led1Pwm = Led1Pwm - 0.005;
                led1 = Led1Pwm;
                if(Led1Pwm <= 0.005) {
                    Led1Up = true;
                }
            }
        }
        tt.set_orientation(1);
        p = tt.get_touch();   // read analog pos.
        if (tt.is_touched(p)) {  // test if touched
//            pc.printf("p1: %d  %d\n", p.x, p.y);

// inside the red box  tt.rect(5,5,30,30,Red);
            if((p.x >= 10000) && (p.x <= 15500) && (p.y >= 10500) && (p.y <= 16300)) {          // clear out TFT LCD red box
                InitTft();
            } else if((p.x >= 10000) && (p.x <= 15500) && (p.y >= 16400) && (p.y <= 21300)) {   // pen color select colored box
                TftNewColor();
            } else if((p.x >= 10000) && (p.x <= 15500) && (p.y >= 21400) && (p.y <= 29000)) {   // pen width select blue circle
                TftNewPenSize();
            } else if((p.x >= 10000) && (p.x <= 12000) && (p.y >= 50000) && (p.y <= 55000)) {   // hidden system-reboot near "TFT" text
                KillMbed();
            } else {
                p = tt.to_pixel(p);                                                             // convert to pixel pos
                tt.fillcircle(p.x,p.y,PenWidth,PenColor);                                       // print a blue dot on the screen
            }
//            pc.printf("p2: %d\n", p);
        }
    }
}