V.06 11/3
Dependencies: FT6206 SDFileSystem SPI_TFT_ILI9341 TFT_fonts
Fork of ATT_AWS_IoT_demo by
Diff: main.cpp
- Revision:
- 29:f71a0be59b99
- Parent:
- 28:54d9a550adf1
--- a/main.cpp Mon Oct 09 21:13:49 2017 +0000 +++ b/main.cpp Fri Nov 03 20:28:02 2017 +0000 @@ -7,6 +7,10 @@ #include "SPI_TFT_ILI9341.h" #include "FT6206.h" #include "Arial12x12.h" +#include "Arial28x28.h" +#include "BookAntiqua19x19-14.h" + +#include "logo.h" // SD File System #include "SDFileSystem.h" @@ -26,6 +30,19 @@ #include "aws_iot_config.h" #include "aws_iot_mqtt_interface.h" +#include "mbedtls/net.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/certs.h" +#include "mbedtls/x509.h" +#include "mbedtls/error.h" +#include "mbedtls/debug.h" +#include "mbedtls/timing.h" +#include "mbedtls/net_sockets.h" +#include "pem.h" + + // Sensors #include "HTS221.h" @@ -51,7 +68,7 @@ // AWS defines #define PATH_MAX 1024 #define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200 // NOTE: Be wary of this if your JSON doc grows -#define SHADOW_SYNC_INTERVAL 3.0 // How often we sync with AWS Shadow (in seconds) +#define SHADOW_SYNC_INTERVAL 6.0 // How often we sync with AWS Shadow (in seconds) // Comment out the following line if color is not supported on the terminal //#define USE_COLOR @@ -81,21 +98,12 @@ #define CTOF(x) ((x)*1.8+32) // Temperature //TFT - -//#define PIN_XP A3 -//#define PIN_XM A1 -//#define PIN_YP A2 -//#define PIN_YM A0 -#define PIN_SCLK D13 -#define PIN_MISO D12 -#define PIN_MOSI D11 -#define PIN_CS_TFT D10 // chip select pin -#define PIN_DC_TFT D9 // data/command select pin. - -#define PIN_RESET_TFT D8 -//#define PIN_BL_TFT D7 -//#define PIN_CS_SD D4 - +#define PIN_SCLK PTD5 +#define PIN_MISO PTD7 +#define PIN_MOSI PTD6 +#define PIN_CS_TFT PTD4 // chip select pin +#define PIN_DC_TFT PTB20 // data/command select pin. +#define PIN_RESET_TFT PTB20 //we don't need reset so just use DC instead. Could modify library #define PORTRAIT 0 #define LANDSCAPE 1 @@ -105,15 +113,21 @@ /* #define PIN_SCL_FT6206 PTE24 #define PIN_SDA_FT6206 PTE25 -#define PIN_INT_FT6206 PTC6 +//#define PIN_INT_FT6206 PTC6 +#define PIN_INT_FT6206 PTC3 */ //#else + #define PIN_SCL_FT6206 D15 #define PIN_SDA_FT6206 D14 #define PIN_INT_FT6206 PTC3 + //#endif + + SPI_TFT_ILI9341 TFT(PIN_MOSI, PIN_MISO, PIN_SCLK, PIN_CS_TFT, PIN_RESET_TFT, PIN_DC_TFT, "TFT"); // mosi, miso, sclk, cs, reset, dc +FT6206 ft6206(PIN_SDA_FT6206, PIN_SCL_FT6206, PIN_INT_FT6206); // sda, scl, int //===================================================================================================================== // @@ -131,7 +145,7 @@ InterruptIn Interrupt(SW3); // These defines are pulled from aws_iot_config.h -char HostAddress[255] = AWS_IOT_MQTT_HOST; +char HostAddress[255] = AWS_IOT_MQTT_HOST1; char MqttClientID[32] = AWS_IOT_MQTT_CLIENT_ID; char ThingName[32] = AWS_IOT_MY_THING_NAME; char PortString[5] = "8883"; @@ -141,12 +155,21 @@ // Sensor data float temperature = 0.0; int humidity = 0; +unsigned int count = 1; char iccid[] = "89011702278124165220"; +//mqqt host name +char *aws_iot_mqtt_host; + +//certificate +static mbedtls_x509_crt clicert; + // Temp/humidity object HTS221 hts221; + + //===================================================================================================================== // // Devices @@ -166,6 +189,11 @@ // I2C bus (SDA, SCL) I2C i2c(PTC11, PTC10); +extern unsigned char cSubject[100]; + +int16_t dbm; +unsigned char cUpdateStatus = 0x00; + //===================================================================================================================== // // Functions @@ -220,13 +248,16 @@ void printData() { INFO("Temperature is: %0.2f F", temperature); - INFO("Humidity is: %02d", humidity); + INFO("Humidity is: %02d", humidity); + switch (ledColor) { case COLOR_OFF: INFO("LED: Off"); + break; case COLOR_RED: INFO("LED: Red"); + break; case COLOR_GREEN: INFO("LED: Green"); @@ -238,8 +269,113 @@ INFO("LED: White"); break; } + } +/* +void printDatatoTFT() +{ + //TFT.cls(); + TFT.locate(0,10); + TFT.printf("ATT LTE: %d dBm AWS: Connected\n\n", dbm); + //TFT.line (0,21, 320,21, White); + TFT.printf("Certificate Name: %s\n\n", cSubject); + //TFT.printf("Sending Device Data...\n\n"); + TFT.printf("ICCID: %s\n", iccidName); + TFT.printf("Temperature: %0.2f F \n", temperature); + TFT.printf("Humidity: %02d %%\n", humidity); + TFT.printf("LED: "); + + switch (ledColor) { + case COLOR_OFF: + TFT.foreground(White); + TFT.printf("OFF \n"); + TFT.fillcircle (240,160, 25, Black); + TFT.circle (240,160, 25, White); + break; + case COLOR_RED: + TFT.foreground(Red); + TFT.printf("RED \n"); + TFT.foreground(White); + TFT.fillcircle (240,160, 25, Red); + break; + case COLOR_GREEN: + TFT.foreground(Green); + TFT.printf("GREEN \n"); + TFT.foreground(White); + TFT.fillcircle (240,160, 25, Green); + break; + case COLOR_BLUE: + TFT.foreground(Blue); + TFT.printf("BLUE \n"); + TFT.foreground(White); + TFT.fillcircle (240,160, 25, Blue); + break; + case COLOR_WHITE: + TFT.foreground(White); + TFT.printf("WHITE \n"); + TFT.fillcircle (240,160, 25, White); + break; + } + TFT.printf("\nUpdate Count: %d\n", count++); +} +*/ + +void printDatatoTFT() +{ + //TFT.cls(); + TFT.locate(0,10); + TFT.printf("ATT LTE: %d dBm AWS: %d\n\n", dbm, count++); + //TFT.line (0,21, 320,21, White); + TFT.printf("CN: %s\n", cSubject); + //TFT.printf("Sending Device Data...\n\n"); + TFT.printf("ICCID: %s\n", iccidName); + TFT.printf("TEMPERATURE: %0.2f F \n", temperature); + TFT.printf("HUMIDITY: %02d %%\n", humidity); + TFT.printf("LED: "); + + switch (ledColor) { + case COLOR_OFF: + TFT.foreground(White); + TFT.printf("OFF \n"); + TFT.fillcircle (240,160, 25, Black); + TFT.circle (240,160, 25, White); + break; + case COLOR_RED: + TFT.foreground(Red); + TFT.printf("RED \n"); + TFT.foreground(White); + TFT.fillcircle (240,160, 25, Red); + break; + case COLOR_GREEN: + TFT.foreground(Green); + TFT.printf("GREEN \n"); + TFT.foreground(White); + TFT.fillcircle (240,160, 25, Green); + break; + case COLOR_BLUE: + TFT.foreground(Blue); + TFT.printf("BLUE \n"); + TFT.foreground(White); + TFT.fillcircle (240,160, 25, Blue); + break; + case COLOR_WHITE: + TFT.foreground(White); + TFT.printf("WHITE \n"); + TFT.fillcircle (240,160, 25, White); + break; + } + //TFT.printf("\nUpdate Count: %d\n", count++); +} + +void ShowINFO(const char *sInfo) +{ + INFO(sInfo); + TFT.printf(sInfo); + TFT.printf("\n"); +} + + //===================================================================================================================== // // AWS Shadow Callbacks @@ -252,14 +388,15 @@ const char *pReceivedJsonDocument, void *pContextData) { INFO("Shadow Update Status Callback"); - + TFT.printf("\n"); if (status == SHADOW_ACK_TIMEOUT) { - INFO("Update Timeout--"); + INFO("Update Timeout"); } else if (status == SHADOW_ACK_REJECTED) { - INFO("Update RejectedXX"); + INFO("Update Rejected"); } else if (status == SHADOW_ACK_ACCEPTED) { - INFO("Update Accepted!!"); // Good + INFO("Update Accepted"); // Good } + } //********************************************************************************************************************* @@ -458,19 +595,32 @@ return rc; } +void InitTFT() +{ + //Configure the display driver + TFT.claim(stdout); + TFT.background(Black); + TFT.foreground(White); + TFT.set_orientation(LANDSCAPE_R); + TFT.cls(); + TFT.set_font((unsigned char*) Arial12x12); + //TFT.set_font((unsigned char*) Courier10x13-12B); + TFT.locate(0,0); +} + void TFTStuff() { INFO("DBG> main\r\n"); - FT6206 ft6206(PIN_SDA_FT6206, PIN_SCL_FT6206, PIN_INT_FT6206); // sda, scl, int + //FT6206 ft6206(PIN_SDA_FT6206, PIN_SCL_FT6206, PIN_INT_FT6206); // sda, scl, int //Configure the display driver TFT.claim(stdout); - //TFT.background(Black); - //TFT.foreground(White); + TFT.background(Black); + TFT.foreground(White); - TFT.background(White); - TFT.foreground(Black); + //TFT.background(White); + //TFT.foreground(Black); TFT.set_orientation(LANDSCAPE_R); @@ -484,16 +634,26 @@ INFO("Hello mbed!\r\n"); INFO("Touch Screen to Continue!!\r\n"); + int X1, Y1, X2, Y2; + TS_Point p; + while(1) { - int X1, Y1, X2, Y2; - TS_Point p; - if(ft6206.touched()){ + + if(ft6206.touched()) + { INFO("Touched\r\n"); p = ft6206.getPoint(); - ft6206.clearPoint(); - return; + + + X1 = TFT.width()-p.x; + Y1 = TFT.height()-p.y; + pc.printf("Touched at x=%3d y=%3d\n", p.x, p.y); + pc.printf("Touched actual at x=%3d y=%3d\n", X1, Y1); + + //ft6206.clearPoint(); + //return; } - +/* if (ft6206.getTouchPoint(p)) { X1 = X2; Y1 = Y2; @@ -506,21 +666,149 @@ TFT.line(X1, Y1, X2, Y2, RGB(255,128,255)); } } +*/ } } +/* +//===================================================================================================================== +// setupShield +// setup the Adrafruit 1947 +//===================================================================================================================== +void setupShield(bool touch) { + //Configure the display driver + TFT.claim(stdout); + TFT.background(Black); + TFT.foreground(White); + TFT.set_orientation(LANDSCAPE); + + TFT.cls(); + INFO("TFT.cls()"); + + TFT.circle(120, 120, 50, Red); + + //Print a welcome message + TFT.set_font((unsigned char*) Arial12x12); + TFT.locate(120,160); + TFT.printf("Hello G+D!\n"); + + if (touch) { + while (0) + if(pc.readable()) + pc.putc(pc.getc()); + + int X1, Y1, X2, Y2 = 0; + X2 = -100; + while(1) { + if (FT6206.touched()) { + // if (FT6206.dataReceived()) { + // led1 = !led1; + // Retrieve a point + TS_Point p = FT6206.getPoint(); + X1 = X2; + Y1 = Y2; + X2 = p.x; + Y2 = p.y; + // printf("Touch %3d %3d\n", p.x, p.y); + if ((X1 > 0) && (Y1 > 0) && (X2 > 0) && (Y2 > 0)) { + TFT.line(X1, Y1, X2, Y2, Green); + } + } + // TFT.printf("Count: %d\n", count++); + wait(0.05); + } + } +} +*/ + +int DoAWSThingMenu() +{ + + //FT6206 ft6206(PIN_SDA_FT6206, PIN_SCL_FT6206, PIN_INT_FT6206); // sda, scl, int + + TFT.cls(); + TFT.locate(0,3); + INFO ("AWS Host Selection\n"); + TFT.set_font((unsigned char*) Book_Antiqua19x19); + TFT.printf (" SELECT AWS HOST\n"); + + TFT.set_font((unsigned char*) Arial28x28); + //TFT.circle (160,65, 40, Blue); + TFT.fillcircle (160,75, 40, Blue); + TFT.locate(130,63); + //TFT.foreground(Blue); + TFT.background(Blue); + TFT.foreground(Red); + TFT.printf("ATT"); + //TFT.line (0,39, 319, 39, White); + //TFT.circle (160,150, 40, Green); + TFT.fillcircle (160,160, 40, Green); + TFT.locate(137, 148); + //TFT.foreground(Green); + TFT.background(Green); + TFT.foreground(Black); + TFT.printf("GD"); + //TFT.line (0,79, 319, 79, White); + + int X1, Y1, X2, Y2; + TS_Point p; + + + while(1) + { + if(ft6206.touched()) + { + p = ft6206.getPoint(); + X1 = TFT.width()-p.x; + Y1 = TFT.height()-p.y; + + //pc.printf("Touched at x=%3d y=%3d\n", p.x, p.y); + //pc.printf("Touched actual at x=%3d y=%3d\n", X1, Y1); + + if ((X1 > 120) && (X1 < 200) && (Y1 > 35) && (Y1 <115)) + { + INFO("ATT selected\r\n"); + return 1; + } + + if ((X1 > 120) && (X1 < 200) && (Y1 > 120) && (Y1 < 200)) + { + INFO ("GD selected\n"); + return 2; + } + + //ft6206.clearPoint(); + } + + } + pc.printf ("leaving menu\n"); + wait (10.0); + //TFT.set_font((unsigned char*) Arial12x12); + TFT.set_font((unsigned char*) Book_Antiqua19x19); + TFT.foreground(White); + return 0; +} //===================================================================================================================== // // Main // //===================================================================================================================== -int main() { +int main() +{ + bool bFirstTime = true; + + //Init Screen + InitTFT(); // Set baud rate for PC Serial pc.baud(115200); - INFO("AT&T AWS IoT Demo V.01!"); - + ShowINFO("AT&T AWS IoT Demo V.06"); + + TFT.drawBitmap(43, 10, att, 234, 96); + TFT.drawBitmap(0, 150, gd, 320, 56); + + int i; IoT_Error_t rc = NONE_ERROR; char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER]; @@ -554,6 +842,7 @@ INFO("AWS IoT SDK Version(dev) %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG); + #ifdef USING_SD_CARD // Paths for certs from SD card @@ -577,8 +866,7 @@ wait(.5); SetLedColor(COLOR_OFF); - //TFT Stuff - TFTStuff(); + //TFTStuff(); // Initialize sensors INFO("Init sensors..."); @@ -587,24 +875,73 @@ if(!i) { WARN(RED "HTS221 NOT DETECTED!!\n\r"); } + + //TFTStuff(); + wait (2.0); + int iSelection = 0; + string sMQTTHostName; + + iSelection = DoAWSThingMenu(); + + TFT.locate(0,0); + //TFT.set_font((unsigned char*) Arial12x12); + TFT.set_font((unsigned char*) Book_Antiqua19x19); + TFT.background(Black); + TFT.foreground(White); + TFT.cls(); + switch (iSelection) + { + case 1: + aws_iot_mqtt_host = AWS_IOT_MQTT_HOST1; + sMQTTHostName = "ATT"; + TFT.printf ("ATT AWS Host Selected\n"); + break; + case 2: + aws_iot_mqtt_host = AWS_IOT_MQTT_HOST2; + sMQTTHostName = "GD"; + TFT.printf ("GD AWS Host Selected\n"); + break; + default: + ShowINFO ("Unknown MQTT HOST\n"); + break; + + } // Setup SW3 button to falling edge interrupt + INFO("Init interrupts..."); Interrupt.fall(&sw3ButtonHandler); - - - + //TFTStuff(); + // Boot the Avnet Shield before any other operations INFO("Net Boot..."); - net_modem_boot(); + TFT.printf ("Connecting to ATT LTE Network....\n"); + if (net_modem_boot() != 0) + { + TFT.printf ("Unable to Connect to ATT LTE Network. Please try again by rebooting the device.\n"); + return 0; + } + TFT.printf ("Connected to ATT LTE Network.\n"); + wait (3.0); + + if (GetSignalStrength(&dbm) != 0) + { + TFT.printf ("Unable to Signal Strength. Please try again by rebooting the device.\n"); + return 0; + } + + //========================================================================== // NOTE: You can comment in the following line for an alternate demo that // is used as the out-of-box demo binary that comes with the AT&T IoT // Starter Kit. It loops instead of the rest of Main() //return outOfBoxDemo(); //========================================================================== + + restart1: + // Intialize MQTT/Cert parameters ShadowParameters_t sp = ShadowParametersDefault; @@ -620,29 +957,81 @@ #else sp.pMyThingName = AWS_IOT_MY_THING_NAME; sp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID; - sp.pHost = HostAddress; + //sp.pHost = HostAddress; + INFO ("Host Name:"); + INFO (aws_iot_mqtt_host); + sp.pHost = aws_iot_mqtt_host; + INFO (sp.pHost); sp.port = port; sp.pClientCRT = AWS_IOT_CERTIFICATE_FILENAME; sp.pClientKey = AWS_IOT_PRIVATE_KEY_FILENAME; sp.pRootCA = AWS_IOT_ROOT_CA_FILENAME; #endif - +/* + char cBlockOffset[7]; + string sObject; + pc.printf ("Length = %d\n", AWS_IOT_CERTIFICATE_LENGTH ); + for (int i = 0; i < AWS_IOT_CERTIFICATE_LENGTH; i++) + { + sprintf (cBlockOffset, "%02X", AWS_IOT_CERTIFICATE[i]); + sObject += string (cBlockOffset); + + } + pc.printf(sObject.c_str()); + pc.printf("\n"); +*/ + int ret = 0; + mbedtls_x509_crt_init(&clicert); + ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *)AWS_IOT_CERTIFICATE, AWS_IOT_CERTIFICATE_LENGTH); + if (ret != 0) { + ERROR(" failed\n ! mbedtls_x509_crt_parse IOT returned 1 -0x%x, %d\n\n", -ret, AWS_IOT_CERTIFICATE_LENGTH); + TFT.printf ("Invalid Certificate. Please check the certificate and reboot the device."); + return ret; + } + else + { + for (int i = 0; i < clicert.subject_raw.len; i++) + { + if (clicert.subject_raw.p[i] == 0x0C) + { + i++; + unsigned char cLength = clicert.subject_raw.p[i]; + DEBUG ("subject length = %d", cLength); + i++; + for (int j = 0; j < (int) cLength; j++) + { + cSubject[j] = clicert.subject_raw.p[i]; + i++; + } + cSubject[cLength] = 0x00; + break; + } + } + } + + TFT.printf("Logging into %s AWS\n", sMQTTHostName); + TFT.printf("CN: %s\n", cSubject); INFO("Initialize the MQTT client..."); MQTTClient_t mqttClient; aws_iot_mqtt_init(&mqttClient); + string sAWSError = "\nUnable to Log into AWS. Invalid certificate. Please make sure the certificates in the SIM card are valid and reboot the device.\n"; + TFT.printf("."); INFO("Shadow Init..."); rc = aws_iot_shadow_init(&mqttClient); if (NONE_ERROR != rc) { ERROR("Shadow Init Error %d", rc); + TFT.printf(sAWSError.c_str()); return rc; } INFO("Shadow Connect..."); + TFT.printf("."); rc = aws_iot_shadow_connect(&mqttClient, &sp); if (NONE_ERROR != rc) { ERROR("Shadow Connection Error %d", rc); + TFT.printf(sAWSError.c_str()); return rc; } @@ -652,6 +1041,7 @@ rc = mqttClient.setAutoReconnectStatus(true); if (NONE_ERROR != rc) { ERROR("Unable to set Auto Reconnect to true - %d", rc); + TFT.printf(sAWSError.c_str()); return rc; } @@ -659,22 +1049,29 @@ //aws_iot_shadow_delete(&mqttClient, AWS_IOT_MY_THING_NAME, ShadowUpdateStatusCallback, NULL, 8, true); INFO("Shadow Register Delta..."); + TFT.printf("."); rc = aws_iot_shadow_register_delta(&mqttClient, &ledController); if (NONE_ERROR != rc) { ERROR("Shadow Register Delta Error"); + TFT.printf(sAWSError.c_str()); return rc; } INFO("Will attempt to sync with device shadow every %f seconds.", SHADOW_SYNC_INTERVAL); // Loop and publish changes from the FRDM board - while (NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc) { + + while (NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc) + { // Looks for incoming socket messages rc = aws_iot_shadow_yield(&mqttClient, 200); - if (NETWORK_ATTEMPTING_RECONNECT == rc) { + if (NETWORK_ATTEMPTING_RECONNECT == rc) + { // If the client is attempting to reconnect we will skip the rest of the loop. - INFO("Attempting to reconnect..."); + ShowINFO("Attempting to reconnect..."); wait(1); + bFirstTime = true; + //TFT.cls(); continue; } @@ -685,10 +1082,12 @@ INFO("\n=======================================================================================\n"); // Initialize JSON shadow document rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer); - if (rc == NONE_ERROR) { + if (rc == NONE_ERROR) + { // If there has been a SW3 button press update the 'desired' color - if (buttonOverride) { + if (buttonOverride) + { rc = aws_iot_shadow_add_desired(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 1, &ledController); buttonOverride = false; } @@ -698,10 +1097,12 @@ &temperatureHandler, &humidityHandler, &iccidHandler); - if (rc == NONE_ERROR) { + if (rc == NONE_ERROR) + { rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer); - if (rc == NONE_ERROR) { + if (rc == NONE_ERROR) + { INFO("Update Shadow: %s", JsonDocumentBuffer); rc = aws_iot_shadow_update(&mqttClient, sp.pMyThingName, JsonDocumentBuffer, ShadowUpdateStatusCallback, NULL, 8, true); @@ -709,17 +1110,70 @@ } } - // Print data + //get signal strength + GetSignalStrength(&dbm); + + //check if certificate is updated + + if (GetUpdateStatus(&cUpdateStatus) != 0) + { + ERROR("Get Update Status Error"); + } + else + { + if (cUpdateStatus == 0xFF) + { + TFT.cls(); + TFT.locate(0,10); + ShowINFO ("Certifcate Update Detected."); + ShowINFO("Disconnecting AWS"); + rc = aws_iot_shadow_disconnect(&mqttClient); + if (NONE_ERROR != rc) + { + ERROR("Disconnect error %d. Please reboot the device", rc); + return rc; + } + + if (GetAllObjects() != 0) + { + ShowINFO ("Read Certficate Error. Check hardware and Reboot the device.."); + return 0; + } + + wait(3.0); + bFirstTime = true; + goto restart1; + } + } + + + // Print data + if (bFirstTime == true) + { + TFT.cls(); + bFirstTime = false; + } + printDatatoTFT(); printData(); INFO("*****************************************************************************************"); // Set the LED color SetLedColor(ledColor); wait(SHADOW_SYNC_INTERVAL); + + if (count > 50) + { + INFO ("Max Upload reached. Please reset the device to start again"); + TFT.printf ("Max upload reached. Please reset the device to continue."); + return rc; + } + } - if (NONE_ERROR != rc) { + if (NONE_ERROR != rc) + { ERROR("An error occurred in the loop %d", rc); + TFT.printf("Fatal Error. Please reboot the device.\n"); } INFO("Disconnecting");