The codebase to run the *spark d-fuser controller www.sparkav.co.uk/dvimixer

Dependencies:   SPK-TVOne DMX DmxArtNet NetServicesMin OSC PinDetect mRotaryEncoder iniparser mbed spk_oled_ssd1305 filter

Files at this revision

API Documentation at this revision

Comitter:
tobyspark
Date:
Sat Mar 10 19:26:44 2012 +0000
Child:
1:f9fca21102e0
Commit message:
v15 - PCB a la toby; OLED a la toby

Changed in this revision

PinDetect.lib Show annotated file Show diff for this revision Revisions of this file
mRotaryEncoder.lib 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.lib Show annotated file Show diff for this revision Revisions of this file
spk_mRotaryEncoder.h Show annotated file Show diff for this revision Revisions of this file
spk_oled_gfx.h Show annotated file Show diff for this revision Revisions of this file
spk_oled_ssd1305.cpp Show annotated file Show diff for this revision Revisions of this file
spk_oled_ssd1305.h Show annotated file Show diff for this revision Revisions of this file
spk_tvone.h Show annotated file Show diff for this revision Revisions of this file
spk_tvone_mbed.cpp Show annotated file Show diff for this revision Revisions of this file
spk_tvone_mbed.h Show annotated file Show diff for this revision Revisions of this file
spk_utils.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PinDetect.lib	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/libraries/PinDetect/lkyxpw
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mRotaryEncoder.lib	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/charly/libraries/mRotaryEncoder/lmcj2u
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,429 @@
+// *SPARK D-FUSER
+// A project by *spark audio-visual
+//
+// 'DJ' controller styke RS232 Control for TV-One products
+// Good for 1T-C2-750, others will need some extra work
+//
+// Copyright *spark audio-visual 2009-2011
+//
+// v10 - Port to mBed, keying redux - Apr'11
+// v11 - Sign callbacks, code clean-up - Apr'11
+// v12 - TVOne header split into two: defines and mbed class. v002 header updates pulled down. Removed sign callbacks, rewrite of debug and signing. - Apr'11
+// v13 - Menu system for Resolution + Keying implemented, it writing to debug, it sending TVOne commands - Apr'11
+// v14 - Fixes for new PCB - Oct'11
+// v15 - TBZ PCB, OLED - Mar'12
+// v16 - TODO: EDID upload from USB mass storage
+// v17 - TODO: EDID creation from resolution
+
+// !! AIN on own thread doing some kind of low pass / median filter? ie. take average of two most similar values from last three
+
+#include "mbed.h"
+
+#include "spk_tvone_mbed.h"
+#include "spk_utils.h"
+#include "spk_mRotaryEncoder.h"
+#include "spk_oled_ssd1305.h"
+
+#include <sstream>
+
+#define kMenuLine1 4
+#define kMenuLine2 5
+#define kStatusLine 7
+
+//// DEBUG
+
+// Comment out one or the other...
+Serial *debug = new Serial(USBTX, USBRX); // For debugging via USB serial
+// Serial *debug = NULL; // For release (no debugging)
+
+//// mBED PIN ASSIGNMENTS
+
+// Inputs
+AnalogIn xFadeAIN(p19);    
+AnalogIn fadeUpAIN(p20);
+DigitalIn tapLeftDIN(p24);
+DigitalIn tapRightDIN(p21);
+
+SPKRotaryEncoder menuEnc(p17, p16, p15);
+
+// Outputs
+PwmOut fadeAPO(LED1);
+PwmOut fadeBPO(LED2);
+
+// SPKTVOne(PinName txPin, PinName rxPin, PinName signWritePin, PinName signErrorPin, Serial *debugSerial)
+SPKTVOne tvOne(p28, p27, LED3, LED4, debug);
+//SPKTVOne tvOne(p28, p27, LED3, LED4);
+
+// SPKDisplay(PinName mosi, PinName clk, PinName cs, PinName dc, PinName res, Serial *debugSerial = NULL);
+SPKDisplay screen(p5, p7, p8, p10, p9, debug);
+
+
+
+// Menu 
+
+SPKMenu *selectedMenu;
+SPKMenu *lastSelectedMenu;
+SPKMenuOfMenus mainMenu;
+SPKMenuPayload resolutionMenu;
+SPKMenuPayload mixModeMenu;
+
+// Fade logic constants + variables
+const float xFadeTolerance = 0.05;
+const float fadeUpTolerance = 0.05;
+float xFade = 0;
+float fadeUp = 1;
+
+// A&B Fade as resolved percent
+int fadeAPercent = 0;
+int fadeBPercent = 0;
+
+// Tap button states
+bool tapLeftPrevious = false;
+bool tapRightPrevious = false;
+
+// Key mode parameters
+int keyerParamsSet = -1; // last keyParams index uploaded to unit 
+// {lumakey, chroma on blue [, to be extended as needed] }
+// {minY, maxY, minU, maxU, minV, maxV }
+int keyerParams[2][6] = 
+{
+    {0, 18, 128, 129, 128, 129}, // lumakey
+    {41, 42, 240, 241, 109, 110} // chroma on blue
+    // ...
+};
+
+
+
+inline float fadeCalc (const float AIN, const float tolerance) {
+    float pos ;
+    if (AIN < tolerance) pos = 0;
+    else if (AIN > 1.0 - tolerance) pos = 1;
+    else pos = (AIN - tolerance) / (1 - 2*tolerance);
+    if (debug && false) debug->printf("fadeCalc in: %f out: %f \r\n", AIN, pos);
+    return pos;
+}
+
+bool setKeyParamsTo(int index) {   
+    // Only spend the time uploading six parameters if we need to
+    // Might want to bounds check here
+    
+    bool ok = false;
+    
+    if (index != keyerParamsSet)
+    {
+        ok =       tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinY, keyerParams[index][0]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxY, keyerParams[index][1]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinU, keyerParams[index][2]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxU, keyerParams[index][3]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinV, keyerParams[index][4]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxV, keyerParams[index][5]);
+        
+        keyerParamsSet = index;
+    } 
+    
+    return ok;
+}
+
+int main() 
+{
+
+    if (debug) 
+    { 
+        debug->printf("\r\n\r\n");
+        debug->printf("*spark d-fuser -----------\r\n");
+        debug->printf(" debug channel\r\n");
+    }
+    
+    // Splash screen
+    screen.imageToBuffer();
+    screen.textToBuffer("SPK:D-Fuser",0);
+    screen.textToBuffer("SW beta.15",1);
+    screen.sendBuffer();
+
+    
+    // Set menu structure
+    mixModeMenu.title = "Mix Mode";
+    enum { blend, additive, lumaKey, chromaKey1, chromaKey2, chromaKey3 }; // additive will require custom TVOne firmware.
+    mixModeMenu.addMenuItem("Blend", blend, 0);
+    mixModeMenu.addMenuItem("LumaKey", lumaKey, 0);
+    mixModeMenu.addMenuItem("ChromaKey - Blue", chromaKey1, 0);
+ 
+    resolutionMenu.title = "Resolution";
+    resolutionMenu.addMenuItem(kTV1ResolutionDescriptionVGA, kTV1ResolutionVGA, 5);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescriptionSVGA, kTV1ResolutionSVGA, 5);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescriptionXGAp60, kTV1ResolutionXGAp60, 5);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescriptionWSXGAPLUSp60, kTV1ResolutionWSXGAPLUSp60, 5);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescriptionWUXGAp60, kTV1ResolutionWUXGAp60, 5);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescription720p60, kTV1Resolution720p60, 5);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescription1080p60, kTV1Resolution1080p60, 5);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescriptionDualHeadSVGAp60, kTV1ResolutionDualHeadSVGAp60, 0);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescriptionDualHeadXGAp60, kTV1ResolutionDualHeadXGAp60, 0);
+    resolutionMenu.addMenuItem(kTV1ResolutionDescriptionTripleHeadVGAp60, kTV1ResolutionTripleHeadVGAp60, 0);
+
+    mainMenu.title = "Main Menu";
+    mainMenu.addMenuItem(&mixModeMenu);
+    mainMenu.addMenuItem(&resolutionMenu);
+    
+    selectedMenu = &mainMenu;
+    lastSelectedMenu = &mainMenu;    
+    
+    // Misc I/O stuff
+    
+    fadeAPO.period(0.001);
+    fadeBPO.period(0.001);
+    
+    // TVOne setup
+    
+    bool ok = false;
+    
+    // horrid, horrid HDCP
+    ok = tvOne.setHDCPOff();
+
+    std::string sendOK = ok ? "Sent: HDCP Off" : "Send Error: HDCP Off";
+
+    // display menu and framing lines
+    screen.horizLineToBuffer(kMenuLine1*pixInPage - 1);
+    screen.clearBufferRow(kMenuLine1);
+    screen.textToBuffer(selectedMenu->title, kMenuLine1);
+    screen.clearBufferRow(kMenuLine2);
+    screen.textToBuffer(selectedMenu->selectedString(), kMenuLine2);
+    screen.horizLineToBuffer(kMenuLine2*pixInPage + pixInPage);
+    screen.horizLineToBuffer(kStatusLine*pixInPage - 1);
+    screen.clearBufferRow(kStatusLine);
+    screen.textToBuffer(sendOK, 7);
+    screen.sendBuffer();
+
+
+    //// CONTROLS TEST
+
+    while (0) {
+        if (debug) debug->printf("xFade: %f, fadeOut: %f, tapLeft %i, tapRight: %i encPos: %i encChange:%i encHasPressed:%i \r\n" , xFadeAIN.read(), fadeUpAIN.read(), tapLeftDIN.read(), tapRightDIN.read(), menuEnc.getPos(), menuEnc.getChange(), menuEnc.hasPressed());
+    }
+
+    //// MIXER RUN
+
+    while (1) {
+
+        //// MENU
+        
+        int menuChange = menuEnc.getChange();
+        
+        // Update GUI
+        if (menuChange != 0)
+        {
+            if (debug) debug->printf("Menu changed by %i\r\n", menuChange);
+            
+            *selectedMenu = selectedMenu->selectedIndex() + menuChange;
+            
+            // update OLED line 2 here
+            screen.clearBufferRow(kMenuLine2);
+            screen.textToBuffer(selectedMenu->selectedString(), kMenuLine2);
+            screen.sendBuffer();
+            
+            if (debug) debug->printf("%s \r\n", selectedMenu->selectedString().c_str());
+
+        }
+        
+        // Action menu item
+        if (menuEnc.hasPressed()) 
+        {
+            if (debug) debug->printf("Action Menu Item!\r\n");
+        
+            // Are we changing menus?
+            if (selectedMenu->type() == menuOfMenus) 
+            {
+                // point selected menu to the new menu
+                // FIXME. Make this function abstract virtual of base class or get dynamic_cast working. BTW: C++ sucks / Obj-c rocks / Right now.
+                if (selectedMenu == &mainMenu) selectedMenu = mainMenu.selectedMenu();
+                else if (debug) debug->printf("FIXME: You've missed a SPKMenuOfMenus");
+                
+                // reset the selection within that menu to the first position
+                (*selectedMenu) = 0;
+                
+                // update OLED lines 1&2
+                screen.clearBufferRow(kMenuLine1);
+                screen.clearBufferRow(kMenuLine2);
+                screen.textToBuffer(selectedMenu->title, kMenuLine1);
+                screen.textToBuffer(selectedMenu->selectedString(), kMenuLine2);
+                screen.sendBuffer();
+                
+                if (debug)
+                {
+                    debug->printf("\r\n");
+                    debug->printf("%s \r\n", selectedMenu->title.c_str());
+                    debug->printf("%s \r\n", selectedMenu->selectedString().c_str());
+                }
+            }
+            // Are we cancelling?
+            else if (selectedMenu->type() == payload && selectedMenu->selectedIndex() == 0)           
+            {
+                selectedMenu = lastSelectedMenu;
+                
+                // update OLED lines 1&2
+                screen.clearBufferRow(kMenuLine1);
+                screen.clearBufferRow(kMenuLine2);
+                screen.textToBuffer(selectedMenu->title, kMenuLine1);
+                screen.textToBuffer(selectedMenu->selectedString(), kMenuLine2);
+                screen.sendBuffer();
+                
+                if (debug)
+                {
+                    debug->printf("\r\n");
+                    debug->printf("%s \r\n", selectedMenu->title.c_str());
+                    debug->printf("%s \r\n", selectedMenu->selectedString().c_str());
+                }
+            }
+            // With that out of the way, we should be actioning a specific menu's payload?
+            else if (selectedMenu == &mixModeMenu)
+            {
+                bool ok = false;
+                std::string sentOK;
+                std::stringstream sentMSG;
+            
+                // Set keying parameters
+                switch (mixModeMenu.selectedPayload1()) {
+                case lumaKey:
+                    ok = setKeyParamsTo(0);
+                    sentMSG << "Keyer Params 0, ";
+                    break;
+                case chromaKey1:
+                    ok = setKeyParamsTo(1);
+                    sentMSG << "Keyer Params 1, ";
+                    break;
+                }
+
+                // Set keying on or off
+                switch (mixModeMenu.selectedPayload1()) {
+                case blend:
+                case additive:
+                    ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerEnable, false);
+                    sentMSG << "Keyer Off";
+                    break;
+                case lumaKey:
+                case chromaKey1:
+                case chromaKey2:
+                case chromaKey3:
+                    ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerEnable, true);
+                    sentMSG << "Keyer On";
+                    break;
+                }
+                
+                if (ok) sentOK = "Sent:";
+                else sentOK = "Send Error:";
+                
+                screen.clearBufferRow(kStatusLine);
+                screen.textToBuffer(sentOK + sentMSG.str(), kStatusLine);
+                screen.sendBuffer();
+                
+                if (debug) { debug->printf("Changing mix mode"); }
+            }
+            else if (selectedMenu == &resolutionMenu)
+            {
+                bool ok = false;
+                
+                ok =       tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsOutputResolution, resolutionMenu.selectedPayload1());
+                ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, resolutionMenu.selectedPayload2());
+                ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, resolutionMenu.selectedPayload2());
+                
+                std::string sentOK;
+                if (ok) sentOK = "Sent: ";
+                else sentOK = "Send Error: ";
+                
+                std::stringstream sentMSG;
+                sentMSG << "Res " << resolutionMenu.selectedPayload1() << ", EDID " << resolutionMenu.selectedPayload2();
+                
+                screen.clearBufferRow(kStatusLine);
+                screen.textToBuffer(sentOK + sentMSG.str(), kStatusLine);
+                screen.sendBuffer();
+                
+                if (debug) { debug->printf("Changing resolution"); }
+            }
+            else
+            {
+                if (debug) { debug->printf("Warning: No action identified"); }
+            }
+
+        }
+        
+
+        
+        //// MIX 
+
+        bool updateFade = false;
+
+        // Get new states of tap buttons, remembering at end of loop() assign these current values to the previous variables
+        const bool tapLeft = (tapLeftDIN) ? false : true;
+        const bool tapRight = (tapRightDIN) ? false : true;
+        
+        // We're going to cache the analog in reads, as have seen wierdness otherwise
+        const float xFadeAINCached = xFadeAIN.read();
+        const float fadeUpAINCached = fadeUpAIN.read();
+        
+        // When a tap is depressed, we can ignore any move of the crossfader but not fade to black
+        if (tapLeft || tapRight) 
+        {
+            // If both are pressed, which was not pressed in the last loop?
+            if (tapLeft && tapRight) 
+            {
+                if (!tapLeftPrevious) xFade = 0;
+                if (!tapRightPrevious) xFade = 1;
+            }
+            // If just one is pressed, is this it going high or the other going low?
+            else if (tapLeft && (!tapLeftPrevious || tapRightPrevious)) xFade = 0;
+            else if (tapRight && (!tapRightPrevious || tapLeftPrevious)) xFade = 1;
+        } 
+        else xFade = fadeCalc(xFadeAINCached, xFadeTolerance);
+
+        fadeUp = 1.0 - fadeCalc(fadeUpAINCached, fadeUpTolerance);
+
+        // WISH: Really, we should have B at 100% and A fading in over that, with fade to black implemented as a fade in black layer on top of that correct mix.
+        // There is no way to implement that though, and the alphas get messy, so this is the only way (afaik).
+        
+        // Calculate new A&B fade percents
+        int newFadeAPercent = 0;
+        int newFadeBPercent = 0;
+
+        switch (mixModeMenu.selectedPayload1()) {
+        case blend:
+        case additive: 
+            newFadeAPercent = (1.0-xFade) * fadeUp * 100.0;
+            newFadeBPercent = xFade * fadeUp * 100.0;
+            break;
+        case lumaKey:
+        case chromaKey1:
+        case chromaKey2:
+        case chromaKey3:
+            newFadeAPercent = (1.0-xFade) * fadeUp * 100.0;
+            newFadeBPercent = fadeUp * 100.0;
+            break;
+        }            
+        
+        // Send to TVOne if percents have changed
+        if (newFadeAPercent != fadeAPercent) {
+            fadeAPercent = newFadeAPercent;
+            updateFade = true;
+            
+            fadeAPO = fadeAPercent / 100.0;
+            tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsMaxFadeLevel, fadeAPercent);
+        }
+
+        if (newFadeBPercent != fadeBPercent) {
+            fadeBPercent = newFadeBPercent;
+            updateFade = true;
+            
+            fadeBPO = fadeBPercent / 100.0;
+            tvOne.command(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsMaxFadeLevel, fadeBPercent);
+        }
+
+        if (updateFade && debug) {
+            debug->printf("\r\n"); 
+            //debug->printf("xFade = %3f   fadeUp = %3f \r\n", xFadeAIN.read(), fadeUpAIN.read());
+            debug->printf("xFade = %3f   fadeUp = %3f \r\n", xFadeAINCached, fadeUpAINCached);
+            debug->printf("xFade = %3f   fadeUp = %3f   fadeA% = %i   fadeB% = %i \r\n", xFade, fadeUp, fadeAPercent, fadeBPercent);
+        }
+        
+        // END OF LOOP - Reset
+        tapLeftPrevious = tapLeft;
+        tapRightPrevious = tapRight;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.lib	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/projects/libraries/svn/mbed/trunk@28
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spk_mRotaryEncoder.h	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,63 @@
+// *SPARK D-FUSER
+// A project by *spark audio-visual
+//
+// spkRotaryEncoder extends mRotaryEncoder to return the change on pot state since last queried
+// This allows the encoder to be polled when the host program is ready, and return info suitable for driving a TVOne style menu
+// Importantly to driving such a menu, it will ignore any further rotation after the switch is pressed.
+
+#include "mRotaryEncoder.h"
+
+class SPKRotaryEncoder : public mRotaryEncoder {
+
+public:
+    bool    hasPressed();
+    int     getChange();
+    int     getPos(); // This would be a Get() override, but its not virtual. We use this instead to correct for positions-per-detent
+    SPKRotaryEncoder(PinName pinA, PinName pinB, PinName pinSW, PinMode pullMode=PullUp, int debounceTime_us=1000);
+
+private:
+    void    onPress();
+    bool    m_hasPressed;
+    int     m_positionOld;
+    int     m_positionOnPress;
+
+};
+
+SPKRotaryEncoder::SPKRotaryEncoder(PinName pinA, PinName pinB, PinName pinSW, PinMode pullMode, int debounceTime_us) : mRotaryEncoder(pinA, pinB, pinSW, pullMode, debounceTime_us)
+{
+    attachSW(this,&SPKRotaryEncoder::onPress);
+}
+
+bool SPKRotaryEncoder::hasPressed()
+{
+    bool hasPressed = m_hasPressed;
+    m_hasPressed = false;
+    
+    return hasPressed;
+}
+
+int SPKRotaryEncoder::getChange()
+{
+    int positionEnc = this->getPos();
+        
+    int positionToUse = m_hasPressed ? m_positionOnPress : positionEnc;
+    int change = positionToUse - m_positionOld;
+    
+    m_positionOld = positionEnc;
+
+    return change;
+}
+
+int SPKRotaryEncoder::getPos()
+{
+    int positionEnc = this->Get();
+    int positionsPerDetent = 2;
+    
+    return positionEnc / positionsPerDetent;
+}
+
+void SPKRotaryEncoder::onPress()
+{
+    m_positionOnPress = this->getPos();
+    m_hasPressed = true;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spk_oled_gfx.h	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,121 @@
+// *spark audio-visual
+// OLED display using SSD1305 driver
+// Copyright *spark audio-visual 2012
+
+#ifndef SPK_OLED_GFX_h
+#define SPK_OLED_GFX_h
+
+#include "mbed.h"
+
+uint8_t image[] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x8F, 0x07, 0x03, 0x03, 0x01, 0xC0, 0xF8, 0xBC, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFE, 0xE0, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x1F, 0x4F, 0xE7, 0xE7, 0xF3, 0xB9, 0xD8, 0xEC, 0x6E, 0x7E, 0x7D, 0x53, 0x47, 0x1E, 0x3F, 0x93, 0x83, 0xC3, 0xC1, 0xE1, 0xE1, 0xF1, 0xF9, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x80, 0xFE, 0x80, 0xF0, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0x7C, 0x7C, 0x3F, 0x9F, 0x0F, 0xCF, 0xE7, 0xE3, 0x33, 0xB9, 0xDC, 0x6C, 0x76, 0x3E, 0x3C, 0x7C, 0x6E, 0x05, 0x03, 0x8F, 0x8F, 0xC8, 0xE0, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0x1F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x60, 0x70, 0xE0, 0xE2, 0xC4, 0xCC, 0xD8, 0xF0, 0xE0, 0xC8, 0xF0, 0xE0, 0xC3, 0x8C, 0xB8, 0xF0, 0xC0, 0xC0, 0xC0, 0x80, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3E, 0x30, 0x98, 0xCC, 0x0E, 0x27, 0x73, 0xF1, 0xD9, 0xFC, 0x6E, 0x36, 0x3B, 0x9F, 0x8F, 0xCC, 0xE1, 0xF3, 0xE7, 0xCE, 0xC8, 0xE0, 0xF6, 0xFE, 0xFE, 0xFC, 0xFE, 0xFE, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x09, 0x9B, 0xDF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3D, 0x3F, 0x7F, 0x1F, 0x87, 0xEF, 0xC7, 0x07, 0x03, 0x39, 0x79, 0xFC, 0x6E, 0x36, 0xBB, 0xDD, 0x6C, 0x76, 0x3E, 0x9C, 0x90, 0xC1, 0xE3, 0xE6, 0xD0, 0xD1, 0xCF, 0xCF, 0xCF, 0x87, 0xC7, 0x43, 0x43, 0x01, 0x01, 0x80, 0x81, 0x81, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x81, 0x81, 0xC7, 0xD7, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0x78, 0x30, 0x83, 0xC7, 0xEF, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, 0x9C, 0x1C, 0x4C, 0xCC, 0xC0, 0xC2, 0xF3, 0xF9, 0xFC, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x9F, 0x1B, 0x19, 0x19, 0x19, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0xA0, 0xB0, 0xF0, 0x78, 0xF9, 0xBD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0x79, 0xFC, 0xFC, 0xFE, 0xFC, 0xF1, 0xF3, 0xF9, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF1, 0xF1, 0xD3, 0xC3, 0x87, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x07, 0x0C, 0x0D, 0x19, 0x10, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x22, 0x71, 0x71, 0x39, 0x1C, 0x1E, 0x0F, 0x0F, 0x07, 0x03, 0x03, 0x21, 0x31, 0x18, 0x0F, 0x07, 0x03, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x3F, 0x0F, 0x3F, 0x3F, 0x1F, 0x0F, 0x3F, 0x7F, 0xFF, 0x7F, 0x4F, 0x1B, 0x13, 0x01, 0x03, 0x06, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+// number of columns, column0 hex, column1 hex...
+uint8_t char33[] = {1, 0x2F};
+uint8_t char34[] = {3, 0x06, 0x00, 0x06};
+uint8_t char35[] = {5, 0x14, 0x3E, 0x14, 0x3E, 0x14};
+uint8_t char36[] = {5, 0x24, 0x2A, 0x7F, 0x2A, 0x12};
+uint8_t char37[] = {5, 0x06, 0x36, 0x08, 0x36, 0x30};
+uint8_t char38[] = {6, 0x14, 0x2A, 0x2A, 0x24, 0x10, 0x08};
+uint8_t char39[] = {1, 0x06};
+uint8_t char40[] = {2, 0x3E, 0x41};
+uint8_t char41[] = {2, 0x41, 0x3E};
+uint8_t char42[] = {5, 0x14, 0x08, 0x3E, 0x08, 0x14};
+uint8_t char43[] = {5, 0x08, 0x08, 0x3E, 0x08, 0x08};
+uint8_t char44[] = {2, 0x40, 0x20};
+uint8_t char45[] = {3, 0x08, 0x08, 0x08};
+uint8_t char46[] = {1, 0x20};
+uint8_t char47[] = {3, 0x30, 0x08, 0x06};
+uint8_t char48[] = {5, 0x1C, 0x22, 0x2A, 0x22, 0x1C};
+uint8_t char49[] = {3, 0x22, 0x3E, 0x20};
+uint8_t char50[] = {5, 0x32, 0x2A, 0x2A, 0x2A, 0x24};
+uint8_t char51[] = {5, 0x22, 0x2A, 0x2A, 0x2A, 0x14};
+uint8_t char52[] = {5, 0x18, 0x14, 0x12, 0x3E, 0x10};
+uint8_t char53[] = {5, 0x2E, 0x2A, 0x2A, 0x2A, 0x12};
+uint8_t char54[] = {5, 0x1C, 0x2A, 0x2A, 0x2A, 0x10};
+uint8_t char55[] = {4, 0x02, 0x32, 0x0A, 0x06};
+uint8_t char56[] = {5, 0x14, 0x2A, 0x2A, 0x2A, 0x14};
+uint8_t char57[] = {5, 0x04, 0x2A, 0x2A, 0x2A, 0x1C};
+uint8_t char58[] = {1, 0x24};
+uint8_t char59[] = {2, 0x40, 0x24};
+uint8_t char60[] = {3, 0x08, 0x14, 0x22};
+uint8_t char61[] = {4, 0x14, 0x14, 0x14, 0x14};
+uint8_t char62[] = {3, 0x22, 0x14, 0x08};
+uint8_t char63[] = {4, 0x01, 0x2D, 0x05, 0x02};
+uint8_t char64[] = {6, 0x3E, 0x41, 0x4D, 0x55, 0x15, 0x1E};
+uint8_t char65[] = {5, 0x3C, 0x0A, 0x0A, 0x0A, 0x3C};
+uint8_t char66[] = {5, 0x3E, 0x2A, 0x2A, 0x2A, 0x14};
+uint8_t char67[] = {5, 0x1C, 0x22, 0x22, 0x22, 0x14};
+uint8_t char68[] = {5, 0x3E, 0x22, 0x22, 0x22, 0x1C};
+uint8_t char69[] = {4, 0x3E, 0x2A, 0x2A, 0x22};
+uint8_t char70[] = {4, 0x3E, 0x0A, 0x0A, 0x02};
+uint8_t char71[] = {5, 0x1C, 0x22, 0x22, 0x2A, 0x1A};
+uint8_t char72[] = {5, 0x3E, 0x08, 0x08, 0x08, 0x3E};
+uint8_t char73[] = {1, 0x3E};
+uint8_t char74[] = {5, 0x10, 0x20, 0x20, 0x20, 0x1E};
+uint8_t char75[] = {5, 0x3E, 0x08, 0x08, 0x14, 0x22};
+uint8_t char76[] = {4, 0x3E, 0x20, 0x20, 0x20};
+uint8_t char77[] = {5, 0x3E, 0x04, 0x08, 0x04, 0x3E};
+uint8_t char78[] = {5, 0x3E, 0x04, 0x08, 0x10, 0x3E};
+uint8_t char79[] = {5, 0x1C, 0x22, 0x22, 0x22, 0x1C};
+uint8_t char80[] = {5, 0x3E, 0x0A, 0x0A, 0x0A, 0x04};
+uint8_t char81[] = {3, 0x1C, 0x22, 0x72};
+uint8_t char82[] = {5, 0x3E, 0x0A, 0x0A, 0x1A, 0x24};
+uint8_t char83[] = {5, 0x24, 0x2A, 0x2A, 0x2A, 0x12};
+uint8_t char84[] = {5, 0x02, 0x02, 0x3E, 0x02, 0x02};
+uint8_t char85[] = {5, 0x1E, 0x20, 0x20, 0x20, 0x1E};
+uint8_t char86[] = {5, 0x06, 0x18, 0x20, 0x18, 0x06};
+uint8_t char87[] = {7, 0x1E, 0x20, 0x10, 0x0E, 0x10, 0x20, 0x1E};
+uint8_t char88[] = {5, 0x22, 0x14, 0x08, 0x14, 0x22};
+uint8_t char89[] = {5, 0x02, 0x04, 0x38, 0x04, 0x02};
+uint8_t char90[] = {5, 0x22, 0x32, 0x2A, 0x26, 0x22};
+uint8_t char91[] = {2, 0x7F, 0x41};
+uint8_t char92[] = {3, 0x06, 0x08, 0x30};
+uint8_t char93[] = {2, 0x41, 0x7F};
+uint8_t char94[] = {3, 0x04, 0x02, 0x04};
+uint8_t char95[] = {4, 0x40, 0x40, 0x40, 0x40};
+uint8_t char96[] = {2, 0x02, 0x04};
+uint8_t char97[] = {5, 0x3C, 0x0A, 0x0A, 0x0A, 0x3C};
+uint8_t char98[] = {5, 0x3E, 0x2A, 0x2A, 0x2A, 0x14};
+uint8_t char99[] = {5, 0x1C, 0x22, 0x22, 0x22, 0x14};
+uint8_t char100[] = {5, 0x3E, 0x22, 0x22, 0x22, 0x1C};
+uint8_t char101[] = {4, 0x1C, 0x2A, 0x2A, 0x22};
+uint8_t char102[] = {4, 0x3E, 0x0A, 0x0A, 0x02};
+uint8_t char103[] = {1, 0x1C};
+uint8_t char104[] = {5, 0x3E, 0x08, 0x08, 0x08, 0x3E};
+uint8_t char105[] = {1, 0x3A};
+uint8_t char106[] = {5, 0x10, 0x20, 0x22, 0x22, 0x1E};
+uint8_t char107[] = {5, 0x3E, 0x08, 0x08, 0x14, 0x22};
+uint8_t char108[] = {4, 0x3E, 0x20, 0x20, 0x20};
+uint8_t char109[] = {5, 0x3E, 0x04, 0x08, 0x04, 0x3E};
+uint8_t char110[] = {5, 0x3E, 0x04, 0x08, 0x10, 0x3E};
+uint8_t char111[] = {5, 0x1C, 0x22, 0x22, 0x22, 0x1C};
+uint8_t char112[] = {5, 0x3E, 0x0A, 0x0A, 0x0A, 0x04};
+uint8_t char113[] = {3, 0x1C, 0x22, 0x72};
+uint8_t char114[] = {5, 0x3E, 0x0A, 0x0A, 0x1A, 0x24};
+uint8_t char115[] = {5, 0x24, 0x2A, 0x2A, 0x2A, 0x12};
+uint8_t char116[] = {5, 0x02, 0x02, 0x3E, 0x02, 0x02};
+uint8_t char117[] = {5, 0x1E, 0x20, 0x20, 0x20, 0x1E};
+uint8_t char118[] = {5, 0x06, 0x18, 0x20, 0x18, 0x06};
+uint8_t char119[] = {7, 0x1E, 0x20, 0x10, 0x0E, 0x10, 0x20, 0x1E};
+uint8_t char120[] = {5, 0x22, 0x14, 0x08, 0x14, 0x22};
+uint8_t char121[] = {5, 0x02, 0x04, 0x38, 0x04, 0x02};
+uint8_t char122[] = {5, 0x22, 0x32, 0x2A, 0x26, 0x22};
+uint8_t char123[] = {3, 0x08, 0x77, 0x41};
+uint8_t char124[] = {1, 0x3E};
+uint8_t char125[] = {3, 0x41, 0x77, 0x08};
+uint8_t char126[] = {4, 0x04, 0x02, 0x04, 0x02};
+
+int characterBytesStartChar = 33;
+int characterBytesEndChar = 126;
+uint8_t* characterBytes[] = {char33, char34, char35, char36, char37, char38, char39, char40, char41, char42, char43, char44, char45, char46, char47, char48, char49, char50, char51, char52, char53, char54, char55, char56, char57, char58, char59, char60, char61, char62, char63, char64, char65, char66, char67, char68, char69, char70, char71, char72, char73, char74, char75, char76, char77, char78, char79, char80, char81, char82, char83, char84, char85, char86, char87, char88, char89, char90, char91, char92, char93, char94, char95, char96, char97, char98, char99, char100, char101, char102, char103, char104, char105, char106, char107, char108, char109, char110, char111, char112, char113, char114, char115, char116, char117, char118, char119, char120, char121, char122, char123, char124, char125, char126, };
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spk_oled_ssd1305.cpp	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,220 @@
+// *spark audio-visual
+// OLED display using SSD1305 driver
+// Copyright *spark audio-visual 2012
+
+#include "spk_oled_ssd1305.h"
+#include "spk_oled_gfx.h"
+#include "mbed.h"
+
+SPKDisplay::SPKDisplay(PinName mosiPin, PinName clkPin, PinName csPin, PinName dcPin, PinName resPin, Serial *debugSerial)
+{
+    spi = new SPI(mosiPin, NC, clkPin);
+    spi->format(8,3);
+    spi->frequency(2000000);
+    
+    cs = new DigitalOut(csPin);
+    dc = new DigitalOut(dcPin);
+    res = new DigitalOut(resPin);
+    
+    // Link up debug Serial object
+    // Passing in shared object as debugging is shared between all DVI mixer functions
+    debug = debugSerial;
+    
+    setup();
+    
+    clearBuffer();
+    
+    if (debug) debug->printf("SPKDisplay loaded\n\r");
+}
+
+void SPKDisplay::clearBuffer()
+{
+    memset(buffer, 0, bufferCount);
+}
+
+void SPKDisplay::imageToBuffer()
+{
+    memcpy(buffer, image, bufferCount);
+}
+
+void SPKDisplay::clearBufferRow(int row)
+{
+    // Range check
+    if (row >= 8)
+    {
+        if (debug) debug->printf("SPKDisplay::clearBufferRow sent out of bounds row");
+        return;
+    }
+    int bStart = row*bufferWidth;
+    int bEnd = bStart + pixelWidth;
+
+    for (int bPos = bStart; bPos <= bEnd; bPos++)
+    {
+        buffer[bPos] = 0x00;
+    }
+}
+
+void SPKDisplay::horizLineToBuffer(int y)
+{
+    if (y >= pixelHeight)
+    {
+        if (debug) debug->printf("SPKDisplay::clearBufferRow sent out of bounds y");
+        return;
+    }
+    
+    int row = (y*pixInPage) / pixelHeight;
+    int posInRow = y % pixInPage;
+    
+    int bStart = row*bufferWidth;
+    int bEnd = bStart + pixelWidth;
+    
+    for (int bPos = bStart; bPos <= bEnd; bPos++)
+    {
+        // Need to bitwise OR as setting single bit (the line) in byte (the row)
+        buffer[bPos] = buffer[bPos] | 0x01 << posInRow;
+    } 
+}
+
+void SPKDisplay::textToBuffer(std::string message, int row)
+{
+    // Range check
+    if (row >= 8) row = 7;
+    int bStart = row*bufferWidth;
+    int bEnd = bStart + pixelWidth;
+
+    int bPos = bStart;
+    for (int i = 0; i < message.size(); i++)
+    {
+        char character = message.at(i);
+        
+        // Is it outside the range we have glyphs for?
+        if ((character < characterBytesStartChar) || (character > characterBytesEndChar))
+        {
+            // Treat as a space
+            for (int j = 0; j < 5; j++)
+            {
+                if (bPos >= bEnd) break;
+                buffer[bPos++] = 0x00;
+            }
+            
+            // Warn if not
+            if (debug)
+            {
+                if (character != ' ') debug->printf("No glyph for character %c at position %i", character, i);
+            }
+        }
+        // If not, typeset it!
+        else 
+        {
+            // Shift into our array's indexing
+            character -= characterBytesStartChar;
+            
+            // Write each byte's vertical column of 8bits into the buffer.
+            for (int j = 0; j < characterBytes[character][0]; j++)
+            {
+                if (bPos >= bEnd) break;
+                buffer[bPos++] = characterBytes[character][j+1];
+            }
+            
+            // Put 1px letter spacing at end
+            if (bPos >= bEnd) break;
+            buffer[bPos++] = 0x00; // 1 px letter spacing
+        }
+    }
+}
+
+void SPKDisplay::sendBuffer()
+{
+    // Select the device by seting chip select low
+    *cs = 0;
+
+    // Set to receive DATA not commands
+    *dc = 1;
+
+    for (int i = 0; i < bufferCount; i++)
+    {
+        spi->write(buffer[i]);
+    }
+    
+    // Deselect the device
+    *cs = 1;
+}
+
+void SPKDisplay::setup()
+{
+    // TASK: SCREEN OFF, Run pre-flight
+    
+    // Hard reset the OLED
+    *res = 0;
+    wait_ms(1);
+    *res = 1;
+
+    // Select the device by seting chip select low
+    *cs = 0;
+    
+    // Set to receive COMMANDS not data
+    *dc = 0;
+
+    spi->write(0xAE); // set display off
+    spi->write(0xD5); // set display clock divide ratio
+    spi->write(0xA0);
+    spi->write(0xA8); // set multiplex ratio
+    spi->write(0x3F); 
+    spi->write(0xD3); // set display offset
+    spi->write(0x00);
+    spi->write(0x40); // set display start line
+    spi->write(0xAD); // set master configuration
+    spi->write(0x8E);
+    spi->write(0xD8); // set area color mode
+    spi->write(0x05);
+    spi->write(0xA1); // set segment re-map
+    spi->write(0xC8); // set com output scan direction
+    spi->write(0xDA); // set com pins hardware configuration
+    spi->write(0x12);
+    spi->write(0x91); // set look-up table
+    spi->write(0x3F);
+    spi->write(0x3F);
+    spi->write(0x3F);
+    spi->write(0x3F);
+    spi->write(0x81); // set current control for bank 0
+    spi->write(0x8F);
+    spi->write(0xD9); // set pre-charge period
+    spi->write(0xD2);
+    spi->write(0xDB); //set vcomh deselect level
+    spi->write(0x34);
+    spi->write(0xA4); // set entire display on/off
+    spi->write(0xA6); // set normal/inverse display
+    
+    spi->write(0x20); // page mode
+    spi->write(0x00);
+    
+    // TASK: Clear screen's content buffer
+    
+    // Is this neccessary when switching command/data?
+    *cs = 1;
+    wait_ms(1);
+    *cs = 0;
+    
+    // Set to receive DATA not commands
+    *dc = 1;
+        
+    for (int i = 0; i < bufferCount; i++)
+    {
+        spi->write(0x00);
+    }
+    
+    // TASK: SCREEN ON
+    
+    // Is this neccessary when switching command/data?
+    *cs = 1;
+    wait_ms(1);
+    *cs = 0;
+    
+    // Set to receive COMMANDS not data
+    *dc = 0;
+    
+    spi->write(0xAF); // set display on
+  
+    // Deselect the device
+    *cs = 1;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spk_oled_ssd1305.h	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,46 @@
+// *spark audio-visual
+// OLED display using SSD1305 driver
+// Copyright *spark audio-visual 2012
+
+// TODO
+// sendBufferIfNeeded() -- library caches whether buffer has been updated, and this method sends buffer if so
+
+#ifndef SPK_OLED_SSD1305_h
+#define SPK_OLED_SSD1305_h
+
+#include "mbed.h"
+#include <string> 
+
+#define bufferCount 1056
+#define bufferWidth 132
+#define pixelWidth 128
+#define pixelHeight 64
+#define pixInPage 8
+#define pageCount 8
+
+class SPKDisplay
+{
+  public:
+    SPKDisplay(PinName mosi, PinName clk, PinName cs, PinName dc, PinName res, Serial *debugSerial = NULL);
+
+    void clearBuffer();
+    void clearBufferRow(int row);
+    void imageToBuffer();
+    void horizLineToBuffer(int y);
+    void textToBuffer(std::string message, int row);
+    
+    void sendBuffer();
+    
+  private:
+    SPI *spi;
+    DigitalOut *cs;
+    DigitalOut *dc;
+    DigitalOut *res;
+    
+    Serial *debug;
+    uint8_t buffer[bufferCount];
+    
+    void setup(); 
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spk_tvone.h	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,348 @@
+// *spark audio-visual and v002
+// RS232 Control for TV-One products
+// Good for 1T-C2-750, others will need some extra work
+// Copyright *spark audio-visual / v002 2009-2011
+
+#ifndef SPKTVOne_h
+#define SPKTVOne_h
+
+// Sources - Note only higher end models have more than 2 in....
+//#pragma mark -
+//#pragma mark Channel / Sources
+
+#define kTV1SourceRGB1                                0x10
+#define kTV1SourceRGB2                                0x11    
+#define kTV1SourceRGB3                                0x12 
+#define kTV1SourceRGB4                                0x13 
+#define kTV1SourceRGB5                                0x14 
+#define kTV1SourceRGB6                                0x15 
+
+// Window
+//#pragma mark -
+//#pragma mark Window IDs
+
+#define kTV1WindowIDA                                'A' // aka 0x41 
+#define kTV1WindowIDB                                'B'
+#define kTV1WindowIDZ                                'Z'
+#define kTV1WindowIDLogoA                            'a'    // aka 0x61
+#define kTV1WindowIDLogoB                            'b'
+
+//#pragma mark -
+//#pragma mark Functions
+
+// Complete function list for verbosity. We will probably only be using a small small subset. Useful to have in one place.
+
+// Preset & Mixer Mode Functions
+#define kTV1FunctionMode                            0x109    // Values: 0 = Switcher, 1 = Independant, 2 = Dual PIP
+#define kTV1FunctionPreset                            0x225    // Values: 0 - 9 (Preset 1 to 10) Set the current preset for the following functions.     
+#define kTV1FunctionPresetLoad                        0x226    // Values: 1 to Load - switches back to 0 after a load
+#define kTV1FunctionPresetStore                        0x227    // Values: 1 to Store - switches back to 0 after a store
+#define kTV1FunctionPresetErase                        0x228    // Values: 1 to Erase - switches back to 0 after erase
+
+// Adjust output Functions
+//#pragma mark -
+#define kTV1FunctionAdjustOutputsOutputEnable        0x170    // Values: 0 = Blanked 1 = Active
+#define kTV1FunctionAdjustOutputsLockSource            0x149    // Values: 0x10 to 0x1F = RGB1 - RGB 16 (see manual for other values corresponding to SDI, CV etc)
+#define kTV1FunctionAdjustOutputsLockMethod            0x10A    // Values: 0 = Off, 1 = Genlock, 2 = Lock & Mix (see manual for other values)
+#define kTV1FunctionAdjustOutputsLockHShift            0x14A    // Values: -4096 - 4096
+#define kTV1FunctionAdjustOutputsLockVShift            0x14B    // Values: -4096 - 4096
+#define kTV1FunctionAdjustOutputsOutputResolution    0x083    // Values: 0 - 1000 (which resolution, "pragma mark" Resolutions for list.
+#define kTV1FunctionAdjustOutputsOutputImageTypeA    0x0E2    // Values: 0 = RGBHV, 2 = RGBsB, 3 = YUV, 4 = tlYUV, 7 = tlRGB (Analog)
+#define kTV1FunctionAdjustOutputsOutputImageTypeD    0x16C    // Values: 0 = RGBHV, 3 = YUV, 9 = Not Available (?) (Digital)
+#define kTV1FunctionAdjustOutputsHDCPRequired        0x233    // Values: 0 = Off, 1 = On (if display supports it)
+#define kTV1FunctionAdjustOutputsHDCPStatus            0x234    // Values: 0 = Unavailable, 1 = Supported, 2 = Active, 3 = Repeater Supported, 4 = Repeater Active
+#define kTV1FunctionAdjustOutputsBackgroundY        0x13B    // Values: 16-235
+#define kTV1FunctionAdjustOutputsBackgroundU        0x13C    // Values: 16-235
+#define kTV1FunctionAdjustOutputsBackgroundV        0x13D    // Values: 16-235
+#define kTV1FunctionAdjustOutputsSDIOptimization    0x197    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustOutputsOutputStandard        0x101    // Values: 0 = NTSC/PAL, 1 = PAL-M / PAL-N, 2 = SECAM
+#define kTV1FunctionAdjustOutputsCVYCIRE            0x133    // Values: -0.75 - 12.5
+#define kTV1FunctionAdjustOutputsCVYCHue            0x139    // Values: -22 - 22
+#define kTV1FunctionAdjustOutputsSCHPhase            0x085    // Values: -180 - 180 
+#define kTV1FunctionAdjustOutputsLumaBandwidth        0x134    // Values: 0 = Low, 1 = Medium, 2 = High
+#define kTV1FunctionAdjustOutputsChromaBandwidth    0x135    // Values: 0 = Low, 1 = Medium, 2 = High
+#define kTV1FunctionAdjustOutputsOutputChromaDelay    0x137    // Values: -4 - 3
+#define kTV1FunctionAdjustOutputsPalWSS                0x130    // Values: 0-8 (see manual for value explanation) 
+#define kTV1FunctionAdjustOutputsTake                0x11E    // Values: 0->1 Perform a Preview -> Program transition (?)
+#define kTV1FunctionAdjustOutputsVolume                0x201    // Values: -16 - 15 (-16 = Mute)
+// Left out additional functions specific to SDI Audio Channel adjustment
+
+// Adjust Windows Functions -  Note for window functions, you must specify a Window to work on via the below value
+//#pragma mark -
+
+#define kTV1FunctionAdjustWindowsWindowSource        0x82    // Values: 0x10 to 0x1F = RGB1 to RGB16
+#define kTV1FunctionAdjustWindowsSelectUniSource    0x241    // Values: 0xE0 to OxEF for universal source 1 - 16
+#define kTV1FunctionAdjustWindowsSourceResolution    0xF8    // Values: (Read only) Resolution #
+#define kTV1FunctionAdjustWindowsEnable                0x12B    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustWindowsZoomLevel            0x86    // Values: 100 - 1000
+#define kTV1FunctionAdjustWindowsZoomLevelH            0x103    // Values: 100 - 1000 (only if advanced aspect ratio mode is enabled)
+#define kTV1FunctionAdjustWindowsZoomLevelV            0x105    // Values: 100 - 1000 (only if advanced aspect ratio mode is enabled)
+#define kTV1FunctionAdjustWindowsAspectRationIn        0x107    // Values: 0.1:1 - 9.99:1 (read only)
+#define kTV1FunctionAdjustWindowsZoomPanH            0x9F    // Values: 0 - 100
+#define kTV1FunctionAdjustWindowsZoomPanV            0xA0    // Values: 0 - 100
+#define kTV1FunctionAdjustWindowsImageFreeze        0x9C    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustWindowsCropH                0x223    // Values: 0 - 100
+#define kTV1FunctionAdjustWindowsCropV                0x224    // Values: 0 - 100
+#define kTV1FunctionAdjustWindowsOutShiftH            0xAD    // Values: -4096 - 4096
+#define kTV1FunctionAdjustWindowsOutShiftV            0xAE    // Values: -4096 - 4096
+#define kTV1FunctionAdjustWindowsShrinkLevel        0x87    // Values: 10 - 100
+#define kTV1FunctionAdjustWindowsShrinkLevelH        0x104    // Values: 10 - 100 (only if advanced aspect ratio mode is enabled)
+#define kTV1FunctionAdjustWindowsShrinkLevelV        0x106    // Values: 10 - 100 (only if advanced aspect ratio mode is enabled)
+#define kTV1FunctionAdjustWindowsShrinkEnable        0x18E    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustWindowsShrinkPosH            0xDA    // Values: 0 - 100
+#define kTV1FunctionAdjustWindowsShrinkPosV            0xDB    // Values: 0 - 100
+#define kTV1FunctionAdjustWindowsInTopLeftH            0x21B    // ??
+#define kTV1FunctionAdjustWindowsInTopLeftV            0x21D    // ??
+#define kTV1FunctionAdjustWindowsInSizeH            0x21C    // ??
+#define kTV1FunctionAdjustWindowsInSizeV            0x21E    // ??
+#define kTV1FunctionAdjustWindowsOutTopLeftH        0x21F    // ??
+#define kTV1FunctionAdjustWindowsOutTopLeftV        0x221    // ??
+#define kTV1FunctionAdjustWindowsOutSizeH            0x220    // ??
+#define kTV1FunctionAdjustWindowsOutTopLeft            0x222    // ??
+#define kTV1FunctionAdjustWindowsAspectChange        0x190    // Values: 0 = Normal, 1 = Letterbox, 2 = PillarBox
+#define kTV1FunctionAdjustWindowsAspectAdjust        0x102    // Values: 0 = Simple, 1 = Advanced
+#define kTV1FunctionAdjustWindowsFlickerReduction    0x92    // Values: 0 = Off, 1 = Low, 2 = Medium, 3 = High
+#define kTV1FunctionAdjustWindowsImageSmoothing        0xA1    // Values: 0 = Off, 1 = Medium, 2 = High
+#define kTV1FunctionAdjustWindowsImageFlip            0x95    // Values: 0 = Off, 1 = Horizontal, 2 = Vertical, 3 = H & V
+#define kTV1FunctionAdjustWindowsTemporalInterp        0x229    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustWindowsMaxFadeLevel        0x10F    // Values: 0 - 100
+#define kTV1FunctionAdjustWindowsFadeOutIn            0x193    // Values -1 = Fade Out, 0 = No Action, 1 = Fade In
+#define kTV1FunctionAdjustWindowsLayerPriority        0x144    // Values: 0 - 5
+#define kTV1FunctionAdjustWindowsHeadPhonVolume        0xFD    // Vaules: -16 - 15 (-16 = Mute)
+#define kTV1FunctionAdjustWindowsAudioVolume        0x206    // Vaules: -128 - 127 (
+#define kTV1FunctionAdjustWindowsAudioVolumeEnable    0x206    // Vaules: 0 = Off, 1 = On
+
+// Adjust Keyer
+//#pragma mark -
+
+#define kTV1FunctionAdjustKeyerEnable                0x127    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustKeyerMinY                    0xAF    // Values: 0 - 255        
+#define kTV1FunctionAdjustKeyerMinU                    0xB0    // Values: 0 - 255
+#define kTV1FunctionAdjustKeyerMinV                    0xB1    // Values: 0 - 255
+#define kTV1FunctionAdjustKeyerMaxY                    0xB2    // Values: 0 - 255
+#define kTV1FunctionAdjustKeyerMaxU                    0xB3    // Values: 0 - 255
+#define kTV1FunctionAdjustKeyerMaxV                    0xB4    // Values: 0 - 255
+#define kTV1FunctionAdjustKeyerSoftnessY            0x121    // Values: 0 - 255
+#define kTV1FunctionAdjustKeyerSoftnessU            0x123    // Values: 0 - 255
+#define kTV1FunctionAdjustKeyerSoftnessV            0x125    // Values: 0 - 255
+#define kTV1FunctionAdjustKeyerInvertY                0x122    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustKeyerInvertU                0x124    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustKeyerInvertV                0x126    // Values: 0 = Off, 1 = On (Typo in documentation, noted as 0x156) 
+#define kTV1FunctionAdjustKeyerSwap                    0x144    // Values: 0 = Off, 1 = On
+
+// Edge Blending (not used in TVOne 1T-C2-750, therefore not bothered with for now)
+//#define kTV1FunctionAdjustEdgeBlendXXX
+
+// Adjust Logos
+//#pragma mark -
+
+#define kTV1FunctionAdjustLogoEnable                0x12B    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustLogoNumber                0x143    // Values: 0 - 9 (Logo Selection)
+#define kTV1FunctionAdjustLogoOutShiftH                0xAD    // Values: 0 - 100
+#define kTV1FunctionAdjustLogoOutShiftV                0xAE    // Values: 0 - 100
+#define kTV1FunctionAdjustLogoMaxFadeLevel            0x10F    // Values: 0 - 100
+#define kTV1FunctionAdjustLogoLayerPriority            0x144    // Values: 0 - 5
+
+// Adjust Borders
+//#pragma mark -
+
+#define kTV1FunctionAdjustBorderEnable                0x150    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustBorderSizeH                0x151    // Values: 0 - 99
+#define kTV1FunctionAdjustBorderSizeV                0x152    // Values: 0 - 99
+#define kTV1FunctionAdjustBorderOffsetH                0x153    // Values: 0 - 99
+#define kTV1FunctionAdjustBorderOffsetV                0x154    // Values: 0 - 99
+#define kTV1FunctionAdjustBorderY                    0x155    // Values: 16 - 235
+#define kTV1FunctionAdjustBorderU                    0x156    // Values: 16 - 240    
+#define kTV1FunctionAdjustBorderV                    0x157    // Values: 16 - 240
+#define kTV1FunctionAdjustBorderOpacity                0x158    // Values: 0 - 100 ( 0 = Transparent, 100 = Opaque)
+
+// Adjust Sources - Note: These functions require the Channel parameter to be properly set. Not all functions take all channels.
+//#pragma mark -
+
+#define kTV1FunctionAdjustSourceTestCard            0xDC    // Values: 0 - 10
+#define kTV1FunctionAdjustSourceAutoSet                0xFE    // Values: 1 = Start AutoSet Procedure
+#define kTV1FunctionAdjustSourceAspectCorrect        0x240    // Values: 0 = Fill, 1 = Aspect, 2 = H-Fit, 3 = V-Fit, 4 = 1:1
+#define kTV1FunctionAdjustSourceEDID                0x243    // Values: 0 - 7 (edid entry number)
+#define kTV1FunctionAdjustSourceEDIDCapureID        0x244    // Values: 0 - 7 (edid entry number) - entry to grab into
+#define kTV1FunctionAdjustSourceEditCaptureGrab        0x245    // Values: 1 performs grab of Edid to currently set EDIDCapureID
+#define kTV1FunctionAdjustSourceHDCPAdvertize        0x237    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustSourceHDCPStatus            0x238    // Values: 0 = Inactive, 1 = Active (read only)
+#define kTV1FunctionAdjustSourcePositionH            0xB6    // Values: -100 - 100
+#define kTV1FunctionAdjustSourcePositionV            0xB7    // Values: -100 - 100
+#define kTV1FunctionAdjustSourceSizeH                0xDE    // Values: -100 - 100
+#define kTV1FunctionAdjustSourceSizeV                0xDF    // Values: -100 - 100
+#define kTV1FunctionAdjustSourceAudioXXX                    // Ignored for now In source, Option IN source Volume, Balance 
+#define kTV1FunctionAdjustSourceOnSourceLoss        0xA3    // Values: 0 = Show, 1 = Freeze, 2 = Blue, 3 = Black, 4 = Remove
+#define kTV1FunctionAdjustSourceSourceStable        0x22A    // Values: 0 = Unstable, 1 = Stable
+#define kTV1FunctionAdjustSourcePixelPhase            0x91    // Values: 0 - 31
+#define kTV1FunctionAdjustSourceRGBInType            0xC1    // Values: 0 = Auto, 1 = D-RGB, 2 = D-YUV, 3 = A-RGB, 4 = A-YUV (Digital / Analog)
+#define kTV1FunctionAdjustSourceRGBContributionR    0xC5    // Values: 75 - 150
+#define kTV1FunctionAdjustSourceRGBContributionG    0xC6    // Values: 75 - 150    
+#define kTV1FunctionAdjustSourceRGBContributionB    0xC7    // Values: 75 - 150
+#define kTV1FunctionAdjustSourceYUVSetup            0x23E    // Values: 0 = 0 IRE, 1 = 7.5 IRE
+#define kTV1FunctionAdjustSourceDeInterlace            0xB8    // Values: 0 = Normal, 1 = Auto, 2 = Film 3:2, 3 = Motion Compensation Low, 4 = Motion Compensation Medium, 5 = Motion Compensation High, 6 = Frame / Bob
+#define kTV1FunctionAdjustSourceFilmMode            0xE3    // Values: 0 = Not Detected 1 = Detected (read only) 
+#define kTV1FunctionAdjustSourceDiagonalInterp        0x22B    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustSourceNoiseReduction        0x23F    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustSourceBrightness            0xBB    // Values: 0 - 180    
+#define kTV1FunctionAdjustSourceContrast            0xBC    // Values: 0 - 180
+#define kTV1FunctionAdjustSourceSaturation            0xB9    // Values: 0 - 180
+#define kTV1FunctionAdjustSourceHue                    0xBA    // Values: -180 - 180
+#define kTV1FunctionAdjustSourceSharpness            0x80    // Values: -7 - 7
+#define kTV1FunctionAdjustSourceLumaDelay            0xBD    // Values: -4 -3
+#define kTV1FunctionAdjustSourceFieldSwap            0xC9    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustSourceFieldOffset            0x196    // Values: = 0 - 7
+#define kTV1FunctionAdjustSourceAudioChannel1                // Ignored for now
+#define kTV1FunctionAdjustSourceAudioChannel2                // Ignored for now
+#define kTV1FunctionAdjustSourceAudioChannel3                // Ignored for now
+#define kTV1FunctionAdjustSourceAudioChannel4                // Ignored for now
+#define kTV1FunctionAdjustSourceAudioChannel5                // Ignored for now
+#define kTV1FunctionAdjustSourceAudioChannel6                // Ignored for now
+#define kTV1FunctionAdjustSourceAudioChannel7                // Ignored for now
+
+// Adjust Audio
+//#pragma mark -
+#define kTV1FunctionAdjustAudioXXX                            // Ignored for now
+
+// Adjust Transitions
+//#pragma mark -
+#define kTV1FunctionAdjustTransitionType            0x112    // Values: 0 = Cut, 1 = Fade, 2 = Wipe, 3 = Push
+#define kTV1FunctionAdjustTransitionFadeTime        0xF5    // Values: 0 - 50 (0 - 5.0 seconds)
+#define kTV1FunctionAdjustTransitionWipeType        0x145    // Values: 0 = Left -> Right 1 = Right -> Left, 2 = Up -> Down, 3 = Down -> Up, 4 = Diagonal, 5 = Diamond 
+#define kTV1FunctionAdjustTransitionWipeSize        0x146    // Values: 10 - 2000
+
+// Adjust Resolutions
+
+/* 
+ Note: You MUST set the 'Image to adjust' value to the correct value first, 
+ and only then change the other values - otherwise you may be adjusting the wrong entry. 
+ The user should not adjust the 'Image to adjust' entry using the front panel whilst also accessing it via RS232
+ */
+
+//#pragma mark -
+#define kTV1FunctionAdjustResolutionImageToAdjust    0x81    // Values: 0 - 1000 - the preset you wish to manipulate
+#define kTV1FunctionAdjustResolutionInterlaced        0xCA    // Values: 0 = Off, 1 = On
+#define kTV1FunctionAdjustResolutionFreqCoarseH        0xBE    // Values: 10,000 - 200,000
+#define kTV1FunctionAdjustResolutionFreqFineH        0xBF    // Values: 10,000 - 200,000
+#define kTV1FunctionAdjustResolutionActiveH            0x96    // Values: 64 - 2047
+#define kTV1FunctionAdjustResolutionActiveV            0x97    // Values: 64 - 2047
+#define kTV1FunctionAdjustResolutionStartH            0x8B    // Values: 0 - 1023
+#define kTV1FunctionAdjustResolutionStartV            0x8C    // Values: 0 - 1023
+#define kTV1FunctionAdjustResolutionCLKS            0x8E    // Values: 64 - 4095
+#define kTV1FunctionAdjustResolutionLines            0xBE    // Values: 64 - 2047
+#define kTV1FunctionAdjustResolutionSyncH            0x8F    // Values: 8 - 1023
+#define kTV1FunctionAdjustResolutionSyncV            0x90    // Values: 1 - 1023
+#define kTV1FunctionAdjustResolutionSyncPolarity    0x94    // Values: 0 - 3 (++, +-. -+. --)
+
+// Adjust Misc
+//#pragma mark -
+#define kTV1FunctionAdjustFrontPanelLock            0xFC    // Values: 0 = Unlocked, 1 = Locked
+
+// Resolutions
+//#pragma mark -
+//#pragma mark Resolutions
+
+// Selected Common Resolutions and resolution Descriptions. For a complete list, use the menu system in your TV1
+
+// Res #27 640x480, 59.97Hz
+// Res #28 640x480, 60Hz
+// Res #99 1920x1080, 60Hz
+// Res #104 = 1920x1200, 60Hz
+
+#define kTV1ResolutionVGA                    0x8            
+#define kTV1ResolutionNTSC                    0xF                    
+#define kTV1ResolutionPAL                    0x10            
+#define kTV1ResolutionSVGA                    0x12        
+#define kTV1ResolutionXGAp5994                0x1B                    
+#define kTV1ResolutionXGAp60                0x1C                    
+#define kTV1ResolutionXGAp75                0x1D                     
+#define kTV1Resolution720p2398                0x27                
+#define kTV1Resolution720p24                0x28            
+#define kTV1Resolution720p25                0x29            
+#define kTV1Resolution720p2997                0x2A                
+#define kTV1Resolution720p30                0x2B            
+#define kTV1Resolution720p50                0x2C            
+#define kTV1Resolution720p5994                0x2D            
+#define kTV1Resolution720p60                0x2E            
+#define kTV1ResolutionWXGA5by3p60            0x30                         
+#define kTV1ResolutionWXGA5by3p75            0x31                         
+#define kTV1ResolutionWXGA16by10p60            0x34                         
+#define kTV1ResolutionWXGA16by10p75            0x35         
+#define kTV1ResolutionSGAp60                0x3A                    
+#define kTV1ResolutionSGAp75                0x3B        
+#define kTV1ResolutionWSXGAp60                0x40        
+#define kTV1ResolutionUXGAp60                0x47                    
+#define kTV1ResolutionUXGAp75                0x4A                    
+#define kTV1ResolutionUXGAp85                0x4B
+#define kTV1ResolutionWSXGAPLUSp60     0x53
+#define kTV1Resolution1080p2398                0x60      // NOTE Firmware 362 has higher resolution numbers for these resolutions         
+#define kTV1Resolution1080p24                0x62              
+#define kTV1Resolution1080p25                0x64            
+#define kTV1Resolution1080p2997                0x65         
+#define kTV1Resolution1080p30                0x66        
+#define kTV1Resolution1080p50                0x67        
+#define kTV1Resolution1080p5996                0x69        
+#define kTV1Resolution1080p60                0x6A                
+#define kTV1Resolution1080p75                0x6D        
+#define kTV1ResolutionWUXGAp60                0x70                        
+#define kTV1ResolutionWUXGAp75                0x73                     
+#define kTV1ResolutionWUXGAp85                0x74        
+
+#define kTV1ResolutionDescriptionVGA                "VGA (640x480) @ 60Hz"
+#define kTV1ResolutionDescriptionNTSC                "NTSC (720x480 @ 59.95Hz)"                        
+#define kTV1ResolutionDescriptionPAL                "PAL (720x576 @ 50Hz)"    
+#define kTV1ResolutionDescriptionSVGA                "SVGA (800x600) @ 60Hz"    
+#define kTV1ResolutionDescriptionXGAp5994            "XGA (1024x768) @ 59.94Hz"                        
+#define kTV1ResolutionDescriptionXGAp60                "XGA (1024x768) @ 60Hz"                            
+#define kTV1ResolutionDescriptionXGAp75                "XGA (1024x768) @ 75Hz"                            
+#define kTV1ResolutionDescription720p2398            "720p HD (1280x720) @ 23.98Hz"                    
+#define kTV1ResolutionDescription720p24                "720p HD (1280x720) @ 24Hz"                        
+#define kTV1ResolutionDescription720p25                "720p HD (1280x720) @ 25Hz"                        
+#define kTV1ResolutionDescription720p2997            "720p HD (1280x720) @ 29.97Hz"                    
+#define kTV1ResolutionDescription720p30                "720p HD (1280x720) @ 30Hz"                        
+#define kTV1ResolutionDescription720p50                "720p HD (1280x720) @ 50Hz"                        
+#define kTV1ResolutionDescription720p5994            "720p HD (1280x720) @ 59.95Hz"                     
+#define kTV1ResolutionDescription720p60                "720p HD (1280x720) @ 60Hz"                        
+#define kTV1ResolutionDescriptionWXGA5by3p60        "WXGA (1280x768) @ 60Hz"                        
+#define kTV1ResolutionDescriptionWXGA5by3p75        "WXGA (1280x768) @ 75Hz"                        
+#define kTV1ResolutionDescriptionWXGA16by10p60        "WXGA (1280x800) @ 60Hz"                        
+#define kTV1ResolutionDescriptionWXGA16by10p75        "WXGA (1280x800) @ 75Hz"        
+#define kTV1ResolutionDescriptionSGAp60                "SGA (1280x1024) @ 60Hz"                         
+#define kTV1ResolutionDescriptionSGAp75                "SGA (1280x1024) @ 75Hz"         
+#define kTV1ResolutionDescriptionWSXGAp60            "WSXGA (1440x900) @ 60Hz"
+#define kTV1ResolutionDescriptionUXGAp60            "UXGA (1600x1200) @ 60Hz"                         
+#define kTV1ResolutionDescriptionUXGAp75            "UXGA (1600x1200) @ 75Hz"                         
+#define kTV1ResolutionDescriptionUXGAp85            "UXGA (1600x1200) @ 85Hz"
+#define kTV1ResolutionDescriptionWSXGAPLUSp60     "WSXGA+ (1680x1050) @ 60Hz"
+#define kTV1ResolutionDescription1080p2398        "1080p (1920x1080) @ 23.98Hz"                     
+#define kTV1ResolutionDescription1080p24            "1080p (1920x1080) @ 24Hz"                        
+#define kTV1ResolutionDescription1080p25            "1080p (1920x1080) @ 25Hz"                        
+#define kTV1ResolutionDescription1080p2997        "1080p (1920x1080) @ 29.97Hz"                    
+#define kTV1ResolutionDescription1080p30            "1080p (1920x1080) @ 30Hz"                        
+#define kTV1ResolutionDescription1080p50            "1080p (1920x1080) @ 50Hz"                        
+#define kTV1ResolutionDescription1080p5996        "1080p (1920x1080) @ 59.94Hz"
+#define kTV1ResolutionDescription1080p60            "1080p (1920x1080) @ 60Hz"                        
+#define kTV1ResolutionDescription1080p75      "1080p (1920x1080) @ 75Hz"    
+#define kTV1ResolutionDescriptionWUXGAp60            "WUXGA (1920x1200) @ 60Hz"                        
+#define kTV1ResolutionDescriptionWUXGAp75            "WUXGA (1920x1200) @ 75Hz"                        
+#define kTV1ResolutionDescriptionWUXGAp85            "WUXGA (1920x1200) @ 85Hz"    
+
+#define kTV1Resolution2Kp60                0x71        
+#define kTV1ResolutionDescription2Kp60                "2K (2048x1080) @ 60Hz"    
+#define kTV1ResolutionDoubleWXGA            0x73        
+#define kTV1ResolutionDescriptionDoubleWXGA            "DWXGA (2880x900) @ 60Hz"                                        
+
+// Triplehead resolutions
+// Note these are currently either added to the resolution list (#123-125) via CorioTools
+// Previously these were written over existing resolutions (#112-114)
+
+#define kTV1ResolutionDualHeadSVGAp60        0x7B        
+#define kTV1ResolutionDescriptionDualHeadSVGAp60    "Dual Head SVGA (1600x600) @ 60Hz"        
+
+#define kTV1ResolutionDualHeadXGAp60    0x7C
+#define kTV1ResolutionDescriptionDualHeadXGAp60   "Dual Head XGA (2048x768) @ 60 Hz"
+
+#define kTV1ResolutionTripleHeadVGAp60        0x7D        
+#define kTV1ResolutionDescriptionTripleHeadVGAp60    "Triple Head VGA (1920x480) @ 60Hz"    
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spk_tvone_mbed.cpp	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,184 @@
+// THIS IS AS PER spk_dvimxr_v07 AND IS OUT OF DATE, NEEDS APHEX TWIN FIXES
+
+// *spark audio-visual
+// RS232 Control for TV-One products
+// Good for 1T-C2-750, others will need some extra work
+// Copyright *spark audio-visual 2009-2010
+
+#include "spk_tvone_mbed.h"
+#include "mbed.h"
+
+SPKTVOne::SPKTVOne(PinName txPin, PinName rxPin, PinName signWritePin, PinName signErrorPin, Serial *debugSerial)
+{
+    // Create Serial connection for TVOne unit comms
+    // Creating our own as this is exclusively for TVOne comms
+    serial = new Serial(txPin, rxPin);
+    serial->baud(57600);
+    
+    if (signWritePin != NC) writeDO = new DigitalOut(signWritePin);
+    else writeDO = NULL;
+    
+    if (signErrorPin != NC) errorDO = new DigitalOut(signErrorPin);
+    else errorDO = NULL;
+    
+    // Link up debug Serial object
+    // Passing in shared object as debugging is shared between all DVI mixer functions
+    debug = debugSerial;
+}
+
+bool SPKTVOne::command(uint8_t channel, uint8_t window, int32_t func, int32_t payload) 
+{
+  char i;
+  
+  // TASK: Sign start of serial command write
+  if (writeDO) *writeDO = 1;
+  
+  // TASK: discard anything waiting to be read
+  while (serial->readable()) {
+    serial->getc();
+  }
+  
+  // TASK: Create the bytes of command
+
+  uint8_t cmd[8];
+  uint8_t checksum = 0;
+
+  // CMD
+  cmd[0] = 1<<2; // write
+  // CHA
+  cmd[1] = channel;
+  // WINDOW
+  cmd[2] = window;
+  // OUTPUT & FUNCTION
+  //            cmd[3]  cmd[4]
+  // output 0 = 0000xxx xxxxxxx
+  // function = xxxXXXX XXXXXXX
+  cmd[3] = func >> 8;
+  cmd[4] = func & 0xFF;
+  // PAYLOAD
+  cmd[5] = (payload >> 16) & 0xFF;
+  cmd[6] = (payload >> 8) & 0xFF;
+  cmd[7] = payload & 0xFF;
+
+  // TASK: Write the bytes of command to RS232 as correctly packaged 20 characters of ASCII
+
+  for (i=0; i<8; i++) 
+  {
+    checksum += cmd[i];
+  }
+  
+  serial->printf("F%02X%02X%02X%02X%02X%02X%02X%02X%02X\r", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], checksum);
+  
+  // TASK: Check the unit's return string, to enable return to main program as soon as unit is ready
+
+  // Handling the timing of this return is critical to effective control.
+  // Returning the instant something is received back overloads the processor, as does anything until the full 20 char acknowledgement.
+  // TVOne turn out to say that receipt of the ack doesn't guarantee the unit is ready for the next command. 
+  // According to the manual, operations typically take 30ms, and to simplify programming you can throttle commands to every 100ms.
+  // 100ms is too slow for us. Going with returning after 30ms if we've received an acknowledgement, returning after 100ms otherwise.
+
+  int ack[20];
+  int safePeriod = 100;
+  int clearPeriod = 30;
+  bool ackReceived = false;
+  bool success = false;
+  Timer timer;
+
+  timer.start();
+  i = 0;
+  while (timer.read_ms() < safePeriod) {
+    if (serial->readable())
+        {
+            ack[i] = serial->getc();
+            i++;
+            if (i >= 20) 
+            {
+                ackReceived = true;
+                if (ack[0] == 'F' && ack[1] == '4') // TVOne start of message, acknowledgement with no error, rest will be repeat of sent command
+                {
+                    success = true;
+                }
+            }
+        }
+    if (ackReceived && (timer.read_ms() > clearPeriod)) break;
+  }
+  timer.stop();
+  
+  // TASK: Sign end of write
+  
+  if (writeDO) *writeDO = 0;
+  
+  if (!success) {
+        if (errorDO) {
+            signErrorTimeout.detach();
+            signErrorTimeout.attach(this, &SPKTVOne::signErrorOff, 0.25);
+            *errorDO = 1;
+        }
+        
+        if (debug) {
+            debug->printf("Serial command write error. Time from write finish: %ims \r\n", timer.read_ms());
+        }
+  };
+
+  return success;
+}
+
+void SPKTVOne::setCustomResolutions() 
+{
+  set1920x480(kTV1ResolutionTripleHeadVGAp60);
+  set1600x600(kTV1ResolutionDualHeadSVGAp60);
+}
+
+bool SPKTVOne::setHDCPOff() 
+{
+  bool ok = false;
+
+  // Turn HDCP off on the output
+  ok =       command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsHDCPRequired, 0);
+  ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsHDCPStatus, 0);
+  // Likewise on inputs A and B
+  ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPAdvertize, 0);
+  ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPAdvertize, 0);
+  ok = ok && command(0, kTV1WindowIDB, kTV1FunctionAdjustSourceHDCPStatus, 0);
+  ok = ok && command(0, kTV1WindowIDB, kTV1FunctionAdjustSourceHDCPStatus, 0);
+  
+  return ok;
+}
+
+void SPKTVOne::set1920x480(int resStoreNumber) 
+{
+  command(0, 0, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
+  command(0, 0, kTV1FunctionAdjustResolutionInterlaced, 0);
+  command(0, 0, kTV1FunctionAdjustResolutionFreqCoarseH, 31400);
+  command(0, 0, kTV1FunctionAdjustResolutionFreqFineH, 31475);
+  command(0, 0, kTV1FunctionAdjustResolutionActiveH, 1920);
+  command(0, 0, kTV1FunctionAdjustResolutionActiveV, 480);
+  command(0, 0, kTV1FunctionAdjustResolutionStartH, 192); 
+  command(0, 0, kTV1FunctionAdjustResolutionStartV, 32); 
+  command(0, 0, kTV1FunctionAdjustResolutionCLKS, 2400); 
+  command(0, 0, kTV1FunctionAdjustResolutionLines, 525);
+  command(0, 0, kTV1FunctionAdjustResolutionSyncH, 240);
+  command(0, 0, kTV1FunctionAdjustResolutionSyncV, 5); 
+  command(0, 0, kTV1FunctionAdjustResolutionSyncPolarity, 0);
+}
+
+void SPKTVOne::set1600x600(int resStoreNumber) 
+{
+  command(0, 0, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
+  command(0, 0, kTV1FunctionAdjustResolutionInterlaced, 0);
+  command(0, 0, kTV1FunctionAdjustResolutionFreqCoarseH, 37879);
+  command(0, 0, kTV1FunctionAdjustResolutionFreqFineH, 37879);
+  command(0, 0, kTV1FunctionAdjustResolutionActiveH, 1600);
+  command(0, 0, kTV1FunctionAdjustResolutionActiveV, 600);
+  command(0, 0, kTV1FunctionAdjustResolutionStartH, 160); 
+  command(0, 0, kTV1FunctionAdjustResolutionStartV, 1); 
+  command(0, 0, kTV1FunctionAdjustResolutionCLKS, 2112); 
+  command(0, 0, kTV1FunctionAdjustResolutionLines, 628);
+  command(0, 0, kTV1FunctionAdjustResolutionSyncH, 192);
+  command(0, 0, kTV1FunctionAdjustResolutionSyncV, 14); 
+  command(0, 0, kTV1FunctionAdjustResolutionSyncPolarity, 0);
+}
+
+void SPKTVOne::signErrorOff() {
+    *errorDO = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spk_tvone_mbed.h	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,36 @@
+// *spark audio-visual
+// RS232 Control for TV-One products
+// Good for 1T-C2-750, others will need some extra work
+// Copyright *spark audio-visual 2009-2011
+
+#ifndef SPKTVOne_mBed_h
+#define SPKTVOne_mBed_h
+
+#include "spk_tvone.h"
+#include "mbed.h"
+
+class SPKTVOne
+{
+  public:
+    SPKTVOne(PinName txPin, PinName rxPin, PinName signWritePin = NC, PinName signErrorPin = NC, Serial *debugSerial = NULL);
+    
+    bool command(uint8_t channel, uint8_t window, int32_t func, int32_t payload);
+    
+    void setCustomResolutions();
+    bool setHDCPOff();
+     
+  private:
+    // Tx and Wait LED pins to go here
+    void set1920x480(int resStoreNumber);
+    void set1600x600(int resStoreNumber);
+    
+    Serial *serial;
+    Serial *debug; 
+    
+    DigitalOut *writeDO;
+    DigitalOut *errorDO;
+    Timeout signErrorTimeout;
+    void signErrorOff();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spk_utils.h	Sat Mar 10 19:26:44 2012 +0000
@@ -0,0 +1,192 @@
+#include <string>
+#include <vector>
+
+class SPKIndexInRange {
+public:
+    void operator = (int newIndex) {
+        set(newIndex);
+    }
+    
+    void operator ++ (int) {
+        if (idx == max) idx = wrap ? min : max;
+        else idx++;
+    }
+    
+    void operator -- (int) {
+        if (idx == min) idx = wrap ? max : min;
+        else idx--;
+    }
+    
+    void set (int newIndex) {
+        if (newIndex > max) idx = max;
+        else if (newIndex < min) idx = min;
+        else idx = newIndex;
+    }
+    
+    void set (int newMin, int newMax, int newIndex = 0, bool newWrap = false) {
+        min = newMin;
+        max = newMax;
+        wrap = newWrap;
+        set(newIndex);
+    }
+    
+    void setMax(int newMax) {
+        max = newMax;
+    }
+    
+    SPKIndexInRange () {
+        min = 0;
+        max = 1;
+        wrap = true;
+        idx = 0;
+    }
+    
+    SPKIndexInRange (int newMin, int newMax, int newIndex = 0, bool newWrap = false) {
+        set(newMin, newMax, newIndex, newWrap);
+    }
+    
+    int index() {
+        return idx;
+    }
+    
+private:
+    int idx;
+    int min, max;
+    bool wrap;
+};
+
+enum SPKMenuType { menuOfMenus, payload };
+
+class SPKMenu {
+public:
+    SPKMenu() {
+        selected.set(0, 0, 0, true);
+    }
+    
+    virtual SPKMenuType type(void) = 0;
+    
+    std::string title;
+    
+    void operator = (int newIndex) {
+        selected = newIndex;
+    }
+    
+    void operator ++ () {
+        selected++;
+    }
+    
+    void operator -- () {
+        selected--;
+    }
+    
+    void addMenuItem (std::string menuText) {
+        text.push_back(menuText);
+        selected.setMax(text.size()-1);
+    }
+    
+    int selectedIndex() {
+        return selected.index();
+    }
+    
+    std::string  selectedString() {
+        return text[selected.index()];
+    }
+        
+protected:
+    SPKIndexInRange selected;
+    std::vector<std::string> text;
+};
+
+class SPKMenuOfMenus: public SPKMenu {
+public:
+    SPKMenuOfMenus() : SPKMenu() {}
+    
+    virtual SPKMenuType type() {
+        return menuOfMenus;
+    }
+    
+    void addMenuItem(SPKMenu* menu) {
+        SPKMenu::addMenuItem(menu->title);
+        payload.push_back(menu);
+    }
+    
+    SPKMenu* selectedMenu() {
+        return payload[selected.index()];
+    }
+        
+private:
+    vector<SPKMenu*> payload;
+};
+
+class SPKMenuPayload: public SPKMenu {
+public:
+    SPKMenuPayload() : SPKMenu() {
+        text.push_back("Cancel");
+        payload1.push_back(0);
+        payload2.push_back(0);
+    }
+    
+    virtual SPKMenuType type() {
+        return payload;
+    }
+    
+    void addMenuItem(std::string menuText, int32_t menuPayload1, int32_t menuPayload2) {
+        SPKMenu::addMenuItem(menuText);
+        payload1.push_back(menuPayload1);
+        payload2.push_back(menuPayload2);
+    }
+    
+    int32_t selectedPayload1() {
+        return payload1[selected.index()];
+    }
+    
+    int32_t selectedPayload2() {
+        return payload2[selected.index()];
+    }
+        
+private:
+    vector<int32_t> payload1;
+    vector<int32_t> payload2;
+};
+
+class SPKSign {
+public:
+    SPKSign(PinName signWrite, PinName signError) {
+        writeDO = new DigitalOut(signWrite);
+        errorDO = new DigitalOut(signError);
+    }
+    
+    ~SPKSign() {
+        delete writeDO;
+        delete errorDO;
+    }
+    
+    void serialWrite() {
+        signWriteTimeout.detach();
+        signWriteTimeout.attach(this, &SPKSign::writeOff, 0.25);
+        *writeDO = 1;
+    }
+    
+    void serialError() {
+        signErrorTimeout.detach();
+        signErrorTimeout.attach(this, &SPKSign::errorOff, 0.25);
+        *errorDO = 1;   
+    }
+
+private:
+    void writeOff() {
+        *writeDO = 0;
+    }
+    
+    void errorOff() {
+        *errorDO = 0;
+    }
+    
+    DigitalOut *writeDO;
+    DigitalOut *errorDO;
+    Timeout signWriteTimeout;
+    Timeout signErrorTimeout;
+};
+
+
+