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
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; +}; + + +