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

Revision:
0:e065ca40f28a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Aug 01 16:29:58 2011 +0000
@@ -0,0 +1,1011 @@
+/*
+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);
+        }
+    }
+}
+