From 7832aa950661973decf3e8905617399d861cc8a7 Mon Sep 17 00:00:00 2001
From: RedSnake64 <RedSnake64Dev@t-online.de>
Date: Sun, 8 Mar 2015 18:41:48 +0100
Subject: [PATCH] Add tftbmp example for Arduino Yun

---
 examples/tftbmpYun/tftbmpYun.ino | 239 +++++++++++++++++++++++++++++++
 1 file changed, 239 insertions(+)
 create mode 100644 examples/tftbmpYun/tftbmpYun.ino

diff --git a/examples/tftbmpYun/tftbmpYun.ino b/examples/tftbmpYun/tftbmpYun.ino
new file mode 100644
index 0000000..d4d01bd
--- /dev/null
+++ b/examples/tftbmpYun/tftbmpYun.ino
@@ -0,0 +1,239 @@
+// BMP-loading example specifically for the TFTLCD breakout board.
+
+#include <Adafruit_GFX.h>    // Core graphics library
+#include <Adafruit_TFTLCD.h> // Hardware-specific library
+#include <FileIO.h>
+
+// The control pins for the LCD can be assigned to any digital or
+// analog pins...but we'll use the analog pins as this allows us to
+// double up the pins with the touch screen (see the TFT paint example).
+#define LCD_CS A3 // Chip Select goes to Analog 3
+#define LCD_CD A2 // Command/Data goes to Analog 2
+#define LCD_WR A1 // LCD Write goes to Analog 1
+#define LCD_RD A0 // LCD Read goes to Analog 0
+
+// When using the BREAKOUT BOARD only, use these 8 data lines to the LCD:
+// For the Arduino Yun
+//   D0 connects to digital pin 8  (Notice these are
+//   D1 connects to digital pin 9   NOT in order!)
+//   D2 connects to digital pin 2
+//   D3 connects to digital pin 3
+//   D4 connects to digital pin 4
+//   D5 connects to digital pin 5
+//   D6 connects to digital pin 6
+//   D7 connects to digital pin 7
+
+//
+//SD mount point
+const String sdMountPoint = "/mnt/sda1/";
+
+// In the SD card, place 24 bit color BMP files (be sure they are 24-bit!)
+// There are examples in the sketch folder
+
+// our TFT wiring
+Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, A4);
+
+void setup()
+{
+  Serial.begin(9600);
+
+  Bridge.begin();
+
+  tft.reset();
+
+  uint16_t identifier = tft.readID();
+
+  if(identifier == 0x9325) {
+    Serial.println(F("Found ILI9325 LCD driver"));
+  } else if(identifier == 0x9328) {
+    Serial.println(F("Found ILI9328 LCD driver"));
+  } else if(identifier == 0x7575) {
+    Serial.println(F("Found HX8347G LCD driver"));
+  } else {
+    Serial.print(F("Unknown LCD driver chip: "));
+    Serial.println(identifier, HEX);
+    Serial.println(F("If using the Adafruit 2.8\" TFT Arduino shield, the line:"));
+    Serial.println(F("  #define USE_ADAFRUIT_SHIELD_PINOUT"));
+    Serial.println(F("should appear in the library header (Adafruit_TFT.h)."));
+    Serial.println(F("If using the breakout board, it should NOT be #defined!"));
+    Serial.println(F("Also if using the breakout, double-check that all wiring"));
+    Serial.println(F("matches the tutorial."));
+    return;
+  }
+
+  tft.begin(identifier);
+
+  Serial.print(F("Initializing SD card..."));
+  if (!FileSystem.begin()) {
+    Serial.println(F("failed!"));
+    return;
+  }
+  Serial.println(F("OK!"));
+
+  bmpDraw("woof.bmp", 0, 0);
+  delay(1000);
+}
+
+void loop()
+{
+  for(int i = 0; i<4; i++) {
+    tft.setRotation(i);
+    tft.fillScreen(0);
+    for(int j=0; j <= 200; j += 50) {
+      bmpDraw("miniwoof.bmp", j, j);
+    }
+    delay(1000);
+  }
+}
+
+// This function opens a Windows Bitmap (BMP) file and
+// displays it at the given coordinates.  It's sped up
+// by reading many pixels worth of data at a time
+// (rather than pixel by pixel).  Increasing the buffer
+// size takes more of the Arduino's precious RAM but
+// makes loading a little faster.  20 pixels seems a
+// good balance.
+
+#define BUFFPIXEL 20
+
+void bmpDraw(String filename, int x, int y) {
+
+  File     bmpFile = FileSystem.open((sdMountPoint + filename).c_str());
+  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 in buffer (R+G+B per pixel)
+  uint16_t lcdbuffer[BUFFPIXEL];  // pixel out buffer (16-bit 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;
+  uint8_t  r, g, b;
+  uint32_t pos = 0, startTime = millis();
+  uint8_t  lcdidx = 0;
+  boolean  first = true;
+
+  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 == NULL) {
+    Serial.println(F("File not found"));
+    return;
+  }
+
+  // Parse BMP header
+  if(read16(&bmpFile) == 0x4D42) { // BMP signature
+    Serial.println(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
+        w = bmpWidth;
+        h = bmpHeight;
+        if((x+w-1) >= tft.width())  w = tft.width()  - x;
+        if((y+h-1) >= tft.height()) h = tft.height() - y;
+
+        // Set TFT address window to clipped image bounds
+        tft.setAddrWindow(x, y, x+w-1, y+h-1);
+
+        for (row=0; row<h; row++) { // For each scanline...
+          // Seek to start of scan line.  It might seem labor-
+          // intensive to be doing this on every line, but this
+          // method covers a lot of gritty details like cropping
+          // and scanline padding.  Also, the seek only takes
+          // place if the file position actually needs to change
+          // (avoids a lot of cluster math in SD library).
+          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
+            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
+          else     // Bitmap is stored top-to-bottom
+            pos = bmpImageoffset + row * rowSize;
+          if(bmpFile.position() != pos) { // Need seek?
+            bmpFile.seek(pos);
+            buffidx = sizeof(sdbuffer); // Force buffer reload
+          }
+
+          for (col=0; col<w; col++) { // For each column...
+            // Time to read more pixel data?
+            if (buffidx >= sizeof(sdbuffer)) { // Indeed
+              // Push LCD buffer to the display first
+              if(lcdidx > 0) {
+                tft.pushColors(lcdbuffer, lcdidx, first);
+                lcdidx = 0;
+                first  = false;
+              }
+              bmpFile.read(sdbuffer, sizeof(sdbuffer));
+              buffidx = 0; // Set index to beginning
+            }
+
+            // Convert pixel from BMP to TFT format
+            b = sdbuffer[buffidx++];
+            g = sdbuffer[buffidx++];
+            r = sdbuffer[buffidx++];
+            lcdbuffer[lcdidx++] = tft.color565(r,g,b);
+          } // end pixel
+        } // end scanline
+        // Write any remaining data to LCD
+        if(lcdidx > 0) {
+          tft.pushColors(lcdbuffer, lcdidx, first);
+        } 
+        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."));
+}
+
+// These read 16- and 32-bit types from the SD card file.
+// BMP data is stored little-endian, Arduino is little-endian too.
+// May need to reverse subscript order if porting elsewhere.
+
+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;
+}
+