Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
XkLi
Date:
Tue Oct 11 01:24:18 2011 +0000
Commit message:
v1.0

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
MPR121/mpr121.cpp Show annotated file Show diff for this revision Revisions of this file
MPR121/mpr121.h Show annotated file Show diff for this revision Revisions of this file
NokiaLCD/NokiaLCD.cpp Show annotated file Show diff for this revision Revisions of this file
NokiaLCD/NokiaLCD.h Show annotated file Show diff for this revision Revisions of this file
SDFileSystem/SDFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
SDFileSystem/SDFileSystem.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
myBMP/myBMP.cpp Show annotated file Show diff for this revision Revisions of this file
myBMP/myBMP.h Show annotated file Show diff for this revision Revisions of this file
picojpeg/jpegutil.c Show annotated file Show diff for this revision Revisions of this file
picojpeg/jpegutil.h Show annotated file Show diff for this revision Revisions of this file
picojpeg/picojpeg.c Show annotated file Show diff for this revision Revisions of this file
picojpeg/picojpeg.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPR121/mpr121.cpp	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,222 @@
+/*
+Copyright (c) 2011 Anthony Buckton (abuckton [at] blackink [dot} net {dot} au)
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <mbed.h>
+#include <sstream>
+#include <string>
+#include <list>
+
+#include <mpr121.h>
+
+Mpr121::Mpr121(I2C *i2c, Address i2cAddress)
+{
+    this->i2c = i2c;
+    
+    address = i2cAddress;
+           
+    // Configure the MPR121 settings to default
+    
+    this->configureSettings();
+}
+
+   
+void Mpr121::configureSettings()
+{
+    // Put the MPR into setup mode
+    this->write(ELE_CFG,0x00);
+    
+    // Electrode filters for when data is > baseline
+    unsigned char gtBaseline[] = {
+         0x01,  //MHD_R
+         0x01,  //NHD_R 
+         0x00,  //NCL_R
+         0x00   //FDL_R
+         };
+         
+    writeMany(MHD_R,gtBaseline,4);   
+                 
+     // Electrode filters for when data is < baseline   
+     unsigned char ltBaseline[] = {
+        0x01,   //MHD_F
+        0x01,   //NHD_F
+        0xFF,   //NCL_F
+        0x02    //FDL_F
+        };
+        
+    writeMany(MHD_F,ltBaseline,4);
+        
+    // Electrode touch and release thresholds
+    unsigned char electrodeThresholds[] = {
+        E_THR_T, // Touch Threshhold
+        E_THR_R  // Release Threshold
+        };
+
+    for(int i=0; i<12; i++){
+        int result = writeMany((ELE0_T+(i*2)),electrodeThresholds,2);
+    }   
+
+    // Proximity Settings
+    unsigned char proximitySettings[] = {
+        0xff,   //MHD_Prox_R
+        0xff,   //NHD_Prox_R
+        0x00,   //NCL_Prox_R
+        0x00,   //FDL_Prox_R
+        0x01,   //MHD_Prox_F
+        0x01,   //NHD_Prox_F
+        0xFF,   //NCL_Prox_F
+        0xff,   //FDL_Prox_F
+        0x00,   //NHD_Prox_T
+        0x00,   //NCL_Prox_T
+        0x00    //NFD_Prox_T
+        };
+    writeMany(MHDPROXR,proximitySettings,11);
+
+    unsigned char proxThresh[] = {
+        PROX_THR_T, // Touch Threshold
+        PROX_THR_R  // Release Threshold
+        };
+    writeMany(EPROXTTH,proxThresh,2); 
+       
+    this->write(FIL_CFG,0x04);
+    
+    // Set the electrode config to transition to active mode
+    this->write(ELE_CFG,0x0c);
+}
+
+void Mpr121::setElectrodeThreshold(int electrode, unsigned char touch, unsigned char release){
+    
+    if(electrode > 11) return;
+    
+    // Get the current mode
+    unsigned char mode = this->read(ELE_CFG);
+    
+    // Put the MPR into setup mode
+    this->write(ELE_CFG,0x00);
+    
+    // Write the new threshold
+    this->write((ELE0_T+(electrode*2)), touch);
+    this->write((ELE0_T+(electrode*2)+1), release);
+    
+    //Restore the operating mode
+    this->write(ELE_CFG, mode);
+}
+    
+    
+unsigned char Mpr121::read(int key){
+
+    unsigned char data[2];
+    
+    //Start the command
+    i2c->start();
+
+    // Address the target (Write mode)
+    int ack1= i2c->write(address);
+
+    // Set the register key to read
+    int ack2 = i2c->write(key);
+
+    // Re-start for read of data
+    i2c->start();
+
+    // Re-send the target address in read mode
+    int ack3 = i2c->write(address+1);
+
+    // Read in the result
+    data[0] = i2c->read(0); 
+
+    // Reset the bus        
+    i2c->stop();
+
+    return data[0];
+}
+
+
+int Mpr121::write(int key, unsigned char value){
+    
+    //Start the command
+    i2c->start();
+
+    // Address the target (Write mode)
+    int ack1= i2c->write(address);
+
+    // Set the register key to write
+    int ack2 = i2c->write(key);
+
+    // Read in the result
+    int ack3 = i2c->write(value); 
+
+    // Reset the bus        
+    i2c->stop();
+    
+    return (ack1+ack2+ack3)-3;
+}
+
+
+int Mpr121::writeMany(int start, unsigned char* dataSet, int length){
+    //Start the command
+    i2c->start();
+
+    // Address the target (Write mode)
+    int ack= i2c->write(address);
+    if(ack!=1){
+        return -1;
+    }
+    
+    // Set the register key to write
+    ack = i2c->write(start);
+    if(ack!=1){
+        return -1;
+    }
+
+    // Write the date set
+    int count = 0;
+    while(ack==1 && (count < length)){
+        ack = i2c->write(dataSet[count]);
+        count++;
+    } 
+    // Stop the cmd
+    i2c->stop();
+    
+    return count;
+}
+      
+
+bool Mpr121::getProximityMode(){
+    if(this->read(ELE_CFG) > 0x0c)
+        return true;
+    else
+        return false;
+}
+
+void Mpr121::setProximityMode(bool mode){
+    this->write(ELE_CFG,0x00);
+    if(mode){
+        this->write(ELE_CFG,0x30); //Sense proximity from ALL pads
+    } else {
+        this->write(ELE_CFG,0x0c); //Sense touch, all 12 pads active.
+    }
+}
+
+
+int Mpr121::readTouchData(){
+    return this->read(0x00);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPR121/mpr121.h	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,157 @@
+/*
+Copyright (c) 2011 Anthony Buckton (abuckton [at] blackink [dot} net {dot} au)
+
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+   Parts written by Jim Lindblom of Sparkfun
+   Ported to mbed by A.Buckton, Feb 2011
+*/
+
+#ifndef MPR121_H
+#define MPR121_H
+
+//using namespace std;
+
+class Mpr121 
+{
+
+public:
+    // i2c Addresses, bit-shifted
+    enum Address { ADD_VSS = 0xb4,// ADD->VSS = 0x5a <-wiring on Sparkfun board
+                   ADD_VDD = 0xb6,// ADD->VDD = 0x5b
+                   ADD_SCL = 0xb8,// ADD->SDA = 0x5c
+                   ADD_SDA = 0xba // ADD->SCL = 0x5d
+                 };
+
+    // Real initialiser, takes the i2c address of the device.
+    Mpr121(I2C *i2c, Address i2cAddress);
+    
+    bool getProximityMode();
+    
+    void setProximityMode(bool mode);
+    
+    int readTouchData();
+               
+    unsigned char read(int key);
+    
+    int write(int address, unsigned char value);
+    int writeMany(int start, unsigned char* dataSet, int length);
+
+    void setElectrodeThreshold(int electrodeId, unsigned char touchThreshold, unsigned char releaseThreshold);
+    void configureSettings();    
+protected:
+    // Configures the MPR with standard settings. This is permitted to be overwritten by sub-classes.
+    //void configureSettings();
+    
+private:
+    // The I2C bus instance.
+    I2C *i2c;
+
+    // i2c address of this mpr121
+    Address address;
+};
+
+
+// MPR121 Register Defines
+#define    MHD_R        0x2B
+#define    NHD_R        0x2C
+#define    NCL_R        0x2D
+#define    FDL_R        0x2E
+#define    MHD_F        0x2F
+#define    NHD_F        0x30
+#define    NCL_F        0x31
+#define    FDL_F        0x32
+#define    NHDT         0x33
+#define    NCLT         0x34
+#define    FDLT         0x35
+// Proximity sensing controls
+#define    MHDPROXR     0x36
+#define    NHDPROXR     0x37
+#define    NCLPROXR     0x38
+#define    FDLPROXR     0x39
+#define    MHDPROXF     0x3A
+#define    NHDPROXF     0x3B
+#define    NCLPROXF     0x3C
+#define    FDLPROXF     0x3D
+#define    NHDPROXT     0x3E
+#define    NCLPROXT     0x3F
+#define    FDLPROXT     0x40
+// Electrode Touch/Release thresholds
+#define    ELE0_T       0x41
+#define    ELE0_R       0x42
+#define    ELE1_T       0x43
+#define    ELE1_R       0x44
+#define    ELE2_T       0x45
+#define    ELE2_R       0x46
+#define    ELE3_T       0x47
+#define    ELE3_R       0x48
+#define    ELE4_T       0x49
+#define    ELE4_R       0x4A
+#define    ELE5_T       0x4B
+#define    ELE5_R       0x4C
+#define    ELE6_T       0x4D
+#define    ELE6_R       0x4E
+#define    ELE7_T       0x4F
+#define    ELE7_R       0x50
+#define    ELE8_T       0x51
+#define    ELE8_R       0x52
+#define    ELE9_T       0x53
+#define    ELE9_R       0x54
+#define    ELE10_T      0x55
+#define    ELE10_R      0x56
+#define    ELE11_T      0x57
+#define    ELE11_R      0x58
+// Proximity Touch/Release thresholds
+#define    EPROXTTH     0x59
+#define    EPROXRTH     0x5A
+// Debounce configuration
+#define    DEB_CFG      0x5B
+// AFE- Analogue Front End configuration
+#define    AFE_CFG      0x5C 
+// Filter configuration
+#define    FIL_CFG      0x5D
+// Electrode configuration - transistions to "active mode"
+#define    ELE_CFG      0x5E
+
+#define GPIO_CTRL0      0x73
+#define GPIO_CTRL1      0x74
+#define GPIO_DATA       0x75
+#define    GPIO_DIR     0x76
+#define    GPIO_EN      0x77
+#define    GPIO_SET     0x78
+#define GPIO_CLEAR      0x79
+#define GPIO_TOGGLE     0x7A
+// Auto configration registers
+#define    AUTO_CFG_0   0x7B
+#define    AUTO_CFG_U   0x7D
+#define    AUTO_CFG_L   0x7E
+#define    AUTO_CFG_T   0x7F
+
+// Threshold defaults
+// Electrode touch threshold
+#define    E_THR_T      0x0F   
+// Electrode release threshold 
+#define    E_THR_R      0x0A    
+// Prox touch threshold
+#define    PROX_THR_T   0x02
+// Prox release threshold
+#define    PROX_THR_R   0x02
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NokiaLCD/NokiaLCD.cpp	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,458 @@
+/* mbed Nokia LCD Library
+ * Copyright (c) 2007-2010, sford
+ */
+
+#include "NokiaLCD.h"
+
+#include "mbed.h"
+
+#define NOKIALCD_ROWS 16
+#define NOKIALCD_COLS 16
+#define NOKIALCD_WIDTH 130
+#define NOKIALCD_HEIGHT 130
+#define NOKIALCD_FREQUENCY 5000000
+
+NokiaLCD::NokiaLCD(PinName mosi, PinName sclk, PinName cs, PinName rst, LCDType type)
+        : _spi(mosi, NC, sclk)
+        , _rst(rst)
+        , _cs(cs) {
+
+    _type = type;
+
+    _row = 0;
+    _column = 0;
+    _foreground = 0x00FFFFFF;
+    _background = 0x00000000;
+
+    reset();
+}
+
+void NokiaLCD::reset() {
+
+    // setup the SPI interface and bring display out of reset
+    _cs = 1;
+    _rst = 0;
+    _spi.format(9);
+    _spi.frequency(NOKIALCD_FREQUENCY);
+    wait_ms(1);
+    _rst = 1;
+    wait_ms(1);
+
+    _cs = 0;
+
+    switch (_type) {
+        case LCD6100:
+            command(0xCA); // display control
+            data(0);
+            data(32);
+            data(0);
+            command(0xBB);
+            data(1);
+            command(0xD1); // oscillator on
+            command(0x94); // sleep out
+            command(0x20); // power control
+            data(0x0F);
+            command(0xA7); // invert display
+            command(0x81); // Voltage control
+            data(39);      // contrast setting: 0..63
+            data(3);       // resistance ratio
+            wait_ms(1);
+            command(0xBC);
+            data(0);
+            data(1);
+            data(4);
+            command(0xAF);  // turn on the display
+            break;
+            
+        case LCD6610:
+            command(0xCA);    // display control
+            data(0);
+            data(31);
+            data(0);
+            command(0xBB);
+            data(1);
+            command(0xD1); // oscillator on
+            command(0x94); // sleep out
+            command(0x20); // power control
+            data(0x0F);
+            command(0xA7); // invert display
+            command(0x81); // Voltage control
+            data(39);      // contrast setting: 0..63
+            data(3);       // resistance ratio
+            wait_ms(1);
+            command(0xBC);
+            data(0);
+            data(0);
+            data(2);
+            command(0xAF);  // turn on the display
+            break;
+            
+        case PCF8833:
+            command(0x11);  // sleep out
+            command(0x3A);  // column mode
+            data(0x05);
+            command(0x36);  // madctl
+            data(0x60);     // vertical RAM, flip x
+            command(0x25);  // setcon
+            data(0x30);// contrast 0x30
+            wait_ms(2);
+            command(0x29);//DISPON
+            command(0x03);//BSTRON
+            break;
+    }
+
+    _cs = 1;
+
+    cls();
+}
+
+void NokiaLCD::command(int value) {
+    _spi.write(value & 0xFF);
+}
+
+void NokiaLCD::data(int value) {
+    _spi.write(value | 0x100);
+}
+
+void NokiaLCD::_window(int x, int y, int width, int height) {
+    int x1 = x + 0;
+    int y1 = y + 0;
+    int x2 = x1 + width - 1;
+    int y2 = y1 + height - 1;
+
+    switch (_type) {
+        case LCD6100:
+        case LCD6610:
+            command(0x15); // column
+            data(x1);
+            data(x2);
+            command(0x75); // row
+            data(y1);
+            data(y2);
+            command(0x5C); // start write to ram
+            break;
+        case PCF8833:
+            command(0x2A);  // column
+            data(x1);
+            data(x2);
+            command(0x2B); // row
+            data(y1);
+            data(y2);
+            command(0x2C); // start write to ram
+            break;
+    }
+}
+
+void NokiaLCD::_putp(int colour) {
+    int gr = ((colour >> 20) & 0x0F)
+             | ((colour >> 8 ) & 0xF0);
+    int nb = ((colour >> 4 ) & 0x0F);
+    data(nb);
+    data(gr);
+}
+
+const unsigned char FONT8x8[97][8] = {
+    0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00, // columns, rows, num_bytes_per_char
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // space 0x20
+    0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00, // !
+    0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00, // "
+    0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00, // #
+    0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00, // $
+    0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00, // %
+    0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00, // &
+    0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00, // '
+    0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00, // (
+    0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00, // )
+    0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00, // *
+    0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00, // +
+    0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30, // ,
+    0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, // -
+    0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, // .
+    0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00, // / (forward slash)
+    0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00, // 0 0x30
+    0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00, // 1
+    0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00, // 2
+    0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00, // 3
+    0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00, // 4
+    0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00, // 5
+    0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00, // 6
+    0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00, // 7
+    0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00, // 8
+    0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00, // 9
+    0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00, // :
+    0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30, // ;
+    0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00, // <
+    0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00, // =
+    0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00, // >
+    0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00, // ?
+    0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00, // @ 0x40
+    0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00, // A
+    0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00, // B
+    0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00, // C
+    0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00, // D
+    0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00, // E
+    0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00, // F
+    0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00, // G
+    0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00, // H
+    0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // I
+    0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, // J
+    0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00, // K
+    0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00, // L
+    0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00, // M
+    0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00, // N
+    0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00, // O
+    0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00, // P 0x50
+    0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00, // Q
+    0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00, // R
+    0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00, // S
+    0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00, // T
+    0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00, // U
+    0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00, // V
+    0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00, // W
+    0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00, // X
+    0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00, // Y
+    0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00, // Z
+    0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00, // [
+    0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00, // \ (back slash)
+    0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00, // ]
+    0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00, // ^
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, // _
+    0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00, // ` 0x60
+    0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00, // a
+    0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00, // b
+    0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00, // c
+    0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00, // d
+    0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00, // e
+    0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00, // f
+    0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C, // g
+    0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00, // h
+    0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00, // i
+    0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C, // j
+    0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00, // k
+    0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // l
+    0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00, // m
+    0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00, // n
+    0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00, // o
+    0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78, // p
+    0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F, // q
+    0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00, // r
+    0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00, // s
+    0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00, // t
+    0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00, // u
+    0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00, // v
+    0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00, // w
+    0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00, // x
+    0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C, // y
+    0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00, // z
+    0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00, // {
+    0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00, // |
+    0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00, // }
+    0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00, // ~
+    0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00
+}; // DEL
+
+void NokiaLCD::locate(int column, int row) {
+    _column = column;
+    _row = row;
+}
+
+void NokiaLCD::newline() {
+    _column = 0;
+    _row++;
+    if (_row >= _rows) {
+        _row = 0;
+    }
+}
+
+int NokiaLCD::_putc(int value) {
+    int x = _column * 8;  // FIXME: Char sizes
+    int y = _row * 8;
+    bitblit(x + 1, y + 1, 8, 8, (char*)&(FONT8x8[value - 0x1F][0]));
+
+    _column++;
+
+    if (_column >= NOKIALCD_COLS) {
+        _row++;
+        _column = 0;
+    }
+
+    if (_row >= NOKIALCD_ROWS) {
+        _row = 0;
+    }
+
+    return value;
+}
+
+void NokiaLCD::cls() {
+    fill(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT, _background);
+    _row = 0;
+    _column = 0;
+}
+
+
+void NokiaLCD::window(int x, int y, int width, int height) {
+    _cs = 0;
+    _window(x, y, width, height);
+    _cs = 1;
+}
+
+void NokiaLCD::putp(int colour) {
+    _cs = 0;
+    _putp(colour);
+    _cs = 1;
+}
+
+void NokiaLCD::pixel(int x, int y, int colour) {
+    _cs = 0;
+    _window(x, y, 1, 1);
+     switch (_type) {
+        case LCD6100:
+        case PCF8833:
+           
+                _putp(colour);
+            
+            break;
+        case LCD6610:
+           
+                int r4 = (colour >> (16 + 4)) & 0xF;
+                int g4 = (colour >> (8 + 4)) & 0xF;
+                int b4 = (colour >> (0 + 4)) & 0xF;
+                int d1 = (r4 << 4) | g4;
+                int d2 = (b4 << 4) | r4;
+                int d3 = (g4 << 4) | b4;
+                data(d1); 
+                data(d2);   
+                data(d3);
+            
+            break;
+            }
+    _cs = 1;
+}
+
+void NokiaLCD::fill(int x, int y, int width, int height, int colour) {
+    _cs = 0;
+    _window(x, y, width, height);
+    switch (_type) {
+        case LCD6100:
+        case PCF8833:
+            for (int i=0; i<width*height; i++) {
+                _putp(colour);
+            }
+            break;
+        case LCD6610:
+            for (int i=0; i<width*height/2; i++) {
+                int r4 = (colour >> (16 + 4)) & 0xF;
+                int g4 = (colour >> (8 + 4)) & 0xF;
+                int b4 = (colour >> (0 + 4)) & 0xF;
+                int d1 = (r4 << 4) | g4;
+                int d2 = (b4 << 4) | r4;
+                int d3 = (g4 << 4) | b4;
+                data(d1); 
+                data(d2);   
+                data(d3);
+            }
+            break;
+    }
+    _window(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT);
+    _cs = 1;
+}
+
+void NokiaLCD::blit(int x, int y, int width, int height, const int* colour) {
+    _cs = 0;
+    _window(x, y, width, height);
+
+    switch (_type) {
+        case LCD6100:
+        case PCF8833:
+            for (int i=0; i<width*height; i++) {
+                 _putp(colour[i]);
+             }
+             break;
+        case LCD6610:
+            for (int i=0; i<width*height/2; i++) {
+                int r41 = (colour[i*2] >> (16 + 4)) & 0xF;
+                int g41 = (colour[i*2] >> (8 + 4)) & 0xF;
+                int b41 = (colour[i*2] >> (0 + 4)) & 0xF;
+           
+                int r42 = (colour[i*2+1] >> (16 + 4)) & 0xF;
+                int g42 = (colour[i*2+1] >> (8 + 4)) & 0xF;
+                int b42 = (colour[i*2+1] >> (0 + 4)) & 0xF;   
+                int d1 = (r41 << 4) | g41;
+                int d2 = (b41 << 4) | r42;
+                int d3 = (g42 << 4) | b42;               
+                   data(d1); 
+                data(d2); 
+                data(d3); 
+            }
+            break;
+     }            
+    _window(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT);
+    _cs = 1;
+}
+
+void NokiaLCD::bitblit(int x, int y, int width, int height, const char* bitstream) {
+    _cs = 0;
+    _window(x, y, width, height);
+
+    switch (_type) {
+        case LCD6100:
+        case PCF8833:
+            for (int i=0; i<height*width; i++) {
+                int byte = i / 8;
+                int bit = i % 8;
+                int colour = ((bitstream[byte] << bit) & 0x80) ? _foreground : _background;
+                _putp(colour);
+            }
+            break;
+        case LCD6610:
+            for(int i=0; i<height*width/2; i++) {
+                int byte1 = (i*2) / 8;
+                int bit1 = (i*2) % 8;   
+                int colour1 = ((bitstream[byte1] << bit1) & 0x80) ? _foreground : _background;
+                int byte2 = (i*2+1) / 8;
+                int bit2 = (i*2+1) % 8;   
+                int colour2 = ((bitstream[byte2] << bit2) & 0x80) ? _foreground : _background;
+    
+                int r41 = (colour1 >> (16 + 4)) & 0xF;
+                int g41 = (colour1 >> (8 + 4)) & 0xF;
+                int b41 = (colour1 >> (0 + 4)) & 0xF;
+           
+                int r42 = (colour2 >> (16 + 4)) & 0xF;
+                int g42 = (colour2 >> (8 + 4)) & 0xF;
+                int b42 = (colour2 >> (0 + 4)) & 0xF;   
+                int d1 = (r41 << 4) | g41;
+                int d2 = (b41 << 4) | r42;
+                int d3 = (g42 << 4) | b42;               
+                   data(d1); 
+                data(d2); 
+                data(d3); 
+            }
+            break;
+     }
+    _window(0, 0, _width, _height);
+    _cs = 1;
+}
+
+void NokiaLCD::foreground(int c) {
+    _foreground = c;
+}
+
+void NokiaLCD::background(int c) {
+    _background = c;
+}
+
+int NokiaLCD::width() {
+    return NOKIALCD_WIDTH;
+}
+
+int NokiaLCD::height() {
+    return NOKIALCD_HEIGHT;
+}
+
+int NokiaLCD::columns() {
+    return NOKIALCD_COLS;
+}
+
+int NokiaLCD::rows() {
+    return NOKIALCD_ROWS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NokiaLCD/NokiaLCD.h	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,151 @@
+/* mbed NokiaLCD Library, for a 130x130 Nokia colour LCD
+ * Copyright (c) 2007-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_NOKIALCD_H
+#define MBED_NOKIALCD_H
+
+#include "mbed.h"
+
+/** An interface for the 130x130 Nokia Mobile phone screens
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "NokiaLCD.h"
+ *
+ * NokiaLCD lcd(p5, p7, p8, p9, NokiaLCD::6610); // mosi, sclk, cs, rst, type
+ *
+ * int main() {
+ *     lcd.printf("Hello World!");
+ * }
+ * @endcode
+ */
+class NokiaLCD : public Stream {
+
+public:
+    /** LCD panel format */
+    enum LCDType {
+        LCD6100     /**< Nokia 6100, as found on sparkfun board (default) */
+        , LCD6610   /**< Nokia 6610, as found on olimex board */
+        , PCF8833
+    };
+
+    /** Create and Nokia LCD interface, using a SPI and two DigitalOut interfaces
+     *
+     * @param mosi SPI data out
+     * @param sclk SPI clock
+     * @param cs Chip Select (DigitalOut)
+     * @param rst Reset (DigitalOut)
+     * @param type The LCDType to select driver chip variants
+     */
+    NokiaLCD(PinName mosi, PinName sclk, PinName cs, PinName rst, LCDType type = LCD6100);
+
+#if DOXYGEN_ONLY
+    /** Write a character to the LCD
+     *
+     * @param c The character to write to the display
+     */
+    int putc(int c);
+
+    /** Write a formated string to the LCD
+     *
+     * @param format A printf-style format string, followed by the
+     *               variables to use in formating the string.
+     */
+    int printf(const char* format, ...);
+#endif
+
+    /** Locate to a screen column and row
+     *
+     * @param column  The horizontal position from the left, indexed from 0
+     * @param row     The vertical position from the top, indexed from 0
+     */
+    void locate(int column, int row);
+
+    /** Clear the screen and locate to 0,0 */
+    void cls();
+
+    /** Set a pixel on te screen
+     * 
+     * @param x horizontal position from left
+     * @param y vertical position from top
+     * @param colour 24-bit colour in format 0x00RRGGBB
+     */
+    void pixel(int x, int y, int colour);
+    
+    /** Fill an area of the screen
+     * 
+     * @param x horizontal position from left
+     * @param y vertical position from top
+     * @param width width in pixels
+     * @param height height in pixels
+     * @param colour 24-bit colour in format 0x00RRGGBB
+     */    
+    void fill(int x, int y, int width, int height, int colour);
+
+    void blit(int x, int y, int width, int height, const int* colour);
+    void bitblit(int x, int y, int width, int height, const char* bitstream);
+
+    int width();
+    int height();
+    int columns();
+    int rows();
+
+    void reset();
+
+    /** Set the foreground colour
+     * 
+     * @param c 24-bit colour
+     */
+    void foreground(int c);
+
+    /** Set the background colour
+     * 
+     * @param c 24-bit colour
+     */
+    void background(int c);
+
+protected:
+    virtual void _window(int x, int y, int width, int height);
+    virtual void _putp(int colour);
+
+    void command(int value);
+    void data(int value);
+
+    void newline();
+    virtual int _putc(int c);
+    virtual int _getc() {
+        return 0;
+    }
+    void putp(int v);
+    void window(int x, int y, int width, int height);
+
+    SPI _spi;
+    DigitalOut _rst;
+    DigitalOut _cs;
+
+    LCDType _type;
+    int _row, _column, _rows, _columns, _foreground, _background, _width, _height;
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem/SDFileSystem.cpp	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,457 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already 
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of: 
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will 
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and 
+ * indirectly determine whether it is a version 1.x SD/non-SD card or 
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ * 
+ * The protocol supports a CRC, but by default it is off (except for the 
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think! 
+ * 
+ * Standard capacity cards have variable data block sizes, whereas High 
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks 
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then 
+ * a data token or an error.
+ * 
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising 
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte 
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *  
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] | 
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+ 
+#include "SDFileSystem.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+  FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
+      _cs = 1; 
+}
+
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+//  - v1.x Standard Capacity
+//  - v2.x Standard Capacity
+//  - v2.x High Capacity
+//  - Not recognised as an SD Card
+
+#define SDCARD_FAIL 0
+#define SDCARD_V1   1
+#define SDCARD_V2   2
+#define SDCARD_V2HC 3
+
+int SDFileSystem::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000); 
+    _cs = 1;
+    for(int i=0; i<16; i++) {   
+        _spi.write(0xFF);
+    }
+
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if(_cmd(0, 0) != R1_IDLE_STATE) { 
+        fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
+        return SDCARD_FAIL;
+    }
+
+    // send CMD8 to determine whther it is ver 2.x
+    int r = _cmd8();
+    if(r == R1_IDLE_STATE) {
+        return initialise_card_v2();
+    } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+        return initialise_card_v1();
+    } else {
+        fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
+    }
+}
+
+int SDFileSystem::initialise_card_v1() {
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            return SDCARD_V1;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+    
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            _cmd58();
+            return SDCARD_V2;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+
+    int i = initialise_card();
+//    printf("init card = %d\n", i);
+//    printf("OK\n");
+
+    _sectors = _sd_sectors();
+
+    // Set block length to 512 (CMD16)
+    if(_cmd(16, 512) != 0) {
+        fprintf(stderr, "Set 512-byte block timed out\n");
+        return 1;
+    }
+        
+    _spi.frequency(1000000); // Set to 1MHz for data transfer
+    return 0;
+}
+
+int SDFileSystem::disk_write(const char *buffer, int block_number) {
+    // set write address for single block (CMD24)
+    if(_cmd(24, block_number * 512) != 0) {
+        return 1;
+    }
+
+    // send the data block
+    _write(buffer, 512);    
+    return 0;    
+}
+
+int SDFileSystem::disk_read(char *buffer, int block_number) {        
+    // set read address for single block (CMD17)
+    if(_cmd(17, block_number * 512) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+int SDFileSystem::disk_status() { return 0; }
+int SDFileSystem::disk_sync() { return 0; }
+int SDFileSystem::disk_sectors() { return _sectors; }
+
+// PRIVATE FUNCTIONS
+
+int SDFileSystem::_cmd(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+int SDFileSystem::_cmdx(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+    _cs = 0; 
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+//            printf("OCR = 0x%08X\n", ocr);
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_cmd8() {
+    _cs = 0; 
+    
+    // send a command
+    _spi.write(0x40 | 8); // CMD8
+    _spi.write(0x00);     // reserved
+    _spi.write(0x00);     // reserved
+    _spi.write(0x01);     // 3.3v
+    _spi.write(0xAA);     // check pattern
+    _spi.write(0x87);     // crc
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
+        char response[5];
+        response[0] = _spi.write(0xFF);
+        if(!(response[0] & 0x80)) {
+                for(int j=1; j<5; j++) {
+                    response[i] = _spi.write(0xFF);
+                }
+                _cs = 1;
+                _spi.write(0xFF);
+                return response[0];
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_read(char *buffer, int length) {
+    _cs = 0;
+
+    // read until start byte (0xFF)
+    while(_spi.write(0xFF) != 0xFE);
+
+    // read data
+    for(int i=0; i<length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+
+    _cs = 1;    
+    _spi.write(0xFF);
+    return 0;
+}
+
+int SDFileSystem::_write(const char *buffer, int length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for(int i=0; i<length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF); 
+    _spi.write(0xFF);
+
+    // check the repsonse token
+    if((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1;
+        _spi.write(0xFF);        
+        return 1;
+    }
+
+    // wait for write to finish
+    while(_spi.write(0xFF) == 0);
+
+    _cs = 1; 
+    _spi.write(0xFF);
+    return 0;
+}
+
+static int ext_bits(char *data, int msb, int lsb) {
+    int bits = 0;
+    int size = 1 + msb - lsb; 
+    for(int i=0; i<size; i++) {
+        int position = lsb + i;
+        int byte = 15 - (position >> 3);
+        int bit = position & 0x7;
+        int value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+int SDFileSystem::_sd_sectors() {
+
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if(_cmdx(9, 0) != 0) {
+        fprintf(stderr, "Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    char csd[16];    
+    if(_read(csd, 16) != 0) {
+        fprintf(stderr, "Couldn't read csd response from disk\n");
+        return 0;
+    }
+
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
+
+    int csd_structure = ext_bits(csd, 127, 126);
+    int c_size = ext_bits(csd, 73, 62);
+    int c_size_mult = ext_bits(csd, 49, 47);
+    int read_bl_len = ext_bits(csd, 83, 80);
+
+//    printf("CSD_STRUCT = %d\n", csd_structure);
+    
+    if(csd_structure != 0) {
+        fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
+        return 0;
+    }
+             
+    // memory capacity = BLOCKNR * BLOCK_LEN
+    // where
+    //  BLOCKNR = (C_SIZE+1) * MULT
+    //  MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+    //  BLOCK_LEN = 2^READ_BL_LEN, (READ_BL_LEN < 12)         
+                            
+    int block_len = 1 << read_bl_len;
+    int mult = 1 << (c_size_mult + 2);
+    int blocknr = (c_size + 1) * mult;
+    int capacity = blocknr * block_len;
+        
+    int blocks = capacity / 512;
+        
+    return blocks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem/SDFileSystem.h	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,81 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_SDFILESYSTEM_H
+#define MBED_SDFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/** Access the filesystem on an SD Card using SPI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "SDFileSystem.h"
+ *
+ * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs
+ *  
+ * int main() {
+ *     FILE *fp = fopen("/sd/myfile.txt", "w");
+ *     fprintf(fp, "Hello World!\n");
+ *     fclose(fp);
+ * }
+ */
+class SDFileSystem : public FATFileSystem {
+public:
+
+    /** Create the File System for accessing an SD Card using SPI
+     *
+     * @param mosi SPI mosi pin connected to SD Card
+     * @param miso SPI miso pin conencted to SD Card
+     * @param sclk SPI sclk pin connected to SD Card
+     * @param cs   DigitalOut pin used as SD Card chip select
+     * @param name The name used to access the virtual filesystem
+     */
+    SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+    virtual int disk_initialize();
+    virtual int disk_write(const char *buffer, int block_number);
+    virtual int disk_read(char *buffer, int block_number);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual int disk_sectors();
+
+protected:
+
+    int _cmd(int cmd, int arg);
+    int _cmdx(int cmd, int arg);
+    int _cmd8();
+    int _cmd58();
+    int initialise_card();
+    int initialise_card_v1();
+    int initialise_card_v2();
+    
+    int _read(char *buffer, int length);
+    int _write(const char *buffer, int length);
+    int _sd_sectors();
+    int _sectors;
+    
+    SPI _spi;
+    DigitalOut _cs;     
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,186 @@
+#include "mbed.h"
+#include "SDFileSystem.h"
+#include "NokiaLCD.h"
+#include "myBMP.h"
+#include "mpr121.h"
+#include "jpegutil.h"
+#include <string>
+#include <cctype>
+
+SDFileSystem sd(p5, p6, p7, p8, "sd");
+NokiaLCD lcd(p11, p13, p14, p15, NokiaLCD::LCD6610);
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+InterruptIn interrupt(p26);
+I2C i2c(p9,p10);
+Mpr121 mpr121(&i2c, Mpr121::ADD_VSS);
+Serial pc(USBTX,USBRX);
+vector<string> files;
+string file;
+int selectpos = 1;
+int oldvalue;
+int value;
+bool showingImage = false;
+bool displayImage = false;
+
+
+string toLower(string in)
+{
+    for(int i = 0; i < in.length(); i++)
+    {
+        in[i] = tolower(in[i]);
+    }
+    return in;
+}
+
+void changepos(int val2,int val1){ //compares the current position with the old one andchanges currsor accordingly.
+//val1 is the lower value ond val2 th higher possibla value
+
+if (!showingImage) {
+                if (oldvalue==val1) {
+                    if (selectpos != 1)
+                    selectpos--;
+                    // if (selectpos < 1)selectpos = files.size(); // no more raparround
+                } else if(oldvalue==val2){
+                    if (selectpos != files.size())
+                    selectpos++;
+                    //if (selectpos > files.size()) selectpos = 1; // no more raparound
+                }
+            }
+}
+
+void fallInterrupt() {
+    value=mpr121.read(0x00);
+    value +=mpr121.read(0x01)<<8;
+    //pc.printf("%d\r\n",value);
+    switch (value) {
+        case 0: //no button is pressed (good only to execute actions on release)
+                switch (oldvalue) { //if not do action according to button realeased.
+                    case (1<<4):
+                        if (showingImage) {
+                            lcd.background(0xFFFFFF);
+                            lcd.foreground(0xFFFFFF);
+                            lcd.cls();
+                            showingImage = false;
+                        }
+                        break;
+
+                    case (1<<5):
+                        if (!showingImage) {
+                            displayImage = true;
+                            showingImage = true;
+                        }
+                        break;
+                
+            }
+            case 1:
+            changepos(-1,3); //cannot have a lower value as 0 i no button
+            break;
+        case 3:
+            changepos(1,2);
+            break;
+        case 2:
+            changepos((2+1),(2+4));
+            break;
+        case (2+4):
+            changepos(2,4);
+            break;
+        case 4:
+            changepos((4+2),(4+8));
+            break;
+        case (4+8):
+            changepos(4,8);
+            break;
+        case 8:
+            changepos(4+8,-1); // cannot have a highe boundry
+            break;
+
+        default:
+
+            break;
+    };
+
+    oldvalue=value;
+}
+
+void ls(char *dir)
+{
+    DIR *dp;
+    struct dirent *dirp;
+    dp = opendir(dir);
+    while((dirp = readdir(dp)) != NULL)
+    {
+        files.push_back(string(dirp->d_name));
+    }
+}
+
+int main() {
+    interrupt.fall(&fallInterrupt);
+    interrupt.mode(PullUp);
+    
+    lcd.background(0xFFFFFF);
+    lcd.foreground(0xFFFFFF);
+    lcd.cls();
+    ls("/sd");
+    
+    led1 = 1;
+    
+    while(1) {
+        int ypos = 1;
+        if(displayImage)
+        {
+            __disable_irq();
+            file = files[selectpos - 1];
+            string ext = file.substr(file.rfind('.')+1);
+            ext = toLower(ext);
+            if(!ext.compare("bmp"))
+            {
+                RGBApixel *Colors = new RGBApixel [2];
+                file = "/sd/" + file;
+                lcd.background(0x000000);
+                lcd.foreground(0x000000);
+                lcd.cls();
+                ReadBMPFromFile(file.c_str(), Colors, &lcd);
+                showingImage = true;
+            }
+            else if(!ext.compare("jpeg") || !ext.compare("jpg"))
+            {
+                file = "/sd/" + file;
+                lcd.background(0x000000);
+                lcd.foreground(0x000000);
+                lcd.cls();
+                ReadJPEGFromFile(file.c_str(), &lcd);
+                showingImage = true;
+            }
+            else
+            {
+                showingImage = false;
+            }
+            displayImage = false;
+            __enable_irq();
+        }
+        if(!showingImage)
+        {
+            lcd.background(0xFFFFFF);
+            lcd.locate(0,ypos);
+            for(vector<string>::iterator it=files.begin(); it < files.end(); it++)
+            {
+                if(ypos == selectpos)
+                {
+                    lcd.foreground(0xFF0000);
+                }
+                else
+                {
+                    lcd.foreground(0x000000);
+                }
+                lcd.printf("%s",(*it).c_str());
+                ypos++;
+                lcd.locate(0,ypos);
+            }
+        }
+        led1 = !led1;
+        wait(0.05);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/myBMP/myBMP.cpp	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,456 @@
+#include "myBMP.h"
+
+int BitDepth = 1;
+int Width = 1;
+int Height = 1;
+RGBApixel *Colors;
+
+bool SafeFread( char* buffer, int size, int number, FILE* fp )
+{
+ using namespace std;
+ int ItemsRead;
+ if( feof(fp) )
+ { return false; }
+ ItemsRead = (int) fread( buffer , size , number , fp );
+ if( ItemsRead < number )
+ { return false; }
+ return true;
+}
+
+bool Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
+{ 
+ int i;
+ char Colors[4];
+ if( Width*4 > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ {
+    memcpy( (char*) &(Colors), (char*) Buffer+4*i, 4 );
+     //Blue, Green, Red, Alpha
+    int color = 0x00000000 | (Colors[2] << 16) | (Colors[1] << 8) | (Colors[0]);
+    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
+ }
+ return true;
+}
+
+bool Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
+{ 
+ int i;
+ char Colors[4];
+ if( Width*3 > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ {
+    memcpy( (char*) &(Colors), (char*) Buffer+3*i, 3 );
+     //Blue, Green, Red, Alpha
+    int color = 0x00000000 | (Colors[2] << 16) | (Colors[1] << 8) | (Colors[0]);
+    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
+ }
+ return true;
+}
+
+RGBApixel GetColor( int ColorNumber)
+{ 
+ RGBApixel Output;
+ Output.Red   = 255;
+ Output.Green = 255;
+ Output.Blue  = 255;
+ Output.Alpha = 0;
+ 
+ if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
+ {
+  return Output;
+ }
+ if( !Colors )
+ {
+  return Output; 
+ }
+ Output = Colors[ColorNumber];
+ return Output;
+}
+
+bool Read8bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
+{
+ int i;
+ if( Width > BufferSize )
+ { return false; }
+ for( i=0 ; i < Width ; i++ )
+ {
+    int Index = Buffer[i];
+     //Blue, Green, Red, Alpha
+    RGBApixel colors = GetColor(Index);
+    int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
+    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
+ }
+ return true;
+}
+
+bool Read4bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
+{
+ int Shifts[2] = {4  ,0 };
+ int Masks[2]  = {240,15};
+ 
+ int i=0;
+ int j;
+ int k=0;
+ if( Width > 2*BufferSize )
+ { return false; }
+ while( i < Width )
+ {
+  j=0;
+  while( j < 2 && i < Width )
+  {
+   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
+   RGBApixel colors = GetColor(Index);
+   int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
+   (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
+   i++; j++;   
+  }
+  k++;
+ }
+ return true;
+}
+bool Read1bitRow(  ebmpBYTE* Buffer, int BufferSize, int Row, NokiaLCD *lcd)
+{
+ int Shifts[8] = {7  ,6 ,5 ,4 ,3,2,1,0};
+ int Masks[8]  = {128,64,32,16,8,4,2,1};
+ 
+ int i=0;
+ int j;
+ int k=0;
+ 
+ if( Width > 8*BufferSize )
+ { return false; }
+ while( i < Width )
+ {
+  j=0;
+  while( j < 8 && i < Width )
+  {
+   int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
+   RGBApixel colors = GetColor(Index);
+   int color = 0x00000000 | (colors.Red<< 16) | (colors.Blue << 8) | (colors.Green);
+   (*lcd).pixel((130-Width)/2+i,(130-Height)/2+Row,color);
+   i++; j++;   
+  }
+  k++;
+ }
+ return true;
+}
+
+int TellNumberOfColors( int BitDepth )
+{
+ int output = 1 << BitDepth;
+ if( BitDepth == 32 )
+ { output = 1 << 24; }
+ return output;
+}
+
+bool ReadBMPFromFile( const char* FileName, RGBApixel *Colors, NokiaLCD *lcd)
+{ 
+ FILE* fp = fopen( FileName, "rb" );
+ if( fp == NULL )
+ {
+  return false;
+ }
+ 
+ // read the file header 
+ 
+ BMFH bmfh;
+ bool NotCorrupted = true;
+ 
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);
+ 
+ bool IsBitmap = false;
+ 
+ if( bmfh.bfType == 19778 )
+ { IsBitmap = true; }
+ 
+ if( !IsBitmap ) 
+ {
+  fclose( fp ); 
+  return false;
+ }
+
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp); 
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
+ NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);
+ 
+ // read the info header
+
+ BMIH bmih; 
+ 
+ NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp); 
+ NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp); 
+ NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);
+
+ NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
+ NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
+ 
+ // a safety catch: if any of the header information didn't read properly, abort
+ // future idea: check to see if at least most is self-consistent
+  
+ if( !NotCorrupted )
+ {
+  fclose(fp);
+  return false;
+ } 
+ 
+ // if bmih.biCompression 1 or 2, then the file is RLE compressed
+ 
+ if( bmih.biCompression == 1 || bmih.biCompression == 2 )
+ {
+  fclose(fp);
+  return false; 
+ }
+ 
+ // if bmih.biCompression > 3, then something strange is going on 
+ // it's probably an OS2 bitmap file.
+ 
+ if( bmih.biCompression > 3 )
+ {
+  fclose(fp);
+  return false; 
+ }
+ 
+ if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
+ {
+  fclose(fp);
+  return false; 
+ }
+
+ // set the bit depth
+ 
+ int TempBitDepth = (int) bmih.biBitCount;
+ if(    TempBitDepth != 1  && TempBitDepth != 4 
+     && TempBitDepth != 8  && TempBitDepth != 16
+     && TempBitDepth != 24 && TempBitDepth != 32 )
+ {
+  fclose(fp);
+  return false;
+ }
+ BitDepth = (int)bmih.biBitCount;
+ // set the size
+
+ if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 ) 
+ {
+  fclose(fp);
+  return false;
+ } 
+ Width = (int) bmih.biWidth;
+ Height = (int) bmih.biHeight;
+ // some preliminaries
+ 
+ double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
+ double dBytesPerRow = dBytesPerPixel * (Width+0.0);
+ dBytesPerRow = ceil(dBytesPerRow);
+  
+ int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
+ if( BytePaddingPerRow == 4 )
+ { BytePaddingPerRow = 0; }  
+ 
+ // if < 16 bits, read the palette
+ 
+ if( BitDepth < 16 )
+ {
+  // determine the number of colors specified in the 
+  // color table
+  
+  int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;  
+  if( NumberOfColorsToRead > (1 << BitDepth) )
+  { NumberOfColorsToRead = (1 << BitDepth); }
+ 
+  int n;
+  for( n=0; n < NumberOfColorsToRead ; n++ )
+  {
+   SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);     
+  }
+  for( n=NumberOfColorsToRead ; n < TellNumberOfColors(BitDepth) ; n++ )
+  {
+   RGBApixel WHITE; 
+   WHITE.Red = 255;
+   WHITE.Green = 255;
+   WHITE.Blue = 255;
+   WHITE.Alpha = 0;
+   Colors[n] = WHITE;
+  }
+ }
+ 
+ // skip blank data if bfOffBits so indicates
+ 
+ int BytesToSkip = bmfh.bfOffBits - 54;;
+ if( BitDepth < 16 )
+ { BytesToSkip -= 4*(1 << BitDepth); }
+ if( BitDepth == 16 && bmih.biCompression == 3 )
+ { BytesToSkip -= 3*4; }
+ if( BytesToSkip < 0 )
+ { BytesToSkip = 0; }
+ if( BytesToSkip > 0 && BitDepth != 16 )
+ {
+  ebmpBYTE* TempSkipBYTE;
+  TempSkipBYTE = new ebmpBYTE [BytesToSkip];
+  SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);   
+  delete [] TempSkipBYTE;
+ } 
+  
+ // This code reads 1, 4, 8, 24, and 32-bpp files 
+ // with a more-efficient buffered technique.
+
+ int i,j;
+ if( BitDepth != 16 )
+ {
+  int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
+  while( 8*BufferSize < Width*BitDepth )
+  { BufferSize++; }
+  while( BufferSize % 4 )
+  { BufferSize++; }
+  ebmpBYTE* Buffer;
+  Buffer = new ebmpBYTE [BufferSize];
+  j= Height-1;
+  while( j > -1 )
+  {
+   int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
+   if( BytesRead < BufferSize )
+   {
+    j = -1; 
+   }
+   else
+   {
+    bool Success = false;
+    if( BitDepth == 1  )
+    { Success = Read1bitRow(  Buffer, BufferSize, j , lcd); }
+    if( BitDepth == 4  )
+    { Success = Read4bitRow(  Buffer, BufferSize, j , lcd); }
+    if( BitDepth == 8  )
+    { Success = Read8bitRow(  Buffer, BufferSize, j , lcd); }
+    if( BitDepth == 24 )
+    { Success = Read24bitRow( Buffer, BufferSize, j , lcd); }
+    if( BitDepth == 32 )
+    { Success = Read32bitRow( Buffer, BufferSize, j , lcd); }
+    if( !Success )
+    {
+     j = -1;
+    }
+   }   
+   j--;
+  }
+  delete [] Buffer; 
+ }
+
+ if( BitDepth == 16 )
+ {
+  int DataBytes = Width*2;
+  int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
+
+  // set the default mask
+  
+  ebmpWORD BlueMask = 31; // bits 12-16
+  ebmpWORD GreenMask = 992; // bits 7-11
+  ebmpWORD RedMask = 31744; // bits 2-6
+
+  // read the bit fields, if necessary, to 
+  // override the default 5-5-5 mask
+  
+  if( bmih.biCompression != 0 )
+  {
+   // read the three bit masks
+
+   ebmpWORD TempMaskWORD;
+  
+   SafeFread( (char*) &RedMask , 2 , 1 , fp );
+   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
+  
+   SafeFread( (char*) &GreenMask , 2 , 1 , fp );
+   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
+
+   SafeFread( (char*) &BlueMask , 2 , 1 , fp );
+   SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
+  }
+  
+  // read and skip any meta data
+
+  if( BytesToSkip > 0 )
+  {
+   ebmpBYTE* TempSkipBYTE;
+   TempSkipBYTE = new ebmpBYTE [BytesToSkip];
+   SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
+   delete [] TempSkipBYTE;   
+  } 
+  
+  // determine the red, green and blue shifts
+  
+  int GreenShift = 0; 
+  ebmpWORD TempShiftWORD = GreenMask;
+  while( TempShiftWORD > 31 )
+  { TempShiftWORD = TempShiftWORD>>1; GreenShift++; }  
+  int BlueShift = 0;
+  TempShiftWORD = BlueMask;
+  while( TempShiftWORD > 31 )
+  { TempShiftWORD = TempShiftWORD>>1; BlueShift++; }  
+  int RedShift = 0;  
+  TempShiftWORD = RedMask;
+  while( TempShiftWORD > 31 )
+  { TempShiftWORD = TempShiftWORD>>1; RedShift++; }  
+  
+  // read the actual pixels
+  
+  for( j=Height-1 ; j >= 0 ; j-- )
+  {
+   i=0;
+   int ReadNumber = 0;
+   while( ReadNumber < DataBytes )
+   {
+    ebmpWORD TempWORD;
+    SafeFread( (char*) &TempWORD , 2 , 1 , fp );
+    ReadNumber += 2;
+  
+    ebmpWORD Red = RedMask & TempWORD;
+    ebmpWORD Green = GreenMask & TempWORD;
+    ebmpWORD Blue = BlueMask & TempWORD;
+                
+    ebmpBYTE BlueBYTE = (ebmpBYTE) 8*(Blue>>BlueShift);
+    ebmpBYTE GreenBYTE = (ebmpBYTE) 8*(Green>>GreenShift);
+    ebmpBYTE RedBYTE = (ebmpBYTE) 8*(Red>>RedShift);
+        
+    int color = 0x00000000 | (RedBYTE << 16) | (GreenBYTE << 8) | (BlueBYTE);
+    (*lcd).pixel((130-Width)/2+i,(130-Height)/2+j,color);
+    i++;
+   }
+   ReadNumber = 0;
+   while( ReadNumber < PaddingBytes )
+   {
+    ebmpBYTE TempBYTE;
+    SafeFread( (char*) &TempBYTE , 1, 1, fp);
+    ReadNumber++;
+   }
+  }
+
+ }
+ 
+ fclose(fp);
+ return true;
+}
+
+
+BMIH::BMIH()
+{
+ biPlanes = 1;
+ biCompression = 0;
+ biXPelsPerMeter = DefaultXPelsPerMeter;  
+ biYPelsPerMeter = DefaultYPelsPerMeter;
+ biClrUsed = 0;
+ biClrImportant = 0;
+}
+
+BMFH::BMFH()
+{
+ bfType = 19778;
+ bfReserved1 = 0;
+ bfReserved2 = 0;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/myBMP/myBMP.h	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,47 @@
+// Code taken and hacked from EasyBMP library by Paul Macklin
+
+#include "NokiaLCD.h"
+#include "SDFileSystem.h"
+
+#define DefaultXPelsPerMeter 3780
+#define DefaultYPelsPerMeter 3780
+
+typedef unsigned char  ebmpBYTE;
+typedef unsigned short ebmpWORD;
+typedef unsigned int  ebmpDWORD;
+
+typedef struct RGBApixel {
+    ebmpBYTE Blue;
+    ebmpBYTE Green;
+    ebmpBYTE Red;
+    ebmpBYTE Alpha;
+} RGBApixel; 
+
+class BMFH{
+public:
+ ebmpWORD  bfType;
+ ebmpDWORD bfSize;
+ ebmpWORD  bfReserved1;
+ ebmpWORD  bfReserved2;
+ ebmpDWORD bfOffBits; 
+
+ BMFH();
+};
+
+class BMIH{
+public:
+ ebmpDWORD biSize;
+ ebmpDWORD biWidth;
+ ebmpDWORD biHeight;
+ ebmpWORD  biPlanes;
+ ebmpWORD  biBitCount;
+ ebmpDWORD biCompression;
+ ebmpDWORD biSizeImage;
+ ebmpDWORD biXPelsPerMeter;
+ ebmpDWORD biYPelsPerMeter;
+ ebmpDWORD biClrUsed;
+ ebmpDWORD biClrImportant;
+
+ BMIH();
+};
+bool ReadBMPFromFile( const char* FileName , RGBApixel *Colors, NokiaLCD *lcd);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/picojpeg/jpegutil.c	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,107 @@
+#include "jpegutil.h"
+
+FILE *jpegfile;
+int jpeg_filesize = 0;
+int jpeg_filepos = 0;
+
+unsigned char pjpeg_need_bytes_callback(unsigned char* pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data)
+{
+   unsigned int n = min((unsigned int)(jpeg_filesize - jpeg_filepos), (unsigned int)buf_size);
+   if (n && (fread(pBuf, 1, n, jpegfile) != n))
+      return PJPG_STREAM_READ_ERROR;
+   *pBytes_actually_read = (unsigned char)(n);
+   jpeg_filepos += n;
+   return 0;
+}
+
+void ReadJPEGFromFile(const char *filename, NokiaLCD *lcd)
+{
+    pjpeg_image_info_t imageInfo;
+    jpegfile = fopen(filename,"rb");
+    fseek(jpegfile, 0, SEEK_END);
+    jpeg_filesize = ftell(jpegfile);
+    jpeg_filepos = 0;
+    fseek(jpegfile, 0, SEEK_SET);
+    int status = pjpeg_decode_init(&imageInfo, pjpeg_need_bytes_callback, NULL);
+   //const unsigned int row_pitch = imageInfo.m_width * imageInfo.m_comps;
+   int mcu_x = 0;
+   int mcu_y = 0;
+
+   for ( ; ; )
+   {
+      status = pjpeg_decode_mcu();
+
+      if (status)
+      {
+         if (status != PJPG_NO_MORE_BLOCKS)
+         {
+            //pc.printf("pjpeg_decode_mcu() failed with status %u\n", status);
+            fclose(jpegfile);
+            return;
+         }
+
+         break;
+      }
+
+      if (mcu_y >= imageInfo.m_MCUSPerCol)
+      {
+         fclose(jpegfile);
+         return;
+      }
+            
+      // Copy MCU's pixel blocks into the destination bitmap.
+
+      for (int y = 0; y < imageInfo.m_MCUHeight; y += 8)
+      {
+         const int by_limit = min(8, imageInfo.m_height - (mcu_y * imageInfo.m_MCUHeight + y));
+         for (int x = 0; x < imageInfo.m_MCUWidth; x += 8)
+         {
+
+            unsigned int src_ofs = (x * 8U) + (y * 16U);
+            const unsigned char *pSrcR = imageInfo.m_pMCUBufR + src_ofs;
+            const unsigned char *pSrcG = imageInfo.m_pMCUBufG + src_ofs;
+            const unsigned char *pSrcB = imageInfo.m_pMCUBufB + src_ofs;
+
+            const int bx_limit = min(8, imageInfo.m_width - (mcu_x * imageInfo.m_MCUWidth + x));
+                        
+            if (imageInfo.m_scanType == PJPG_GRAYSCALE)
+            {
+               for (int by = 0; by < by_limit; by++)
+               {
+                  for (int bx = 0; bx < bx_limit; bx++)
+                  {
+                      unsigned int color = ((*pSrcR++) << 16);   
+                      (*lcd).pixel(mcu_x*imageInfo.m_MCUWidth+x+bx,mcu_y*imageInfo.m_MCUHeight+y+by,color);
+                  }
+                  pSrcR += (8 - bx_limit);
+               }
+            }
+            else
+            {
+               for (int by = 0; by < by_limit; by++)
+               {
+                  for (int bx = 0; bx < bx_limit; bx++)
+                  {
+                     unsigned int color = ((*pSrcR++) << 16) | ((*pSrcG++) << 8) | (*pSrcB++);
+                     (*lcd).pixel((130-imageInfo.m_width)/2+mcu_x*imageInfo.m_MCUWidth+x+bx,(130-imageInfo.m_height)/2+mcu_y*imageInfo.m_MCUHeight+y+by,color);
+                  }
+
+                  pSrcR += (8 - bx_limit);
+                  pSrcG += (8 - bx_limit);
+                  pSrcB += (8 - bx_limit);
+
+               }
+            }
+         }
+      }
+
+      mcu_x++;
+      if (mcu_x == imageInfo.m_MCUSPerRow)
+      {
+         mcu_x = 0;
+         mcu_y++;
+      }
+   }
+      
+   fclose(jpegfile);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/picojpeg/jpegutil.h	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,6 @@
+#include "picojpeg.h"
+#include "NokiaLCD.h"
+#include <vector>
+
+unsigned char pjpeg_need_bytes_callback(unsigned char* pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data);
+void ReadJPEGFromFile(const char *filename, NokiaLCD *lcd);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/picojpeg/picojpeg.c	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,1736 @@
+//------------------------------------------------------------------------------
+// picojpeg v1.0 - Public domain, Rich Geldreich <richgel99@gmail.com>
+// Last modified Nov. 27, 2010
+//------------------------------------------------------------------------------
+#include "picojpeg.h"
+//------------------------------------------------------------------------------
+typedef unsigned char   uint8;
+typedef unsigned short  uint16;
+typedef signed char     int8;
+typedef signed short    int16;
+//------------------------------------------------------------------------------
+// Change as needed - the PJPG_MAX_WIDTH/PJPG_MAX_HEIGHT checks are only present
+// to quickly detect bogus files.
+#define PJPG_MAX_WIDTH 16384
+#define PJPG_MAX_HEIGHT 16384
+
+#define PJPG_MAXCOMPSINSCAN 3
+//------------------------------------------------------------------------------
+typedef enum
+{
+   M_SOF0  = 0xC0,
+   M_SOF1  = 0xC1,
+   M_SOF2  = 0xC2,
+   M_SOF3  = 0xC3,
+
+   M_SOF5  = 0xC5,
+   M_SOF6  = 0xC6,
+   M_SOF7  = 0xC7,
+
+   M_JPG   = 0xC8,
+   M_SOF9  = 0xC9,
+   M_SOF10 = 0xCA,
+   M_SOF11 = 0xCB,
+
+   M_SOF13 = 0xCD,
+   M_SOF14 = 0xCE,
+   M_SOF15 = 0xCF,
+
+   M_DHT   = 0xC4,
+
+   M_DAC   = 0xCC,
+
+   M_RST0  = 0xD0,
+   M_RST1  = 0xD1,
+   M_RST2  = 0xD2,
+   M_RST3  = 0xD3,
+   M_RST4  = 0xD4,
+   M_RST5  = 0xD5,
+   M_RST6  = 0xD6,
+   M_RST7  = 0xD7,
+
+   M_SOI   = 0xD8,
+   M_EOI   = 0xD9,
+   M_SOS   = 0xDA,
+   M_DQT   = 0xDB,
+   M_DNL   = 0xDC,
+   M_DRI   = 0xDD,
+   M_DHP   = 0xDE,
+   M_EXP   = 0xDF,
+
+   M_APP0  = 0xE0,
+   M_APP15 = 0xEF,
+
+   M_JPG0  = 0xF0,
+   M_JPG13 = 0xFD,
+   M_COM   = 0xFE,
+
+   M_TEM   = 0x01,
+
+   M_ERROR = 0x100
+} JPEG_MARKER;
+
+#define RST0 0xD0
+//------------------------------------------------------------------------------
+const int8 ZAG[] = 
+{
+   0,  1,  8, 16,  9,  2,  3, 10,
+   17, 24, 32, 25, 18, 11,  4,  5,
+   12, 19, 26, 33, 40, 48, 41, 34,
+   27, 20, 13,  6,  7, 14, 21, 28,
+   35, 42, 49, 56, 57, 50, 43, 36,
+   29, 22, 15, 23, 30, 37, 44, 51,
+   58, 59, 52, 45, 38, 31, 39, 46,
+   53, 60, 61, 54, 47, 55, 62, 63,
+};
+//------------------------------------------------------------------------------
+// 128 bytes
+static int16 gCoeffBuf[8*8];
+
+// 8*8*4 bytes * 3 = 768
+static uint8 gMCUBufR[256];
+static uint8 gMCUBufG[256];
+static uint8 gMCUBufB[256];
+
+// 256 bytes
+static int16 gQuant0[8*8];
+static int16 gQuant1[8*8];
+
+// 6 bytes
+static int16 gLastDC[3];
+
+typedef struct HuffTableT
+{
+   uint16 mMinCode[16];
+   uint16 mMaxCode[16];
+   uint8 mValPtr[16];
+} HuffTable;
+
+// DC - 192
+static HuffTable gHuffTab0;
+
+static uint8 gHuffVal0[16];
+
+static HuffTable gHuffTab1;
+static uint8 gHuffVal1[16];
+
+// AC - 672
+static HuffTable gHuffTab2;
+static uint8 gHuffVal2[256];
+
+static HuffTable gHuffTab3;
+static uint8 gHuffVal3[256];
+
+static uint8 gValidHuffTables;
+static uint8 gValidQuantTables;
+
+static uint8 gTemFlag;
+#define MAX_IN_BUF_SIZE 256
+static uint8 gInBuf[MAX_IN_BUF_SIZE];
+static uint8 gInBufOfs;
+static uint8 gInBufLeft;
+
+static uint16 gBitBuf;
+static uint8 gBitsLeft;
+//------------------------------------------------------------------------------
+static uint16 gImageXSize;
+static uint16 gImageYSize;
+static uint8 gCompsInFrame;
+static uint8 gCompIdent[3];
+static uint8 gCompHSamp[3];
+static uint8 gCompVSamp[3];
+static uint8 gCompQuant[3];
+
+static uint16 gRestartInterval;
+static uint16 gNextRestartNum;
+static uint16 gRestartsLeft;
+
+static uint8 gCompsInScan;
+static uint8 gCompList[3];
+static uint8 gCompDCTab[3]; // 0,1
+static uint8 gCompACTab[3]; // 0,1
+
+static pjpeg_scan_type_t gScanType;
+
+static uint8 gMaxBlocksPerMCU;
+static uint8 gMaxMCUXSize;
+static uint8 gMaxMCUYSize;
+static uint16 gMaxMCUSPerRow;
+static uint16 gMaxMCUSPerCol;
+static uint16 gNumMCUSRemaining;
+static uint8 gMCUOrg[6];
+
+static pjpeg_need_bytes_callback_t g_pNeedBytesCallback;
+static void *g_pCallback_data;
+//------------------------------------------------------------------------------
+static uint8 fillInBuf(void)
+{
+   unsigned char status;
+
+   // Reserve a few bytes at the beginning of the buffer for putting back ("stuffing") chars.
+   gInBufOfs = 4;
+   gInBufLeft = 0;
+
+   status = (*g_pNeedBytesCallback)(gInBuf + gInBufOfs, MAX_IN_BUF_SIZE - gInBufOfs, &gInBufLeft, g_pCallback_data);
+   if (status)
+      return status;
+      
+   return 0;
+}   
+//------------------------------------------------------------------------------
+static uint8 getChar(void)
+{
+   if (!gInBufLeft)
+   {
+      fillInBuf();
+      if (!gInBufLeft)
+      {
+         gTemFlag = ~gTemFlag;
+         return gTemFlag ? 0xFF : 0xD9;
+      } 
+   }
+   
+   gInBufLeft--;
+   return gInBuf[gInBufOfs++];
+}
+//------------------------------------------------------------------------------
+static void stuffChar(uint8 i)
+{
+   gInBufOfs--;
+   gInBuf[gInBufOfs] = i;
+   gInBufLeft++;
+}
+//------------------------------------------------------------------------------
+static uint8 getOctet(uint8 FFCheck)
+{
+   uint8 c = getChar();
+      
+   if ((FFCheck) && (c == 0xFF))
+   {
+      uint8 n = getChar();
+
+      if (n)
+      {
+         stuffChar(n);
+         stuffChar(0xFF);
+      }
+   }
+
+   return c;
+}
+//------------------------------------------------------------------------------
+static uint16 getBits(uint8 numBits, uint8 FFCheck)
+{
+   uint8 origBits = numBits;
+   uint16 ret = gBitBuf;
+   
+   if (numBits > 8)
+   {
+      numBits -= 8;
+      
+      gBitBuf <<= gBitsLeft;
+      
+      gBitBuf |= getOctet(FFCheck);
+      
+      gBitBuf <<= (8 - gBitsLeft);
+      
+      ret = (ret & 0xFF00) | (gBitBuf >> 8);
+   }
+      
+   if (gBitsLeft < numBits)
+   {
+      gBitBuf <<= gBitsLeft;
+      
+      gBitBuf |= getOctet(FFCheck);
+      
+      gBitBuf <<= (numBits - gBitsLeft);
+                        
+      gBitsLeft = 8 - (numBits - gBitsLeft);
+   }
+   else
+   {
+      gBitsLeft = (uint8)(gBitsLeft - numBits);
+      gBitBuf <<= numBits;
+   }
+   
+   return ret >> (16 - origBits);
+}
+//------------------------------------------------------------------------------
+static uint16 getBits1(uint8 numBits)
+{
+   return getBits(numBits, 0);
+}
+//------------------------------------------------------------------------------
+static uint16 getBits2(uint8 numBits)
+{
+   return getBits(numBits, 1);
+}
+//------------------------------------------------------------------------------
+static uint8 getBit(void)
+{
+   uint8 ret = 0;
+   if (gBitBuf & 0x8000) 
+      ret = 1;
+   
+   if (!gBitsLeft)
+   {
+      gBitBuf |= getOctet(1);
+
+      gBitsLeft += 8;
+   }
+   
+   gBitsLeft--;
+   gBitBuf <<= 1;
+   
+   return ret;
+}
+//------------------------------------------------------------------------------
+static uint16 getExtendTest(uint8 i)
+{
+   switch (i)
+   {
+      case 0: return 0;
+      case 1: return 0x0001;
+      case 2: return 0x0002;
+      case 3: return 0x0004;
+      case 4: return 0x0008;
+      case 5: return 0x0010; 
+      case 6: return 0x0020;
+      case 7: return 0x0040;
+      case 8:  return 0x0080;
+      case 9:  return 0x0100;
+      case 10: return 0x0200;
+      case 11: return 0x0400;
+      case 12: return 0x0800;
+      case 13: return 0x1000;
+      case 14: return 0x2000; 
+      case 15: return 0x4000;
+      default: return 0;
+   }      
+}
+//------------------------------------------------------------------------------
+static int16 getExtendOffset(uint8 i)
+{ 
+   switch (i)
+   {
+      case 0: return 0;
+      case 1: return ((-1)<<1) + 1; 
+      case 2: return ((-1)<<2) + 1; 
+      case 3: return ((-1)<<3) + 1; 
+      case 4: return ((-1)<<4) + 1; 
+      case 5: return ((-1)<<5) + 1; 
+      case 6: return ((-1)<<6) + 1; 
+      case 7: return ((-1)<<7) + 1; 
+      case 8: return ((-1)<<8) + 1; 
+      case 9: return ((-1)<<9) + 1;
+      case 10: return ((-1)<<10) + 1; 
+      case 11: return ((-1)<<11) + 1; 
+      case 12: return ((-1)<<12) + 1; 
+      case 13: return ((-1)<<13) + 1; 
+      case 14: return ((-1)<<14) + 1; 
+      case 15: return ((-1)<<15) + 1;
+      default: return 0;
+   }
+};
+//------------------------------------------------------------------------------
+static int16 huffExtend(uint16 x, uint8 s)
+{
+   return ((x < getExtendTest(s)) ? ((int16)x + getExtendOffset(s)) : (int16)x);
+}
+//------------------------------------------------------------------------------
+static uint8 huffDecode(const HuffTable* pHuffTable, const uint8* pHuffVal)
+{
+   uint8 i = 0;
+   uint8 j;
+   uint16 code = getBit();
+
+   for ( ; ; )
+   {
+      uint16 maxCode;
+
+      if (i == 16)
+         return 0;
+
+      maxCode = pHuffTable->mMaxCode[i];
+      if ((code <= maxCode) && (maxCode != 0xFFFF))
+         break;
+
+      i++;
+      code <<= 1;
+      code |= getBit();
+   }
+
+   j = pHuffTable->mValPtr[i];
+   j = (uint8)(j + (code - pHuffTable->mMinCode[i]));
+
+   return pHuffVal[j];
+}
+//------------------------------------------------------------------------------
+static void huffCreate(const uint8* pBits, HuffTable* pHuffTable)
+{
+   uint8 i = 0;
+   uint8 j = 0;
+
+   uint16 code = 0;
+      
+   for ( ; ; )
+   {
+      uint8 num = pBits[i];
+      
+      if (!num)
+      {
+         pHuffTable->mMinCode[i] = 0x0000;
+         pHuffTable->mMaxCode[i] = 0xFFFF;
+         pHuffTable->mValPtr[i] = 0;
+      }
+      else
+      {
+         pHuffTable->mMinCode[i] = code;
+         pHuffTable->mMaxCode[i] = code + num - 1;
+         pHuffTable->mValPtr[i] = j;
+         
+         j = (uint8)(j + num);
+         
+         code = (uint16)(code + num);
+      }
+      
+      code <<= 1;
+      
+      i++;
+      if (i > 15)
+         break;
+   }
+}
+//------------------------------------------------------------------------------
+static HuffTable* getHuffTable(uint8 index)
+{
+   // 0-1 = DC
+   // 2-3 = AC
+   switch (index)
+   {
+      case 0: return &gHuffTab0;
+      case 1: return &gHuffTab1;
+      case 2: return &gHuffTab2;
+      case 3: return &gHuffTab3;
+      default: return 0;
+   }
+}
+//------------------------------------------------------------------------------
+static uint8* getHuffVal(uint8 index)
+{
+   // 0-1 = DC
+   // 2-3 = AC
+   switch (index)
+   {
+      case 0: return gHuffVal0;
+      case 1: return gHuffVal1;
+      case 2: return gHuffVal2;
+      case 3: return gHuffVal3;
+      default: return 0;
+   }
+}
+//------------------------------------------------------------------------------
+static uint16 getMaxHuffCodes(uint8 index)
+{
+   return (index < 2) ? 12 : 255;
+}
+//------------------------------------------------------------------------------
+static uint8 readDHTMarker(void)
+{
+   uint8 bits[16];
+   uint16 left = getBits1(16);
+
+   if (left < 2)
+      return PJPG_BAD_DHT_MARKER;
+
+   left -= 2;
+
+   while (left)
+   {
+      uint8 i, tableIndex, index;
+      uint8* pHuffVal;
+      HuffTable* pHuffTable;
+      uint16 count, totalRead;
+            
+      index = (uint8)getBits1(8);
+      
+      if ( ((index & 0xF) > 1) || ((index & 0xF0) > 0x10) )
+         return PJPG_BAD_DHT_INDEX;
+      
+      tableIndex = ((index >> 3) & 2) + (index & 1);
+      
+      pHuffTable = getHuffTable(tableIndex);
+      pHuffVal = getHuffVal(tableIndex);
+      
+      gValidHuffTables |= (1 << tableIndex);
+            
+      count = 0;
+      for (i = 0; i <= 15; i++)
+      {
+         uint8 n = (uint8)getBits1(8);
+         bits[i] = n;
+         count = (uint16)(count + n);
+      }
+      
+      if (count > getMaxHuffCodes(tableIndex))
+         return PJPG_BAD_DHT_COUNTS;
+
+      for (i = 0; i < count; i++)
+         pHuffVal[i] = (uint8)getBits1(8);
+
+      totalRead = 1 + 16 + count;
+
+      if (left < totalRead)
+         return PJPG_BAD_DHT_MARKER;
+
+      left = (uint16)(left - totalRead);
+
+      huffCreate(bits, pHuffTable);
+   }
+      
+   return 0;
+}
+//------------------------------------------------------------------------------
+static void createWinogradQuant(int16* pQuant);
+
+static uint8 readDQTMarker(void)
+{
+   uint16 left = getBits1(16);
+
+   if (left < 2)
+      return PJPG_BAD_DQT_MARKER;
+
+   left -= 2;
+
+   while (left)
+   {
+      uint8 i;
+      uint8 n = (uint8)getBits1(8);
+      uint8 prec = n >> 4;
+      uint16 totalRead;
+
+      n &= 0x0F;
+
+      if (n > 1)
+         return PJPG_BAD_DQT_TABLE;
+
+      gValidQuantTables |= (n ? 2 : 1);         
+
+      // read quantization entries, in zag order
+      for (i = 0; i < 64; i++)
+      {
+         uint16 temp = getBits1(8);
+
+         if (prec)
+            temp = (temp << 8) + getBits1(8);
+
+         if (n)
+            gQuant1[i] = (int16)temp;            
+         else
+            gQuant0[i] = (int16)temp;            
+      }
+      
+      createWinogradQuant(n ? gQuant1 : gQuant0);
+
+      totalRead = 64 + 1;
+
+      if (prec)
+         totalRead += 64;
+
+      if (left < totalRead)
+         return PJPG_BAD_DQT_LENGTH;
+
+      left = (uint16)(left - totalRead);
+   }
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+static uint8 readSOFMarker(void)
+{
+   uint8 i;
+   uint16 left = getBits1(16);
+
+   if (getBits1(8) != 8)   
+      return PJPG_BAD_PRECISION;
+
+   gImageYSize = getBits1(16);
+
+   if ((!gImageYSize) || (gImageYSize > PJPG_MAX_HEIGHT))
+      return PJPG_BAD_HEIGHT;
+
+   gImageXSize = getBits1(16);
+
+   if ((!gImageXSize) || (gImageXSize > PJPG_MAX_WIDTH))
+      return PJPG_BAD_WIDTH;
+
+   gCompsInFrame = (uint8)getBits1(8);
+
+   if (gCompsInFrame > 3)
+      return PJPG_TOO_MANY_COMPONENTS;
+
+   if (left != (gCompsInFrame + gCompsInFrame + gCompsInFrame + 8))
+      return PJPG_BAD_SOF_LENGTH;
+   
+   for (i = 0; i < gCompsInFrame; i++)
+   {
+      gCompIdent[i] = (uint8)getBits1(8);
+      gCompHSamp[i] = (uint8)getBits1(4);
+      gCompVSamp[i] = (uint8)getBits1(4);
+      gCompQuant[i] = (uint8)getBits1(8);
+      
+      if (gCompQuant[i] > 1)
+         return PJPG_UNSUPPORTED_QUANT_TABLE;
+   }
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+// Used to skip unrecognized markers.
+static uint8 skipVariableMarker(void)
+{
+   uint16 left = getBits1(16);
+
+   if (left < 2)
+      return PJPG_BAD_VARIABLE_MARKER;
+
+   left -= 2;
+
+   while (left)
+   {
+      getBits1(8);
+      left--;
+   }
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+// Read a define restart interval (DRI) marker.
+static uint8 readDRIMarker(void)
+{
+   if (getBits1(16) != 4)
+      return PJPG_BAD_DRI_LENGTH;
+
+   gRestartInterval = getBits1(16);
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+// Read a start of scan (SOS) marker.
+static uint8 readSOSMarker(void)
+{
+   uint8 i;
+   uint16 left = getBits1(16);
+   uint8 spectral_start, spectral_end, successive_high, successive_low;
+
+   gCompsInScan = (uint8)getBits1(8);
+
+   left -= 3;
+
+   if ( (left != (gCompsInScan + gCompsInScan + 3)) || (gCompsInScan < 1) || (gCompsInScan > PJPG_MAXCOMPSINSCAN) )
+      return PJPG_BAD_SOS_LENGTH;
+   
+   for (i = 0; i < gCompsInScan; i++)
+   {
+      uint8 cc = (uint8)getBits1(8);
+      uint8 c = (uint8)getBits1(8);
+      uint8 ci;
+      
+      left -= 2;
+     
+      for (ci = 0; ci < gCompsInFrame; ci++)
+         if (cc == gCompIdent[ci])
+            break;
+
+      if (ci >= gCompsInFrame)
+         return PJPG_BAD_SOS_COMP_ID;
+
+      gCompList[i]    = ci;
+      gCompDCTab[ci] = (c >> 4) & 15;
+      gCompACTab[ci] = (c & 15);
+   }
+
+   spectral_start  = (uint8)getBits1(8);
+   spectral_end    = (uint8)getBits1(8);
+   successive_high = (uint8)getBits1(4);
+   successive_low  = (uint8)getBits1(4);
+
+   left -= 3;
+
+   while (left)                  
+   {
+      getBits1(8);
+      left--;
+   }
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+static uint8 nextMarker(void)
+{
+   uint8 c;
+   uint8 bytes = 0;
+
+   do
+   {
+      do
+      {
+         bytes++;
+
+         c = (uint8)getBits1(8);
+
+      } while (c != 0xFF);
+
+      do
+      {
+         c = (uint8)getBits1(8);
+
+      } while (c == 0xFF);
+
+   } while (c == 0);
+
+   // If bytes > 0 here, there where extra bytes before the marker (not good).
+
+   return c;
+}
+//------------------------------------------------------------------------------
+// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is
+// encountered.
+static uint8 processMarkers(uint8* pMarker)
+{
+   for ( ; ; )
+   {
+      uint8 c = nextMarker();
+
+      switch (c)
+      {
+         case M_SOF0:
+         case M_SOF1:
+         case M_SOF2:
+         case M_SOF3:
+         case M_SOF5:
+         case M_SOF6:
+         case M_SOF7:
+         //      case M_JPG:
+         case M_SOF9:
+         case M_SOF10:
+         case M_SOF11:
+         case M_SOF13:
+         case M_SOF14:
+         case M_SOF15:
+         case M_SOI:
+         case M_EOI:
+         case M_SOS:
+         {
+            *pMarker = c;
+            return 0;
+         }
+         case M_DHT:
+         {
+            readDHTMarker();
+            break;
+         }
+         // Sorry, no arithmitic support at this time. Dumb patents!
+         case M_DAC:
+         {
+            return PJPG_NO_ARITHMITIC_SUPPORT;
+         }
+         case M_DQT:
+         {
+            readDQTMarker();
+            break;
+         }
+         case M_DRI:
+         {
+            readDRIMarker();
+            break;
+         }
+         //case M_APP0:  /* no need to read the JFIF marker */
+
+         case M_JPG:
+         case M_RST0:    /* no parameters */
+         case M_RST1:
+         case M_RST2:
+         case M_RST3:
+         case M_RST4:
+         case M_RST5:
+         case M_RST6:
+         case M_RST7:
+         case M_TEM:
+         {
+            return PJPG_UNEXPECTED_MARKER;
+         }
+         default:    /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
+         {
+            skipVariableMarker();
+            break;
+         }
+      }
+   }
+//   return 0;
+}
+//------------------------------------------------------------------------------
+// Finds the start of image (SOI) marker.
+static uint8 locateSOIMarker(void)
+{
+   uint16 bytesleft;
+   
+   uint8 lastchar = (uint8)getBits1(8);
+
+   uint8 thischar = (uint8)getBits1(8);
+
+   /* ok if it's a normal JPEG file without a special header */
+
+   if ((lastchar == 0xFF) && (thischar == M_SOI))
+      return 0;
+
+   bytesleft = 4096; //512;
+
+   for ( ; ; )
+   {
+      if (--bytesleft == 0)
+         return PJPG_NOT_JPEG;
+
+      lastchar = thischar;
+
+      thischar = (uint8)getBits1(8);
+
+      if (lastchar == 0xFF) 
+      {
+         if (thischar == M_SOI)
+            break;
+         else if (thischar == M_EOI)    //getBits1 will keep returning M_EOI if we read past the end
+            return PJPG_NOT_JPEG;
+      }
+   }
+
+   /* Check the next character after marker: if it's not 0xFF, it can't
+   be the start of the next marker, so the file is bad */
+
+   thischar = (uint8)((gBitBuf >> 8) & 0xFF);
+
+   if (thischar != 0xFF)
+      return PJPG_NOT_JPEG;
+      
+   return 0;
+}
+//------------------------------------------------------------------------------
+// Find a start of frame (SOF) marker.
+static uint8 locateSOFMarker(void)
+{
+   uint8 c;
+
+   uint8 status = locateSOIMarker();
+   if (status)
+      return status;
+   
+   status = processMarkers(&c);
+   if (status)
+      return status;
+
+   switch (c)
+   {
+      case M_SOF2:
+      {
+         return PJPG_UNSUPPORTED_MODE;
+      }
+      case M_SOF0:  /* baseline DCT */
+      {
+         status = readSOFMarker();
+         if (status)
+            return status;
+            
+         break;
+      }
+      case M_SOF9:  
+      {
+         return PJPG_NO_ARITHMITIC_SUPPORT;
+      }
+      case M_SOF1:  /* extended sequential DCT */
+      default:
+      {
+         return PJPG_UNSUPPORTED_MARKER;
+      }
+   }
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+// Find a start of scan (SOS) marker.
+static uint8 locateSOSMarker(uint8* pFoundEOI)
+{
+   uint8 c;
+   uint8 status;
+
+   *pFoundEOI = 0;
+      
+   status = processMarkers(&c);
+   if (status)
+      return status;
+
+   if (c == M_EOI)
+   {
+      *pFoundEOI = 1;
+      return 0;
+   }
+   else if (c != M_SOS)
+      return PJPG_UNEXPECTED_MARKER;
+
+   return readSOSMarker();
+}
+//------------------------------------------------------------------------------
+static uint8 init(void)
+{
+   gImageXSize = 0;
+   gImageYSize = 0;
+   gCompsInFrame = 0;
+   gRestartInterval = 0;
+   gCompsInScan = 0;
+   gValidHuffTables = 0;
+   gValidQuantTables = 0;
+   gTemFlag = 0;
+   gInBufOfs = 0;
+   gInBufLeft = 0;
+   gBitBuf = 0;
+   gBitsLeft = 8;
+
+   getBits1(8);
+   getBits1(8);
+
+   return 0;
+}
+//------------------------------------------------------------------------------
+// This method throws back into the stream any bytes that where read
+// into the bit buffer during initial marker scanning.
+static void fixInBuffer(void)
+{
+   /* In case any 0xFF's where pulled into the buffer during marker scanning */
+
+   if (gBitsLeft > 0)  
+      stuffChar((uint8)gBitBuf);
+   
+   stuffChar((uint8)(gBitBuf >> 8));
+   
+   gBitsLeft = 8;
+   getBits2(8);
+   getBits2(8);
+}
+//------------------------------------------------------------------------------
+// Restart interval processing.
+static uint8 processRestart(void)
+{
+   // Let's scan a little bit to find the marker, but not _too_ far.
+   // 1536 is a "fudge factor" that determines how much to scan.
+   uint16 i;
+   uint8 c = 0;
+
+   for (i = 1536; i > 0; i--)
+      if (getChar() == 0xFF)
+         break;
+
+   if (i == 0)
+      return PJPG_BAD_RESTART_MARKER;
+   
+   for ( ; i > 0; i--)
+      if ((c = getChar()) != 0xFF)
+         break;
+
+   if (i == 0)
+      return PJPG_BAD_RESTART_MARKER;
+
+   // Is it the expected marker? If not, something bad happened.
+   if (c != (gNextRestartNum + M_RST0))
+      return PJPG_BAD_RESTART_MARKER;
+
+   // Reset each component's DC prediction values.
+   gLastDC[0] = 0;
+   gLastDC[1] = 0;
+   gLastDC[2] = 0;
+
+   gRestartsLeft = gRestartInterval;
+
+   gNextRestartNum = (gNextRestartNum + 1) & 7;
+
+   // Get the bit buffer going again...
+
+   gBitsLeft = 8;
+   getBits2(8);
+   getBits2(8);
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+static uint8 findEOI(void)
+{
+   uint8 c;
+   uint8 status;
+
+   // Prime the bit buffer
+   gBitsLeft = 8;
+   getBits1(8);
+   getBits1(8);
+
+   // The next marker _should_ be EOI
+   status = processMarkers(&c);
+   if (status)
+      return status;
+   
+   //gTotalBytesRead -= in_buf_left;
+   if (c != M_EOI)
+      return PJPG_UNEXPECTED_MARKER;
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+static uint8 checkHuffTables(void)
+{
+   uint8 i;
+
+   for (i = 0; i < gCompsInScan; i++)
+   {
+      uint8 compDCTab = gCompDCTab[gCompList[i]];
+      uint8 compACTab = gCompACTab[gCompList[i]] + 2;
+      
+      if ( ((gValidHuffTables & (1 << compDCTab)) == 0) ||
+           ((gValidHuffTables & (1 << compACTab)) == 0) )
+         return PJPG_UNDEFINED_HUFF_TABLE;           
+   }
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+static uint8 checkQuantTables(void)
+{
+   uint8 i;
+
+   for (i = 0; i < gCompsInScan; i++)
+   {
+      uint8 compQuantMask = gCompQuant[gCompList[i]] ? 2 : 1;
+      
+      if ((gValidQuantTables & compQuantMask) == 0)
+         return PJPG_UNDEFINED_QUANT_TABLE;
+   }         
+
+   return 0;         
+}
+//------------------------------------------------------------------------------
+static uint8 initScan(void)
+{
+   uint8 foundEOI;
+   uint8 status = locateSOSMarker(&foundEOI);
+   if (status)
+      return status;
+   if (foundEOI)
+      return PJPG_UNEXPECTED_MARKER;
+   
+   status = checkHuffTables();
+   if (status)
+      return status;
+
+   status = checkQuantTables();
+   if (status)
+      return status;
+
+   gLastDC[0] = 0;
+   gLastDC[1] = 0;
+   gLastDC[2] = 0;
+
+   if (gRestartInterval)
+   {
+      gRestartsLeft = gRestartInterval;
+      gNextRestartNum = 0;
+   }
+
+   fixInBuffer();
+
+   return 0;
+}
+//------------------------------------------------------------------------------
+static uint8 initFrame(void)
+{
+   if (gCompsInFrame == 1)
+   {
+      if ((gCompHSamp[0] != 1) || (gCompVSamp[0] != 1))
+         return PJPG_UNSUPPORTED_SAMP_FACTORS;
+
+      gScanType = PJPG_GRAYSCALE;
+
+      gMaxBlocksPerMCU = 1;
+      gMCUOrg[0] = 0;
+
+      gMaxMCUXSize     = 8;
+      gMaxMCUYSize     = 8;
+   }
+   else if (gCompsInFrame == 3)
+   {
+      if ( ((gCompHSamp[1] != 1) || (gCompVSamp[1] != 1)) ||
+         ((gCompHSamp[2] != 1) || (gCompVSamp[2] != 1)) )
+         return PJPG_UNSUPPORTED_SAMP_FACTORS;
+
+      if ((gCompHSamp[0] == 1) && (gCompVSamp[0] == 1))
+      {
+         gScanType = PJPG_YH1V1;
+
+         gMaxBlocksPerMCU = 3;
+         gMCUOrg[0] = 0;
+         gMCUOrg[1] = 1;
+         gMCUOrg[2] = 2;
+                  
+         gMaxMCUXSize = 8;
+         gMaxMCUYSize = 8;
+      }
+      else if ((gCompHSamp[0] == 2) && (gCompVSamp[0] == 2))
+      {
+         gScanType = PJPG_YH2V2;
+
+         gMaxBlocksPerMCU = 6;
+         gMCUOrg[0] = 0;
+         gMCUOrg[1] = 0;
+         gMCUOrg[2] = 0;
+         gMCUOrg[3] = 0;
+         gMCUOrg[4] = 1;
+         gMCUOrg[5] = 2;
+
+         gMaxMCUXSize = 16;
+         gMaxMCUYSize = 16;
+      }
+      else
+         return PJPG_UNSUPPORTED_SAMP_FACTORS;
+   }
+   else
+      return PJPG_UNSUPPORTED_COLORSPACE;
+
+   gMaxMCUSPerRow = (gImageXSize + (gMaxMCUXSize - 1)) >> ((gMaxMCUXSize == 8) ? 3 : 4);
+   gMaxMCUSPerCol = (gImageYSize + (gMaxMCUYSize - 1)) >> ((gMaxMCUYSize == 8) ? 3 : 4);
+   
+   gNumMCUSRemaining = gMaxMCUSPerRow * gMaxMCUSPerCol;
+   
+   return 0;
+}
+/*----------------------------------------------------------------------------*/
+#define DCT_SCALE_BITS   7
+
+#define DCT_SCALE       (1U << DCT_SCALE_BITS)
+
+#define DESCALE(x)   (((x) + (1U << (DCT_SCALE_BITS - 1))) >> DCT_SCALE_BITS)
+
+#define WFIX(x) ((x) * DCT_SCALE + 0.5f)
+
+#define WINOGRAD_QUANT_SCALE_BITS 10
+
+const uint8 gWinogradQuant[] = 
+{
+   128,  178,  178,  167,  246,  167,  151,  232,
+   232,  151,  128,  209,  219,  209,  128,  101,
+   178,  197,  197,  178,  101,   69,  139,  167,
+   177,  167,  139,   69,   35,   96,  131,  151,
+   151,  131,   96,   35,   49,   91,  118,  128,
+   118,   91,   49,   46,   81,  101,  101,   81,
+   46,   42,   69,   79,   69,   42,   35,   54,
+   54,   35,   28,   37,   28,   19,   19,   10,
+};   
+
+static void createWinogradQuant(int16* pQuant)
+{
+   uint8 i;
+   
+   for (i = 0; i < 64; i++) 
+   {
+      long x = pQuant[i];
+      x *= gWinogradQuant[i];
+      pQuant[i] = (int16)((x + (1 << (WINOGRAD_QUANT_SCALE_BITS - DCT_SCALE_BITS - 1))) >> (WINOGRAD_QUANT_SCALE_BITS - DCT_SCALE_BITS));
+   }
+}
+
+// 1/cos(4*pi/16)
+// 362, 256+106
+#define b1 362
+
+// 1/cos(6*pi/16)
+// 669, 256+256+157
+#define b2 669
+
+// 1/cos(4*pi/16)
+// 362, 256+106
+#define b3 362
+
+// 1/cos(2*pi/16)
+// 277, 256+21
+#define b4 277
+
+// 1/(cos(2*pi/16) + cos(6*pi/16))
+// 196, 196
+#define b5 196
+
+static int16 imul_b1_b3(int16 w)
+{
+   long x = (w * 362L);
+   x += 128L;
+   return (int16)(x >> 8);
+}
+
+static int16 imul_b2(int16 w)
+{
+   long x = (w * 669L);
+   x += 128L;
+   return (int16)(x >> 8);
+}
+
+static int16 imul_b4(int16 w)
+{
+   long x = (w * 277L);
+   x += 128L;
+   return (int16)(x >> 8);
+}
+
+static int16 imul_b5(int16 w)
+{
+   long x = (w * 196L);
+   x += 128L;
+   return (int16)(x >> 8);
+}
+
+static uint8 clamp(int16 s)
+{
+   if ((uint16)s > 255U)
+   {
+      if (s < 0) 
+         return 0; 
+      else if (s > 255) 
+         return 255;
+   }
+      
+   return (uint8)s;
+}
+
+static void idctRows(void)
+{
+   uint8 i;
+   int16* pSrc = gCoeffBuf;
+         
+   for (i = 0; i < 8; i++)
+   {
+      int16 src4 = *(pSrc+5);
+      int16 src7 = *(pSrc+3);
+      int16 x4  = src4 - src7;
+      int16 x7  = src4 + src7;
+
+      int16 src5 = *(pSrc+1);
+      int16 src6 = *(pSrc+7);
+      int16 x5  = src5 + src6;
+      int16 x6  = src5 - src6;
+
+      int16 tmp1 = imul_b5(x4 - x6);
+      int16 stg26 = imul_b4(x6) - tmp1;
+
+      int16 x24 = tmp1 - imul_b2(x4);
+
+      int16 x15 = x5 - x7;
+      int16 x17 = x5 + x7;
+
+      int16 tmp2 = stg26 - x17;
+      int16 tmp3 = imul_b1_b3(x15) - tmp2;
+      int16 x44 = tmp3 + x24;
+
+      int16 src0 = *(pSrc+0);
+      int16 src1 = *(pSrc+4);
+      int16 x30 = src0 + src1;
+      int16 x31 = src0 - src1;
+
+      int16 src2 = *(pSrc+2);
+      int16 src3 = *(pSrc+6);
+      int16 x12 = src2 - src3;
+      int16 x13 = src2 + src3;
+
+      int16 x32 = imul_b1_b3(x12) - x13;
+
+      int16 x40 = x30 + x13;
+      int16 x43 = x30 - x13;
+      int16 x41 = x31 + x32;
+      int16 x42 = x31 - x32;
+
+      *(pSrc+0) = x40 + x17;
+      *(pSrc+1) = x41 + tmp2;
+      *(pSrc+2) = x42 + tmp3;
+      *(pSrc+3) = x43 - x44;
+      *(pSrc+4) = x43 + x44;
+      *(pSrc+5) = x42 - tmp3;
+      *(pSrc+6) = x41 - tmp2;
+      *(pSrc+7) = x40 - x17;
+                  
+      pSrc += 8;
+   }      
+}
+
+static void idctCols(void)
+{
+   uint8 i;
+      
+   int16* pSrc = gCoeffBuf;
+   
+   for (i = 0; i < 8; i++)
+   {
+      int16 src4 = *(pSrc+5*8);
+      int16 src7 = *(pSrc+3*8);
+      int16 x4  = src4 - src7;
+      int16 x7  = src4 + src7;
+
+      int16 src5 = *(pSrc+1*8);
+      int16 src6 = *(pSrc+7*8);
+      int16 x5  = src5 + src6;
+      int16 x6  = src5 - src6;
+
+      int16 tmp1 = imul_b5(x4 - x6);
+      int16 stg26 = imul_b4(x6) - tmp1;
+
+      int16 x24 = tmp1 - imul_b2(x4);
+
+      int16 x15 = x5 - x7;
+      int16 x17 = x5 + x7;
+
+      int16 tmp2 = stg26 - x17;
+      int16 tmp3 = imul_b1_b3(x15) - tmp2;
+      int16 x44 = tmp3 + x24;
+
+      int16 src0 = *(pSrc+0*8);
+      int16 src1 = *(pSrc+4*8);
+      int16 x30 = src0 + src1;
+      int16 x31 = src0 - src1;
+
+      int16 src2 = *(pSrc+2*8);
+      int16 src3 = *(pSrc+6*8);
+      int16 x12 = src2 - src3;
+      int16 x13 = src2 + src3;
+
+      int16 x32 = imul_b1_b3(x12) - x13;
+
+      int16 x40 = x30 + x13;
+      int16 x43 = x30 - x13;
+      int16 x41 = x31 + x32;
+      int16 x42 = x31 - x32;
+
+      *(pSrc+0*8) = clamp(DESCALE(x40 + x17)  + 128);
+      *(pSrc+1*8) = clamp(DESCALE(x41 + tmp2) + 128);
+      *(pSrc+2*8) = clamp(DESCALE(x42 + tmp3) + 128);
+      *(pSrc+3*8) = clamp(DESCALE(x43 - x44)  + 128);
+      *(pSrc+4*8) = clamp(DESCALE(x43 + x44)  + 128);
+      *(pSrc+5*8) = clamp(DESCALE(x42 - tmp3) + 128);
+      *(pSrc+6*8) = clamp(DESCALE(x41 - tmp2) + 128);
+      *(pSrc+7*8) = clamp(DESCALE(x40 - x17)  + 128);
+
+      pSrc++;      
+   }      
+}
+
+/*----------------------------------------------------------------------------*/
+static uint8 addAndClamp(uint8 a, int16 b)
+{
+   b = a + b;
+   
+   if ((uint16)b > 255U)
+   {
+      if (b < 0)
+         return 0;
+      else if (b > 255)
+         return 255;
+   }
+      
+   return (uint8)b;
+}
+/*----------------------------------------------------------------------------*/
+static uint8 subAndClamp(uint8 a, int16 b)
+{
+   b = a - b;
+
+   if ((uint16)b > 255U)
+   {
+      if (b < 0)
+         return 0;
+      else if (b > 255)
+         return 255;
+   }
+
+   return (uint8)b;
+}
+/*----------------------------------------------------------------------------*/
+// 103/256
+//R = Y + 1.402 (Cr-128)
+
+// 88/256, 183/256
+//G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
+
+// 198/256
+//B = Y + 1.772 (Cb-128)
+/*----------------------------------------------------------------------------*/
+static void upsampleCb(uint8 srcOfs, uint8 dstOfs)
+{
+   // Cb - affects G and B
+   uint8 x, y;
+   int16* pSrc = gCoeffBuf + srcOfs;
+   uint8* pDstG = gMCUBufG + dstOfs;
+   uint8* pDstB = gMCUBufB + dstOfs;
+   for (y = 0; y < 4; y++)
+   {
+      for (x = 0; x < 4; x++)
+      {
+         uint8 cb = (uint8)*pSrc++;
+         int16 cbG, cbB;
+
+         cbG = ((cb * 88U) >> 8U) - 44U;
+         pDstG[0] = subAndClamp(pDstG[0], cbG);
+         pDstG[1] = subAndClamp(pDstG[1], cbG);
+         pDstG[8] = subAndClamp(pDstG[8], cbG);
+         pDstG[9] = subAndClamp(pDstG[9], cbG);
+
+         cbB = (cb + ((cb * 198U) >> 8U)) - 227U;
+         pDstB[0] = addAndClamp(pDstB[0], cbB);
+         pDstB[1] = addAndClamp(pDstB[1], cbB);
+         pDstB[8] = addAndClamp(pDstB[8], cbB);
+         pDstB[9] = addAndClamp(pDstB[9], cbB);
+
+         pDstG += 2;
+         pDstB += 2;
+      }
+
+      pSrc = pSrc - 4 + 8;
+      pDstG = pDstG - 8 + 16;
+      pDstB = pDstB - 8 + 16;
+   }
+}   
+/*----------------------------------------------------------------------------*/
+// 103/256
+//R = Y + 1.402 (Cr-128)
+
+// 88/256, 183/256
+//G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
+
+// 198/256
+//B = Y + 1.772 (Cb-128)
+/*----------------------------------------------------------------------------*/
+static void upsampleCr(uint8 srcOfs, uint8 dstOfs)
+{
+   // Cr - affects R and G
+   uint8 x, y;
+   int16* pSrc = gCoeffBuf + srcOfs;
+   uint8* pDstR = gMCUBufR + dstOfs;
+   uint8* pDstG = gMCUBufG + dstOfs;
+   for (y = 0; y < 4; y++)
+   {
+      for (x = 0; x < 4; x++)
+      {
+         uint8 cr = (uint8)*pSrc++;
+         int16 crR, crG;
+
+         crR = (cr + ((cr * 103U) >> 8U)) - 179;
+         pDstR[0] = addAndClamp(pDstR[0], crR);
+         pDstR[1] = addAndClamp(pDstR[1], crR);
+         pDstR[8] = addAndClamp(pDstR[8], crR);
+         pDstR[9] = addAndClamp(pDstR[9], crR);
+         
+         crG = ((cr * 183U) >> 8U) - 91;
+         pDstG[0] = subAndClamp(pDstG[0], crG);
+         pDstG[1] = subAndClamp(pDstG[1], crG);
+         pDstG[8] = subAndClamp(pDstG[8], crG);
+         pDstG[9] = subAndClamp(pDstG[9], crG);
+         
+         pDstR += 2;
+         pDstG += 2;
+      }
+
+      pSrc = pSrc - 4 + 8;
+      pDstR = pDstR - 8 + 16;
+      pDstG = pDstG - 8 + 16;
+   }
+}   
+/*----------------------------------------------------------------------------*/
+static void copyY(uint8 dstOfs)
+{
+   uint8 i;
+   uint8* pRDst = gMCUBufR + dstOfs;
+   uint8* pGDst = gMCUBufG + dstOfs;
+   uint8* pBDst = gMCUBufB + dstOfs;
+   int16* pSrc = gCoeffBuf;
+   
+   for (i = 64; i > 0; i--)
+   {
+      uint8 c = (uint8)*pSrc++;
+      
+      *pRDst++ = c;
+      *pGDst++ = c;
+      *pBDst++ = c;
+   }
+}
+/*----------------------------------------------------------------------------*/
+static void convertCb(uint8 dstOfs)
+{
+   uint8 i;
+   uint8* pDstG = gMCUBufG + dstOfs;
+   uint8* pDstB = gMCUBufB + dstOfs;
+   int16* pSrc = gCoeffBuf;
+
+   for (i = 64; i > 0; i--)
+   {
+      uint8 cb = (uint8)*pSrc++;
+      int16 cbG, cbB;
+
+      cbG = ((cb * 88U) >> 8U) - 44U;
+      *pDstG++ = subAndClamp(pDstG[0], cbG);
+
+      cbB = (cb + ((cb * 198U) >> 8U)) - 227U;
+      *pDstB++ = addAndClamp(pDstB[0], cbB);
+   }
+}
+/*----------------------------------------------------------------------------*/
+static void convertCr(uint8 dstOfs)
+{
+   uint8 i;
+   uint8* pDstR = gMCUBufR + dstOfs;
+   uint8* pDstG = gMCUBufG + dstOfs;
+   int16* pSrc = gCoeffBuf;
+
+   for (i = 64; i > 0; i--)
+   {
+      uint8 cr = (uint8)*pSrc++;
+      int16 crR, crG;
+
+      crR = (cr + ((cr * 103U) >> 8U)) - 179;
+      *pDstR++ = addAndClamp(pDstR[0], crR);
+
+      crG = ((cr * 183U) >> 8U) - 91;
+      *pDstG++ = subAndClamp(pDstG[0], crG);
+   }
+}
+/*----------------------------------------------------------------------------*/
+static void transformBlock(uint8 mcuBlock)
+{
+   idctRows();
+   idctCols();
+   
+   switch (gScanType)
+   {
+      case PJPG_GRAYSCALE:
+      {
+         copyY(0);
+         break;
+      }
+      case PJPG_YH1V1:
+      {
+         switch (mcuBlock)
+         {
+            case 0:
+            {
+               copyY(0);
+               break;
+            }
+            case 1:
+            {
+               convertCb(0);
+               break;
+            }
+            case 2:
+            {
+               convertCr(0);
+               break;
+            }
+         }
+
+         break;
+      }
+      case PJPG_YH2V2:
+      {
+         switch (mcuBlock)
+         {
+            case 0:
+            {
+               copyY(0);
+               break;
+            }
+            case 1:
+            {
+               copyY(64);
+               break;
+            }
+            case 2:
+            {
+               copyY(128);
+               break;
+            }
+            case 3:
+            {
+               copyY(192);
+               break;
+            }
+            case 4:
+            {
+               upsampleCb(0, 0);
+               upsampleCb(4, 64);
+               upsampleCb(4*8, 128);
+               upsampleCb(4+4*8, 192);
+               break;
+            }
+            case 5:
+            {
+               upsampleCr(0, 0);
+               upsampleCr(4, 64);
+               upsampleCr(4*8, 128);
+               upsampleCr(4+4*8, 192);
+               break;
+            }
+         }
+      }         
+   }      
+}
+//------------------------------------------------------------------------------
+static uint8 decodeNextMCU(void)
+{
+   uint8 status;
+   uint8 mcuBlock;   
+
+   if (gRestartInterval) 
+   {
+      if (gRestartsLeft == 0)
+      {
+         status = processRestart();
+         if (status)
+            return status;
+      }
+      gRestartsLeft--;
+   }      
+   
+   for (mcuBlock = 0; mcuBlock < gMaxBlocksPerMCU; mcuBlock++)
+   {
+      uint8 componentID = gMCUOrg[mcuBlock];
+      uint8 compQuant = gCompQuant[componentID];    
+      uint8 compDCTab = gCompDCTab[componentID];
+      uint8 numExtraBits, compACTab, k;
+      const int16* pQ = compQuant ? gQuant1 : gQuant0;
+      uint16 r, dc;
+
+      uint8 s = huffDecode(compDCTab ? &gHuffTab1 : &gHuffTab0, compDCTab ? gHuffVal1 : gHuffVal0);
+      
+      r = 0;
+      numExtraBits = s & 0xF;
+      if (numExtraBits)
+         r = getBits2(numExtraBits);
+      dc = huffExtend(r, s);
+            
+      dc = dc + gLastDC[componentID];
+      gLastDC[componentID] = dc;
+            
+      gCoeffBuf[0] = dc * pQ[0];
+
+      compACTab = gCompACTab[componentID];
+                        
+      for (k = 1; k < 64; k++)
+      {
+         uint16 extraBits;
+
+         s = huffDecode(compACTab ? &gHuffTab3 : &gHuffTab2, compACTab ? gHuffVal3 : gHuffVal2);
+
+         extraBits = 0;
+         numExtraBits = s & 0xF;
+         if (numExtraBits)
+            extraBits = getBits2(numExtraBits);
+
+         r = s >> 4;
+         s &= 15;
+
+         if (s)
+         {
+            int16 ac;
+
+            if (r)
+            {
+               if ((k + r) > 63)
+                  return PJPG_DECODE_ERROR;
+
+               while (r)
+               {
+                  gCoeffBuf[ZAG[k++]] = 0;
+                  r--;
+               }
+            }
+
+            ac = huffExtend(extraBits, s);
+            
+            gCoeffBuf[ZAG[k]] = ac * pQ[k]; 
+         }
+         else
+         {
+            if (r == 15)
+            {
+               if ((k + 16) > 64)
+                  return PJPG_DECODE_ERROR;
+               
+               for (r = 16; r > 0; r--)
+                  gCoeffBuf[ZAG[k++]] = 0;
+               
+               k--; // - 1 because the loop counter is k
+            }
+            else
+               break;
+         }
+      }
+      
+      while (k < 64)
+         gCoeffBuf[ZAG[k++]] = 0;
+
+      transformBlock(mcuBlock); 
+   }
+         
+   return 0;
+}
+//------------------------------------------------------------------------------
+unsigned char pjpeg_decode_mcu(void)
+{
+   uint8 status;
+
+   if (!gNumMCUSRemaining)
+      return PJPG_NO_MORE_BLOCKS;
+      
+   status = decodeNextMCU();
+   if (status)
+      return status;
+      
+   gNumMCUSRemaining--;
+   
+   return 0;
+}
+//------------------------------------------------------------------------------
+unsigned char pjpeg_decode_init(pjpeg_image_info_t *pInfo, pjpeg_need_bytes_callback_t pNeed_bytes_callback, void *pCallback_data)
+{
+   uint8 status;
+
+   g_pNeedBytesCallback = pNeed_bytes_callback;
+   g_pCallback_data = pCallback_data;
+    
+   status = init();
+   if (status)
+      return status;
+      
+   status = locateSOFMarker();
+   if (status)
+      return status;
+
+   status = initFrame();
+   if (status)
+      return status;
+
+   status = initScan();
+   if (status)
+      return status;
+
+   pInfo->m_width = gImageXSize;
+   pInfo->m_height = gImageYSize;
+   pInfo->m_comps = gCompsInFrame;
+   pInfo->m_scanType = gScanType;
+   pInfo->m_MCUSPerRow = gMaxMCUSPerRow;
+   pInfo->m_MCUSPerCol = gMaxMCUSPerCol;
+   pInfo->m_MCUWidth = gMaxMCUXSize;
+   pInfo->m_MCUHeight = gMaxMCUYSize;
+   pInfo->m_pMCUBufR = gMCUBufR;
+   pInfo->m_pMCUBufG = gMCUBufG;
+   pInfo->m_pMCUBufB = gMCUBufB;
+      
+   return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/picojpeg/picojpeg.h	Tue Oct 11 01:24:18 2011 +0000
@@ -0,0 +1,102 @@
+//------------------------------------------------------------------------------
+// picojpeg v1.0 - Public domain, Rich Geldreich <richgel99@gmail.com>
+//------------------------------------------------------------------------------
+#ifndef PICOJPEG_H
+#define PICOJPEG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Error codes
+enum
+{
+   PJPG_NO_MORE_BLOCKS = 1,
+   PJPG_BAD_DHT_COUNTS,
+   PJPG_BAD_DHT_INDEX,
+   PJPG_BAD_DHT_MARKER,
+   PJPG_BAD_DQT_MARKER,
+   PJPG_BAD_DQT_TABLE,
+   PJPG_BAD_PRECISION,
+   PJPG_BAD_HEIGHT,
+   PJPG_BAD_WIDTH,
+   PJPG_TOO_MANY_COMPONENTS,
+   PJPG_BAD_SOF_LENGTH,
+   PJPG_BAD_VARIABLE_MARKER,
+   PJPG_BAD_DRI_LENGTH,
+   PJPG_BAD_SOS_LENGTH,
+   PJPG_BAD_SOS_COMP_ID,
+   PJPG_W_EXTRA_BYTES_BEFORE_MARKER,
+   PJPG_NO_ARITHMITIC_SUPPORT,
+   PJPG_UNEXPECTED_MARKER,
+   PJPG_NOT_JPEG,
+   PJPG_UNSUPPORTED_MARKER,
+   PJPG_BAD_DQT_LENGTH,
+   PJPG_TOO_MANY_BLOCKS,
+   PJPG_UNDEFINED_QUANT_TABLE,
+   PJPG_UNDEFINED_HUFF_TABLE,
+   PJPG_NOT_SINGLE_SCAN,
+   PJPG_UNSUPPORTED_COLORSPACE,
+   PJPG_UNSUPPORTED_SAMP_FACTORS,
+   PJPG_DECODE_ERROR,
+   PJPG_BAD_RESTART_MARKER,
+   PJPG_ASSERTION_ERROR,
+   PJPG_BAD_SOS_SPECTRAL,
+   PJPG_BAD_SOS_SUCCESSIVE,
+   PJPG_STREAM_READ_ERROR,
+   PJPG_NOTENOUGHMEM,
+   PJPG_UNSUPPORTED_COMP_IDENT,
+   PJPG_UNSUPPORTED_QUANT_TABLE,
+   PJPG_UNSUPPORTED_MODE,
+};  
+
+// Scan types - currently only GRAYSCALE, YH1V1, and YH2V2 are actually supported.
+typedef enum
+{
+   PJPG_GRAYSCALE,
+   PJPG_YH1V1,
+   PJPG_YH2V1,
+   PJPG_YH1V2,
+   PJPG_YH2V2
+} pjpeg_scan_type_t;
+
+typedef struct
+{
+   // Image resolution
+   int m_width;
+   int m_height;
+   // Number of components (1 or 3)
+   int m_comps;
+   // Total number of minimum coded units (MCU's) per row/col.
+   int m_MCUSPerRow;
+   int m_MCUSPerCol;
+   // Scan type
+   pjpeg_scan_type_t m_scanType;
+   // MCU width/height in pixels
+   int m_MCUWidth;
+   int m_MCUHeight;
+   // Pointers to internal MCU pixel component buffers. 
+   // These buffers Will be filled with pixels each time pjpegDecodeMCU() is called successfully.
+   // Each MCU consists of (m_MCUWidth/8)*(m_MCUHeight/8) blocks (currently either 1 for greyscale/no subsampling, or 4 for H2V2 sampling factors), where each block is a contiguous array of 64 (8x8) bytes.
+   // For greyscale images, only the values in m_pMCUBufR are valid.
+   unsigned char *m_pMCUBufR;
+   unsigned char *m_pMCUBufG;
+   unsigned char *m_pMCUBufB;
+} pjpeg_image_info_t;
+
+typedef unsigned char (*pjpeg_need_bytes_callback_t)(unsigned char* pBuf, unsigned char buf_size, unsigned char *pBytes_actually_read, void *pCallback_data);
+
+// Initializes the decompressor. Returns 0 on success, or one of the above error codes on failure.
+// pNeed_bytes_callback will be called to fill the decompressor's internal input buffer.
+// Not thread safe.
+unsigned char pjpeg_decode_init(pjpeg_image_info_t *pInfo, pjpeg_need_bytes_callback_t pNeed_bytes_callback, void *pCallback_data);
+
+// Decompresses the file's next MCU. Returns 0 on success, PJPG_NO_MORE_BLOCKS if no more blocks are available, or an error code.
+// Must be called a total of m_MCUSPerRow*m_MCUSPerCol times to completely decompress the image.
+unsigned char pjpeg_decode_mcu(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PICOJPEG_H