#include #include #include #include "SPI.h" #include "Adafruit_GFX.h" //#include "./PDQ_ILI9341_config.h" //#include "PDQ_GFX.h" //#include "PDQ_ILI9341.h" #include "SD.h" #include // include fancy serif font #include // For the Adafruit shield, these are the default. #define TFT_DC 48 #define TFT_CS 49 // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC TFT_ILI9341 tft; extern "C" char __data_start[]; // start of SRAM data extern "C" char _end[]; // end of SRAM data (used to check amount of SRAM this program's variables use) extern "C" char __data_load_end[]; // end of FLASH (used to check amount of Flash this program's code and data uses) #include #include #include #include #include "Adafruit_seesaw.h" Adafruit_seesaw soil1; Adafruit_seesaw soil2; Adafruit_seesaw soil3; Adafruit_seesaw soil4; word pin00 = 0; word pin01 = 1; word pin02 = 2; word pin03 = 3; word pin04 = 4; word pin05 = 5; word pin06 = 6; word pin07 = 7; word pin08 = 8; word pin09 = 9; word pin10 = 10; word pin11 = 11; word pin12 = 12; word led = 13; word pin14 = 14; word pin15 = 15; word pin16 = 16; word pin17 = 17; word pin18 = 18; word SD_CS = 19; word pin20 = 20; word pin21 = 21; word pin22 = 22; word pin23 = 23; word pin24 = 24; word pin25 = 25; word pin26 = 26; word pin27 = 27; word pin28 = 28; word pin29 = 29; //word pin30 = 30; //word pin31 = 31; word pin32 = 32; word pin33 = 33; word pin34 = 34; word pin35 = 35; word pin36 = 36; word pin37 = 37; word pin38 = 38; word pin39 = 39; word pin40 = 40; word pin41 = 41; word pin42 = 42; word pin43 = 43; word pin44 = 44; word pin45 = 45; word pin46 = 46; word pin47 = 47; word pin48 = 48; word pin49 = 49; word pin50 = 50; word pin51 = 51; word pin52 = 52; word pin53 = 53; //word LCD_RD = A0; //word LCD_WR = A1; //word LCD_CD = A2; //word LCD_CS = A3; word pinA4 = A4; word pinA5 = A5; word pinA6 = A6; word pinA7 = A7; word pinA8 = A8; word pinA9 = A9; word pinA10 = A10; word pinA11 = A11; word pinA12 = A12; word pinA13 = A13; word pinA14 = A14; word pinA15 = A15; #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define YP A4 #define XM A5 #define YM 30 #define XP 31 #define TS_MINX 100 #define TS_MINY 150 #define TS_MAXX 900 #define TS_MAXY 900 TouchScreen ts = TouchScreen(XP, YP, XM, YM, 333); String outtext = ""; String oldtext = ""; boolean fastboot = false; boolean debug = true; boolean ps3 = false; boolean upd; boolean s1, s2, s3, s4; String outtext2 = ""; int linecount = 0; void setup(void) { Serial.begin(9600); //tft.reset(); #if defined(ILI9341_RST_PIN) // reset like Adafruit does FastPin::setOutput(); FastPin::hi(); FastPin::lo(); delay(1); FastPin::hi(); #endif tft.begin(); //tft.reset(); tft.setRotation(1); boolean didDraw = true; if(!fastboot) { //if (SD.begin(SD_CS)) { //tft.fillScreen(ILI9341_WHITE); //bmpDraw("gbs.bmp", 0, 0); //delay(4000); //} else { didDraw = false; // } tft.fillScreen(ILI9341_WHITE); //yield(); //tft.fillRect(0, 0, 320, 23, ILI9341_BLACK); } clearLog(); printFastCText("Booting GreenhouseOS..."); printFastCText(""); printFastCText(""); delay(250); if(!didDraw) { printFastCText("[FAILED] SD Card not detected!"); } printFastCText("[ OK ] Enabling powersaving features... "); // 53 characters wide example enablePS(3); upd = true; if (!soil1.begin(0x36)) { printFastCText("[ INFO ] Soil sensor 1 unplugged."); s1 = false; } else { String out = "[ OK ] Soil sensor 1 connected. Version: "; out += (soil1.getVersion(), HEX); printFastCText(out); s1 = true; } if (!soil2.begin(0x37)) { printFastCText("[ INFO ] Soil sensor 2 unplugged."); s2 = false; } else { String out = "[ OK ] Soil sensor 2 connected. Version: "; out += (soil2.getVersion(), HEX); printFastCText(out); s2 = true; } if (!soil3.begin(0x38)) { printFastCText("[ INFO ] Soil sensor 3 unplugged."); s3 = false; } else { String out = "[ OK ] Soil sensor 3 connected. Version: "; out += (soil3.getVersion(), HEX); printFastCText(out); s3 = true; } if (!soil4.begin(0x39)) { printFastCText("[ INFO ] Soil sensor 4 unplugged."); s4 = false; } else { String out = "[ OK ] Soil sensor 4 connected. Version: "; out += (soil4.getVersion(), HEX); printFastCText(out); s4 = true; } getMoisture(); } void loop(void) { if (ps3) { ADCSRA = 0; } if(Serial.available() > 0) { String txtin = "Serial: " + Serial.readString(); int x = 0; while(txtin.length() > 53) { printFastCText(txtin.substring(0, 53)); txtin = txtin.substring(53); } printFastCText(txtin.substring(0, txtin.length() - 1)); } unsigned long mil = millis(); /*String tmp = "["; if(mil / 1000 < 10) { tmp += " "; } else if(mil / 1000 < 100) { tmp += " "; } else if(mil / 1000 < 1000) { tmp += " "; } else if(mil / 1000 < 10000) { tmp += " "; } else if(mil / 1000 < 100000) { tmp += " "; } else if(mil / 1000 < 1000000) { tmp += " "; } tmp += mil / 1000; tmp += "."; if(mil % 1000 < 10) { tmp += "00"; } else if(mil % 1000 < 100) { tmp += "0"; } tmp += mil % 1000; tmp += "]";*/ //printConsoleText(tmp); //tft.scrollTo(320); if(mil % 60000 < 3000) { getMoisture(); delay(500); //tft.scrollTo(480); //tft.setAddrWindow(320, 0, 320, 240); } // change upd to true if screen update needed if(!debug && upd) { tft.fillScreen(ILI9341_BLACK); yield(); tft.fillRect(0, 0, 320, 20, ILI9341_WHITE); tft.setCursor(2, 2); tft.setTextSize(2); tft.setTextColor(ILI9341_BLACK); tft.print("Water Level: "); upd = false; } } #define BUFFPIXEL 80 /* void bmpDraw(char *filename, int16_t x, int16_t y) { File bmpFile; int bmpWidth, bmpHeight; // W+H in pixels uint8_t bmpDepth; // Bit depth (currently must be 24) uint32_t bmpImageoffset; // Start of image data in file uint32_t rowSize; // Not always = bmpWidth; may have padding uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer boolean goodBmp = false; // Set to true on valid header parse boolean flip = true; // BMP is stored bottom-to-top int w, h, row, col, x2, y2, bx1, by1; uint8_t r, g, b; uint32_t pos = 0, startTime = millis(); if((x >= tft.width()) || (y >= tft.height())) return; Serial.println(); Serial.print(F("Loading image '")); Serial.print(filename); Serial.println('\''); // Open requested file on SD card if ((bmpFile = SD.open(filename)) == NULL) { Serial.print(F("File not found")); return; } // Parse BMP header if(read16(bmpFile) == 0x4D42) { // BMP signature Serial.print(F("File size: ")); Serial.println(read32(bmpFile)); (void)read32(bmpFile); // Read & ignore creator bytes bmpImageoffset = read32(bmpFile); // Start of image data Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC); // Read DIB header Serial.print(F("Header size: ")); Serial.println(read32(bmpFile)); bmpWidth = read32(bmpFile); bmpHeight = read32(bmpFile); if(read16(bmpFile) == 1) { // # planes -- must be '1' bmpDepth = read16(bmpFile); // bits per pixel Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth); if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed goodBmp = true; // Supported BMP format -- proceed! Serial.print(F("Image size: ")); Serial.print(bmpWidth); Serial.print('x'); Serial.println(bmpHeight); // BMP rows are padded (if needed) to 4-byte boundary rowSize = (bmpWidth * 3 + 3) & ~3; // If bmpHeight is negative, image is in top-down order. // This is not canon but has been observed in the wild. if(bmpHeight < 0) { bmpHeight = -bmpHeight; flip = false; } // Crop area to be loaded x2 = x + bmpWidth - 1; // Lower-right corner y2 = y + bmpHeight - 1; if((x2 >= 0) && (y2 >= 0)) { // On screen? w = bmpWidth; // Width/height of section to load/display h = bmpHeight; bx1 = by1 = 0; // UL coordinate in BMP file if(x < 0) { // Clip left bx1 = -x; x = 0; w = x2 + 1; } if(y < 0) { // Clip top by1 = -y; y = 0; h = y2 + 1; } if(x2 >= tft.width()) w = tft.width() - x; // Clip right if(y2 >= tft.height()) h = tft.height() - y; // Clip bottom // Set TFT address window to clipped image bounds tft.startWrite(); // Requires start/end transaction now tft.setAddrWindow(x, y, w, h); for (row=0; row= sizeof(sdbuffer)) { // Indeed tft.endWrite(); // End TFT transaction bmpFile.read(sdbuffer, sizeof(sdbuffer)); buffidx = 0; // Set index to beginning tft.startWrite(); // Start new TFT transaction } // Convert pixel from BMP to TFT format, push to display b = sdbuffer[buffidx++]; g = sdbuffer[buffidx++]; r = sdbuffer[buffidx++]; tft.writePixel(tft.color565(r,g,b)); } // end pixel } // end scanline tft.endWrite(); // End last TFT transaction } // end onscreen Serial.print(F("Loaded in ")); Serial.print(millis() - startTime); Serial.println(" ms"); } // end goodBmp } } bmpFile.close(); if(!goodBmp) Serial.println(F("BMP format not recognized.")); } */ uint16_t read16(File &f) { uint16_t result; ((uint8_t *)&result)[0] = f.read(); // LSB ((uint8_t *)&result)[1] = f.read(); // MSB return result; } uint32_t read32(File &f) { uint32_t result; ((uint8_t *)&result)[0] = f.read(); // LSB ((uint8_t *)&result)[1] = f.read(); ((uint8_t *)&result)[2] = f.read(); ((uint8_t *)&result)[3] = f.read(); // MSB return result; } ISR (WDT_vect) { wdt_disable(); // disable watchdog } // end of WDT_vect void getMoisture() { if (s1) { float t1 = soil1.getTemp(); int sm1 = map(soil1.touchRead(0), 0, 1023, 0, 100); if(sm1 > 6000 && t1 < 1) { s1 = false; printFastCText("[ INFO ] Soil sensor 1 unplugged."); } else { printS1(t1, sm1); } } else if (!s1) { if (soil1.begin(0x36)) { clearLog(); s1 = true; printFastCText("[ INFO ] Soil sensor 1 connected."); float t1 = soil1.getTemp(); int sm1 = map(soil1.touchRead(0), 0, 1023, 0, 100); printS1(t1, sm1); } } if (s2) { float t2 = soil2.getTemp(); int sm2 = map(soil2.touchRead(0), 0, 1023, 0, 100); if(sm2 > 6000 && t2 < 1) { s2 = false; printFastCText("[ INFO ] Soil sensor 2 unplugged."); } else { printS2(t2, sm2); } } else if (!s2) { if (soil2.begin(0x37)) { clearLog(); s2 = true; printFastCText("[ INFO ] Soil sensor 2 connected."); float t2 = soil2.getTemp(); int sm2 = map(soil2.touchRead(0), 0, 1023, 0, 100); printS2(t2, sm2); } } if (s3) { float t3 = soil3.getTemp(); int sm3 = map(soil3.touchRead(0), 0, 1023, 0, 100); if(sm3 > 6000 && t3 < 1) { s3 = false; printFastCText("[ INFO ] Soil sensor 3 unplugged."); } else { printS3(t3, sm3); } } else if (!s3) { if (soil3.begin(0x38)) { clearLog(); s3 = true; printFastCText("[ INFO ] Soil sensor 3 connected."); float t3 = soil3.getTemp(); int sm3 = map(soil3.touchRead(0), 0, 1023, 0, 100); printS3(t3, sm3); } } if (s4) { float t4 = soil4.getTemp(); int sm4 = map(soil4.touchRead(0), 0, 1023, 0, 100); if(sm4 > 6000 && t4 < 1) { s4 = false; printFastCText("[ INFO ] Soil sensor 4 unplugged."); } else { printS4(t4, sm4); } } else if (!s4) { if (soil4.begin(0x39)) { clearLog(); s4 = true; printFastCText("[ INFO ] Soil sensor 4 connected."); float t4 = soil4.getTemp(); int sm4 = map(soil4.touchRead(0), 0, 1023, 0, 100); printS4(t4, sm4); } } } void printS1(float t, int sm) { String out = "[ OK ] Soil sensor 1 temperature: "; out += t; out += " C, "; out += (t * 9.0 / 5.0 + 32); out += " F"; printFastCText(out); out = ""; out += "[ OK ] Soil sensor 1 moisture: "; out += sm; out += "%"; printFastCText(out); } void printS2(float t, int sm) { String out = "[ OK ] Soil sensor 2 temperature: "; out += t; out += " C, "; out += (t * 9.0 / 5.0 + 32); out += " F"; printFastCText(out); out = ""; out += "[ OK ] Soil sensor 2 moisture: "; out += sm; out += "%"; printFastCText(out); } void printS3(float t, int sm) { String out = "[ OK ] Soil sensor 3 temperature: "; out += t; out += " C, "; out += (t * 9.0 / 5.0 + 32); out += " F"; printFastCText(out); out = ""; out += "[ OK ] Soil sensor 3 moisture: "; out += sm; out += "%"; printFastCText(out); } void printS4(float t, int sm) { String out = "[ OK ] Soil sensor 4 temperature: "; out += t; out += " C, "; out += (t * 9.0 / 5.0 + 32); out += " F"; printFastCText(out); out = ""; out += "[ OK ] Soil sensor 4 moisture: "; out += sm; out += "%"; printFastCText(out); } void enablePS(int level) { if (level > 0) { for(int x = 0; x <= 19; x++) { if(x != 8) { pinMode(x, OUTPUT); digitalWrite(x, LOW); } } for(int x = 32; x <= 53; x++) { pinMode(x, OUTPUT); digitalWrite(x, LOW); } printFastCText("[ OK ] Enabled Level 1 powersaving."); } else { printFastCText("[FAILED] Powersaving: Argument must be > 0."); } if(level > 1) { Serial.end(); power_adc_disable(); //power_spi_disable(); // needed for screen power_usart0_disable(); power_usart1_disable(); power_usart2_disable(); power_timer1_disable(); power_timer2_disable(); power_timer3_disable(); power_timer4_disable(); power_timer5_disable(); //power_twi_disable(); // twi needed for soil sensors / i2c printFastCText("[ OK ] Enabled Level 2 powersaving."); } if(level > 2) { // disable ADC ADCSRA = 0; //power_all_disable(); ps3 = true; printFastCText("[ OK ] Enabled Level 3 powersaving."); printFastCText("[ INFO ] All powersaving features enabled."); } } void clearLog() { outtext = ""; outtext2 = ""; linecount = 0; tft.fillScreen(ILI9341_BLACK); } void printFastCText(String text) { // NOTE: text MUST be under 53 characters long! (this is how the code runs faster) linecount ++; if (linecount > 30) { outtext2 = outtext2.substring(53); //scrollAddress(8); } if (text.length() < 53) { outtext2 += text; for (int x = text.length(); x < 53; x++) { outtext2 += " "; } } else { outtext2 += text; } if (debug) { //tft.setCursor(0, 0); //tft.fillScreen(BLACK); tft.setCursor(0, 0); tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); tft.setTextSize(1); //int cursory = linecount * 8; //for (int x = linecount - 1; x >= 0; x--) { //tft.setCursor(0, cursory - 8); //tft.fillRect(0, cursory - 8, 320, 8, BLACK); //tft.fillScreen(ILI9341_BLACK); tft.print(outtext2); //cursory -= 8; //} } } void scrollAddress(uint16_t vsp) { tft.writecommand(ILI9341_VSCRSADD); // Vertical scrolling pointer tft.writedata(vsp>>8); tft.writedata(vsp); }