Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: SPK-TVOne DMX DmxArtNet NetServicesMin OSC PinDetect mRotaryEncoder iniparser mbed spk_oled_ssd1305 filter
Revision 0:87aab40d5806, committed 2012-03-10
- 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
--- /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;
+};
+
+
+