RS232 control for TVOne products

Dependents:   SPK-DVIMXR

Committer:
tobyspark
Date:
Thu Oct 17 15:49:16 2013 +0000
Revision:
24:4eec37b8387e
Parent:
23:46f42462a183
Resolution Timings - bug fixes; Matrox - support for digital and analogue edition timings of 2048x768

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tobyspark 0:533cfae24a1b 1 // *spark audio-visual
tobyspark 0:533cfae24a1b 2 // RS232 Control for TV-One products
tobyspark 0:533cfae24a1b 3 // Good for 1T-C2-750, others will need some extra work
tobyspark 1:349d6da461df 4
tobyspark 1:349d6da461df 5 /* Copyright (c) 2011 Toby Harris, MIT License
tobyspark 1:349d6da461df 6 *
tobyspark 1:349d6da461df 7 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
tobyspark 1:349d6da461df 8 * and associated documentation files (the "Software"), to deal in the Software without restriction,
tobyspark 1:349d6da461df 9 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
tobyspark 1:349d6da461df 10 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
tobyspark 1:349d6da461df 11 * furnished to do so, subject to the following conditions:
tobyspark 1:349d6da461df 12 *
tobyspark 1:349d6da461df 13 * The above copyright notice and this permission notice shall be included in all copies or
tobyspark 1:349d6da461df 14 * substantial portions of the Software.
tobyspark 1:349d6da461df 15 *
tobyspark 1:349d6da461df 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
tobyspark 1:349d6da461df 17 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
tobyspark 1:349d6da461df 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
tobyspark 1:349d6da461df 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
tobyspark 1:349d6da461df 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
tobyspark 1:349d6da461df 21 */
tobyspark 0:533cfae24a1b 22
tobyspark 0:533cfae24a1b 23 #include "spk_tvone_mbed.h"
tobyspark 0:533cfae24a1b 24 #include "mbed.h"
tobyspark 0:533cfae24a1b 25
tobyspark 0:533cfae24a1b 26 SPKTVOne::SPKTVOne(PinName txPin, PinName rxPin, PinName signWritePin, PinName signErrorPin, Serial *debugSerial)
tobyspark 0:533cfae24a1b 27 {
tobyspark 0:533cfae24a1b 28 // Create Serial connection for TVOne unit comms
tobyspark 0:533cfae24a1b 29 // Creating our own as this is exclusively for TVOne comms
tobyspark 9:42c83cac2f6d 30 serial = new Serial(txPin, rxPin);
tobyspark 0:533cfae24a1b 31 serial->baud(57600);
tobyspark 0:533cfae24a1b 32
tobyspark 0:533cfae24a1b 33 if (signWritePin != NC) writeDO = new DigitalOut(signWritePin);
tobyspark 0:533cfae24a1b 34 else writeDO = NULL;
tobyspark 0:533cfae24a1b 35
tobyspark 0:533cfae24a1b 36 if (signErrorPin != NC) errorDO = new DigitalOut(signErrorPin);
tobyspark 0:533cfae24a1b 37 else errorDO = NULL;
tobyspark 0:533cfae24a1b 38
tobyspark 18:d765b0d9271c 39 processor.version = -1;
tobyspark 18:d765b0d9271c 40 processor.productType = -1;
tobyspark 18:d765b0d9271c 41 processor.boardType = -1;
tobyspark 18:d765b0d9271c 42
tobyspark 18:d765b0d9271c 43 resetCommandPeriods();
tobyspark 14:da403a01f9ef 44
tobyspark 14:da403a01f9ef 45 timer.start();
tobyspark 17:68b9bb89da2b 46 timerCheckTicker.attach(this, &SPKTVOne::timerCheck, 60);
tobyspark 14:da403a01f9ef 47
tobyspark 0:533cfae24a1b 48 // Link up debug Serial object
tobyspark 0:533cfae24a1b 49 // Passing in shared object as debugging is shared between all DVI mixer functions
tobyspark 0:533cfae24a1b 50 debug = debugSerial;
tobyspark 0:533cfae24a1b 51 }
tobyspark 0:533cfae24a1b 52
tobyspark 10:5f398fc9b5c1 53 bool SPKTVOne::command(uint8_t channel, uint8_t window, int32_t func, int32_t payload)
tobyspark 10:5f398fc9b5c1 54 {
tobyspark 14:da403a01f9ef 55 int ackBuff[standardAckLength] = {0};
tobyspark 10:5f398fc9b5c1 56
tobyspark 11:90e5a72a0034 57 bool success = command(writeCommandType, ackBuff, standardAckLength, channel, window, func, payload);
tobyspark 11:90e5a72a0034 58
tobyspark 11:90e5a72a0034 59 // TASK: Check return payload is what we tried to set it to
tobyspark 11:90e5a72a0034 60 char payloadStr[7];
tobyspark 11:90e5a72a0034 61 for (int i = 0; i < 6; i++)
tobyspark 11:90e5a72a0034 62 {
tobyspark 11:90e5a72a0034 63 payloadStr[i] = ackBuff[11+i];
tobyspark 11:90e5a72a0034 64 }
tobyspark 11:90e5a72a0034 65 payloadStr[6] = NULL;
tobyspark 11:90e5a72a0034 66
tobyspark 11:90e5a72a0034 67 int payloadBack = strtol (payloadStr, NULL, 16);
tobyspark 11:90e5a72a0034 68
tobyspark 11:90e5a72a0034 69 if (payload != payloadBack)
tobyspark 11:90e5a72a0034 70 {
tobyspark 11:90e5a72a0034 71 success = false;
tobyspark 13:4d659b89a457 72 if (debug) debug->printf("TVOne return value (%d) is not what was set (%d). Channel: %#x, Window: %#x, Function: %#x \r\n", payloadBack, payload, channel, window, func);
tobyspark 11:90e5a72a0034 73 }
tobyspark 11:90e5a72a0034 74 return success;
tobyspark 11:90e5a72a0034 75 }
tobyspark 11:90e5a72a0034 76
tobyspark 11:90e5a72a0034 77 bool SPKTVOne::readCommand(uint8_t channel, uint8_t window, int32_t func, int32_t &payload)
tobyspark 11:90e5a72a0034 78 {
tobyspark 14:da403a01f9ef 79 int ackBuff[standardAckLength] = {0};
tobyspark 11:90e5a72a0034 80
tobyspark 11:90e5a72a0034 81 bool success = command(readCommandType, ackBuff, standardAckLength, channel, window, func, payload);
tobyspark 11:90e5a72a0034 82
tobyspark 19:350d1191e466 83 if (success)
tobyspark 19:350d1191e466 84 {
tobyspark 19:350d1191e466 85 char payloadStr[7];
tobyspark 19:350d1191e466 86 for (int i = 0; i < 6; i++)
tobyspark 19:350d1191e466 87 {
tobyspark 19:350d1191e466 88 payloadStr[i] = ackBuff[11+i];
tobyspark 19:350d1191e466 89 }
tobyspark 19:350d1191e466 90 payloadStr[6] = NULL;
tobyspark 19:350d1191e466 91
tobyspark 19:350d1191e466 92 payload = strtol (payloadStr, NULL, 16);
tobyspark 11:90e5a72a0034 93 }
tobyspark 10:5f398fc9b5c1 94
tobyspark 10:5f398fc9b5c1 95 return success;
tobyspark 10:5f398fc9b5c1 96 }
tobyspark 10:5f398fc9b5c1 97
tobyspark 10:5f398fc9b5c1 98 bool SPKTVOne::command(commandType readWrite, int* ackBuffer, int ackLength, uint8_t channel, uint8_t window, int32_t func, int32_t payload)
tobyspark 14:da403a01f9ef 99 {
tobyspark 14:da403a01f9ef 100 if (debug) debug->printf("TVOne %s Channel: %#x, Window: %#x, Function: %#x Payload: %i \r\n", (readWrite == writeCommandType) ? "Write" : "Read", channel, window, func, payload);
tobyspark 14:da403a01f9ef 101
tobyspark 0:533cfae24a1b 102 // TASK: Sign start of serial command write
tobyspark 0:533cfae24a1b 103 if (writeDO) *writeDO = 1;
tobyspark 0:533cfae24a1b 104
tobyspark 14:da403a01f9ef 105 // TASK: Prepare to issue command to the TVOne unit
tobyspark 14:da403a01f9ef 106 // - discard anything waiting to be read in the return serial buffer
tobyspark 14:da403a01f9ef 107 // - make sure we're past the minimum time between command sends as the unit can get overloaded
tobyspark 18:d765b0d9271c 108 while (serial->readable() || timer.read_ms() < commandMinimumPeriod) {
tobyspark 14:da403a01f9ef 109 if (serial->readable()) serial->getc();
tobyspark 0:533cfae24a1b 110 }
tobyspark 0:533cfae24a1b 111
tobyspark 0:533cfae24a1b 112 // TASK: Create the bytes of command
tobyspark 0:533cfae24a1b 113
tobyspark 0:533cfae24a1b 114 uint8_t cmd[8];
tobyspark 0:533cfae24a1b 115 uint8_t checksum = 0;
tobyspark 0:533cfae24a1b 116
tobyspark 0:533cfae24a1b 117 // CMD
tobyspark 10:5f398fc9b5c1 118 cmd[0] = readWrite<<7 | 1<<2;
tobyspark 0:533cfae24a1b 119 // CHA
tobyspark 0:533cfae24a1b 120 cmd[1] = channel;
tobyspark 0:533cfae24a1b 121 // WINDOW
tobyspark 0:533cfae24a1b 122 cmd[2] = window;
tobyspark 0:533cfae24a1b 123 // OUTPUT & FUNCTION
tobyspark 0:533cfae24a1b 124 // cmd[3] cmd[4]
tobyspark 0:533cfae24a1b 125 // output 0 = 0000xxx xxxxxxx
tobyspark 0:533cfae24a1b 126 // function = xxxXXXX XXXXXXX
tobyspark 0:533cfae24a1b 127 cmd[3] = func >> 8;
tobyspark 0:533cfae24a1b 128 cmd[4] = func & 0xFF;
tobyspark 0:533cfae24a1b 129 // PAYLOAD
tobyspark 0:533cfae24a1b 130 cmd[5] = (payload >> 16) & 0xFF;
tobyspark 0:533cfae24a1b 131 cmd[6] = (payload >> 8) & 0xFF;
tobyspark 0:533cfae24a1b 132 cmd[7] = payload & 0xFF;
tobyspark 0:533cfae24a1b 133
tobyspark 0:533cfae24a1b 134 // TASK: Write the bytes of command to RS232 as correctly packaged 20 characters of ASCII
tobyspark 10:5f398fc9b5c1 135
tobyspark 11:90e5a72a0034 136 if (readWrite == writeCommandType)
tobyspark 0:533cfae24a1b 137 {
tobyspark 14:da403a01f9ef 138 for (int i=0; i<8; i++) checksum += cmd[i];
tobyspark 10:5f398fc9b5c1 139 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);
tobyspark 0:533cfae24a1b 140 }
tobyspark 11:90e5a72a0034 141 if (readWrite == readCommandType)
tobyspark 10:5f398fc9b5c1 142 {
tobyspark 14:da403a01f9ef 143 for (int i=0; i<5; i++) checksum += cmd[i];
tobyspark 10:5f398fc9b5c1 144 serial->printf("F%02X%02X%02X%02X%02X%02X\r", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], checksum);
tobyspark 10:5f398fc9b5c1 145 }
tobyspark 10:5f398fc9b5c1 146
tobyspark 0:533cfae24a1b 147 // TASK: Check the unit's return string, to enable return to main program as soon as unit is ready
tobyspark 0:533cfae24a1b 148
tobyspark 0:533cfae24a1b 149 // Handling the timing of this return is critical to effective control.
tobyspark 0:533cfae24a1b 150 // Returning the instant something is received back overloads the processor, as does anything until the full 20 char acknowledgement.
tobyspark 0:533cfae24a1b 151 // TVOne turn out to say that receipt of the ack doesn't guarantee the unit is ready for the next command.
tobyspark 0:533cfae24a1b 152 // According to the manual, operations typically take 30ms, and to simplify programming you can throttle commands to every 100ms.
tobyspark 0:533cfae24a1b 153 // 100ms is too slow for us. Going with returning after 30ms if we've received an acknowledgement, returning after 100ms otherwise.
tobyspark 10:5f398fc9b5c1 154
tobyspark 14:da403a01f9ef 155 bool success = false;
tobyspark 14:da403a01f9ef 156 int ackPos = 0;
tobyspark 14:da403a01f9ef 157 timer.reset();
tobyspark 0:533cfae24a1b 158
tobyspark 18:d765b0d9271c 159 while (timer.read_ms() < commandTimeoutPeriod)
tobyspark 10:5f398fc9b5c1 160 {
tobyspark 14:da403a01f9ef 161 if (serial->readable())
tobyspark 10:5f398fc9b5c1 162 {
tobyspark 14:da403a01f9ef 163 if (ackPos == 0)
tobyspark 9:42c83cac2f6d 164 {
tobyspark 14:da403a01f9ef 165 ackBuffer[0] = serial->getc();
tobyspark 14:da403a01f9ef 166 if (ackBuffer[0] == 'F') ackPos = 1;
tobyspark 14:da403a01f9ef 167 }
tobyspark 14:da403a01f9ef 168 else
tobyspark 14:da403a01f9ef 169 {
tobyspark 14:da403a01f9ef 170 ackBuffer[ackPos] = serial->getc();
tobyspark 14:da403a01f9ef 171 ackPos++;
tobyspark 14:da403a01f9ef 172 if (ackPos == ackLength) break;
tobyspark 0:533cfae24a1b 173 }
tobyspark 10:5f398fc9b5c1 174 }
tobyspark 9:42c83cac2f6d 175 }
tobyspark 20:ebddf3ddb1f6 176
tobyspark 14:da403a01f9ef 177 // Return true if we got the no error acknowledgement from the unit. The rest of the ack will be verified elsewhere if needed.
tobyspark 19:350d1191e466 178 if (ackPos == ackLength && ackBuffer[1] == '4')
tobyspark 14:da403a01f9ef 179 {
tobyspark 14:da403a01f9ef 180 success = true;
tobyspark 14:da403a01f9ef 181 }
tobyspark 0:533cfae24a1b 182
tobyspark 0:533cfae24a1b 183 // TASK: Sign end of write
tobyspark 0:533cfae24a1b 184
tobyspark 0:533cfae24a1b 185 if (writeDO) *writeDO = 0;
tobyspark 0:533cfae24a1b 186
tobyspark 0:533cfae24a1b 187 if (!success) {
tobyspark 0:533cfae24a1b 188 if (errorDO) {
tobyspark 0:533cfae24a1b 189 signErrorTimeout.detach();
tobyspark 0:533cfae24a1b 190 signErrorTimeout.attach(this, &SPKTVOne::signErrorOff, 0.25);
tobyspark 0:533cfae24a1b 191 *errorDO = 1;
tobyspark 0:533cfae24a1b 192 }
tobyspark 0:533cfae24a1b 193
tobyspark 0:533cfae24a1b 194 if (debug) {
tobyspark 14:da403a01f9ef 195 debug->printf("TVOne serial error. Time from finishing writing command: %ims. Received %i ack chars:", timer.read_ms(), ackPos);
tobyspark 14:da403a01f9ef 196 for (int i = 0; i<ackLength; i++)
tobyspark 14:da403a01f9ef 197 {
tobyspark 14:da403a01f9ef 198 debug->printf("%c", ackBuffer[i]);
tobyspark 14:da403a01f9ef 199 }
tobyspark 14:da403a01f9ef 200 debug->printf("\r\n");
tobyspark 0:533cfae24a1b 201 }
tobyspark 0:533cfae24a1b 202 };
tobyspark 0:533cfae24a1b 203
tobyspark 0:533cfae24a1b 204 return success;
tobyspark 0:533cfae24a1b 205 }
tobyspark 0:533cfae24a1b 206
tobyspark 18:d765b0d9271c 207 void SPKTVOne::setCommandTimeoutPeriod(int millis)
tobyspark 18:d765b0d9271c 208 {
tobyspark 18:d765b0d9271c 209 commandTimeoutPeriod = millis;
tobyspark 18:d765b0d9271c 210 }
tobyspark 18:d765b0d9271c 211
tobyspark 18:d765b0d9271c 212 void SPKTVOne::setCommandMinimumPeriod(int millis)
tobyspark 18:d765b0d9271c 213 {
tobyspark 18:d765b0d9271c 214 commandMinimumPeriod = millis;
tobyspark 18:d765b0d9271c 215 }
tobyspark 18:d765b0d9271c 216
tobyspark 18:d765b0d9271c 217 void SPKTVOne::increaseCommandPeriods(int millis)
tobyspark 18:d765b0d9271c 218 {
tobyspark 18:d765b0d9271c 219 commandTimeoutPeriod += millis;
tobyspark 18:d765b0d9271c 220 commandMinimumPeriod += millis;
tobyspark 18:d765b0d9271c 221
tobyspark 18:d765b0d9271c 222 if (debug) debug->printf("Command periods increased; minimum: %i, timeout: %i", commandMinimumPeriod, commandTimeoutPeriod);
tobyspark 18:d765b0d9271c 223 }
tobyspark 18:d765b0d9271c 224
tobyspark 18:d765b0d9271c 225 void SPKTVOne::resetCommandPeriods()
tobyspark 18:d765b0d9271c 226 {
tobyspark 18:d765b0d9271c 227 commandTimeoutPeriod = kTV1CommandTimeoutMillis;
tobyspark 18:d765b0d9271c 228 commandMinimumPeriod = kTV1CommandMinimumMillis;
tobyspark 18:d765b0d9271c 229 }
tobyspark 18:d765b0d9271c 230
tobyspark 20:ebddf3ddb1f6 231 int SPKTVOne::getCommandTimeoutPeriod()
tobyspark 20:ebddf3ddb1f6 232 {
tobyspark 20:ebddf3ddb1f6 233 return commandTimeoutPeriod;
tobyspark 20:ebddf3ddb1f6 234 }
tobyspark 20:ebddf3ddb1f6 235
tobyspark 20:ebddf3ddb1f6 236 int SPKTVOne::millisSinceLastCommandSent()
tobyspark 14:da403a01f9ef 237 {
tobyspark 14:da403a01f9ef 238 return timer.read_ms();
tobyspark 14:da403a01f9ef 239 }
tobyspark 14:da403a01f9ef 240
tobyspark 24:4eec37b8387e 241 bool SPKTVOne::setMatroxResolutions(bool digitalEdition)
tobyspark 0:533cfae24a1b 242 {
tobyspark 24:4eec37b8387e 243 bool lock = true;
tobyspark 24:4eec37b8387e 244 bool ok = true;
tobyspark 11:90e5a72a0034 245 int unlocked = 0;
tobyspark 11:90e5a72a0034 246 int locked = 1;
tobyspark 11:90e5a72a0034 247
tobyspark 24:4eec37b8387e 248 lock = lock && command(0, kTV1WindowIDA, kTV1FunctionAdjustFrontPanelLock, locked);
tobyspark 11:90e5a72a0034 249
tobyspark 24:4eec37b8387e 250 // TODO: Any other resolutions that have different timings between analogue and digital editions of the matrox boxes.
tobyspark 24:4eec37b8387e 251 // ok = ok && set1920x480(kTV1ResolutionTripleHeadVGAp60);
tobyspark 24:4eec37b8387e 252 // ok = ok && set1600x600(kTV1ResolutionDualHeadSVGAp60);
tobyspark 24:4eec37b8387e 253 ok = ok && set2048x768(kTV1ResolutionDualHeadXGAp60, digitalEdition);
tobyspark 11:90e5a72a0034 254
tobyspark 24:4eec37b8387e 255 lock = lock && command(0, kTV1WindowIDA, kTV1FunctionAdjustFrontPanelLock, unlocked);
tobyspark 11:90e5a72a0034 256
tobyspark 11:90e5a72a0034 257 return ok;
tobyspark 0:533cfae24a1b 258 }
tobyspark 0:533cfae24a1b 259
tobyspark 21:2260dde18dfa 260 int SPKTVOne::getEDID()
tobyspark 21:2260dde18dfa 261 {
tobyspark 21:2260dde18dfa 262 bool ok = true;
tobyspark 21:2260dde18dfa 263
tobyspark 21:2260dde18dfa 264 int32_t payload1 = -1;
tobyspark 21:2260dde18dfa 265 ok = ok && readCommand(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, payload1);
tobyspark 21:2260dde18dfa 266
tobyspark 21:2260dde18dfa 267 int32_t payload2 = -1;
tobyspark 21:2260dde18dfa 268 ok = ok && readCommand(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, payload2);
tobyspark 21:2260dde18dfa 269
tobyspark 21:2260dde18dfa 270 int EDID = (payload1 == payload2) ? payload1 : -1;
tobyspark 21:2260dde18dfa 271
tobyspark 21:2260dde18dfa 272 return ok ? EDID : -1;
tobyspark 21:2260dde18dfa 273 }
tobyspark 21:2260dde18dfa 274
tobyspark 23:46f42462a183 275 int SPKTVOne::getResolution(int device)
tobyspark 21:2260dde18dfa 276 {
tobyspark 23:46f42462a183 277 bool ok = false;
tobyspark 23:46f42462a183 278 int32_t payload = -1;
tobyspark 21:2260dde18dfa 279
tobyspark 23:46f42462a183 280 if (device == 0)
tobyspark 23:46f42462a183 281 {
tobyspark 23:46f42462a183 282 ok = readCommand(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsOutputResolution, payload);
tobyspark 23:46f42462a183 283 }
tobyspark 23:46f42462a183 284 else if (device == kTV1WindowIDA || device == kTV1WindowIDB)
tobyspark 23:46f42462a183 285 {
tobyspark 23:46f42462a183 286 ok = readCommand(0, device, kTV1FunctionAdjustWindowsSourceResolution, payload);
tobyspark 23:46f42462a183 287 }
tobyspark 21:2260dde18dfa 288
tobyspark 21:2260dde18dfa 289 return ok ? payload : -1;
tobyspark 21:2260dde18dfa 290 }
tobyspark 21:2260dde18dfa 291
tobyspark 18:d765b0d9271c 292 bool SPKTVOne::setResolution(int resolution, int edidSlot)
tobyspark 18:d765b0d9271c 293 {
tobyspark 18:d765b0d9271c 294 bool ok;
tobyspark 18:d765b0d9271c 295
tobyspark 18:d765b0d9271c 296 int minPeriodOnEntry = commandMinimumPeriod;
tobyspark 18:d765b0d9271c 297 int outPeriodOnEntry = commandTimeoutPeriod;
tobyspark 18:d765b0d9271c 298
tobyspark 18:d765b0d9271c 299 for (int i=0; i < 3; i++)
tobyspark 18:d765b0d9271c 300 {
tobyspark 18:d765b0d9271c 301 ok = command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsOutputResolution, resolution);
tobyspark 18:d765b0d9271c 302
tobyspark 18:d765b0d9271c 303 if (ok) break;
tobyspark 18:d765b0d9271c 304 else increaseCommandPeriods(500);
tobyspark 18:d765b0d9271c 305 }
tobyspark 18:d765b0d9271c 306 commandMinimumPeriod = minPeriodOnEntry;
tobyspark 18:d765b0d9271c 307 commandTimeoutPeriod = outPeriodOnEntry;
tobyspark 18:d765b0d9271c 308 if (!ok) return ok;
tobyspark 18:d765b0d9271c 309
tobyspark 18:d765b0d9271c 310 for (int i=0; i < 3; i++)
tobyspark 18:d765b0d9271c 311 {
tobyspark 18:d765b0d9271c 312 ok = command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, edidSlot);
tobyspark 18:d765b0d9271c 313 ok = ok && command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, edidSlot);
tobyspark 18:d765b0d9271c 314
tobyspark 18:d765b0d9271c 315 if (ok) break;
tobyspark 18:d765b0d9271c 316 else increaseCommandPeriods(500);
tobyspark 18:d765b0d9271c 317 }
tobyspark 18:d765b0d9271c 318 commandMinimumPeriod = minPeriodOnEntry;
tobyspark 18:d765b0d9271c 319 commandTimeoutPeriod = outPeriodOnEntry;
tobyspark 18:d765b0d9271c 320
tobyspark 18:d765b0d9271c 321 return ok;
tobyspark 18:d765b0d9271c 322 }
tobyspark 18:d765b0d9271c 323
tobyspark 3:03e7e7b7a870 324 bool SPKTVOne::setHDCPOn(bool state)
tobyspark 0:533cfae24a1b 325 {
tobyspark 18:d765b0d9271c 326 bool ok;
tobyspark 18:d765b0d9271c 327
tobyspark 18:d765b0d9271c 328 int minPeriodOnEntry = commandMinimumPeriod;
tobyspark 18:d765b0d9271c 329 int outPeriodOnEntry = commandTimeoutPeriod;
tobyspark 18:d765b0d9271c 330
tobyspark 18:d765b0d9271c 331 // HDCP can sometimes take a little time to settle down
tobyspark 18:d765b0d9271c 332 for (int i=0; i < 3; i++)
tobyspark 18:d765b0d9271c 333 {
tobyspark 18:d765b0d9271c 334 // Turn HDCP off on the output
tobyspark 18:d765b0d9271c 335 ok = command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsHDCPRequired, state);
tobyspark 18:d765b0d9271c 336
tobyspark 18:d765b0d9271c 337 // Likewise on inputs A and B
tobyspark 18:d765b0d9271c 338 ok = ok && command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPAdvertize, state);
tobyspark 18:d765b0d9271c 339 ok = ok && command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPAdvertize, state);
tobyspark 19:350d1191e466 340
tobyspark 19:350d1191e466 341 // This verify code is accurate but too misleading for D-Fuser use - eg. actual HDCP state requires source / output connection.
tobyspark 19:350d1191e466 342 // // Now verify whats actually going on.
tobyspark 19:350d1191e466 343 // int32_t payload = -1;
tobyspark 19:350d1191e466 344 // ok = ok && readCommand(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsHDCPStatus, payload);
tobyspark 19:350d1191e466 345 // switch (payload)
tobyspark 19:350d1191e466 346 // {
tobyspark 19:350d1191e466 347 // case 0: ok = ok && !state; break;
tobyspark 19:350d1191e466 348 // case 1: ok = ok && !state; break;
tobyspark 19:350d1191e466 349 // case 2: ok = ok && state; break;
tobyspark 19:350d1191e466 350 // case 3: ok = ok && !state; break;
tobyspark 19:350d1191e466 351 // case 4: ok = ok && state; break;
tobyspark 19:350d1191e466 352 // default: ok = false;
tobyspark 19:350d1191e466 353 // }
tobyspark 19:350d1191e466 354 //
tobyspark 19:350d1191e466 355 // payload = -1;
tobyspark 19:350d1191e466 356 // ok = ok && readCommand(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPStatus, payload);
tobyspark 19:350d1191e466 357 // ok = ok && (payload == state);
tobyspark 19:350d1191e466 358 //
tobyspark 19:350d1191e466 359 // payload = -1;
tobyspark 19:350d1191e466 360 // ok = ok && readCommand(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPStatus, payload);
tobyspark 19:350d1191e466 361 // ok = ok && (payload == state);
tobyspark 18:d765b0d9271c 362
tobyspark 18:d765b0d9271c 363 if (ok) break;
tobyspark 18:d765b0d9271c 364 else increaseCommandPeriods(500);
tobyspark 18:d765b0d9271c 365 }
tobyspark 18:d765b0d9271c 366 commandMinimumPeriod = minPeriodOnEntry;
tobyspark 18:d765b0d9271c 367 commandTimeoutPeriod = outPeriodOnEntry;
tobyspark 0:533cfae24a1b 368
tobyspark 18:d765b0d9271c 369 return ok;
tobyspark 0:533cfae24a1b 370 }
tobyspark 0:533cfae24a1b 371
tobyspark 23:46f42462a183 372 bool SPKTVOne::getResolutionParams(int resStoreNumber, int &horizpx, int &vertpx)
tobyspark 23:46f42462a183 373 {
tobyspark 23:46f42462a183 374 bool ok;
tobyspark 23:46f42462a183 375
tobyspark 23:46f42462a183 376 ok = command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 23:46f42462a183 377
tobyspark 23:46f42462a183 378 ok = ok && readCommand(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionActiveH, horizpx);
tobyspark 23:46f42462a183 379 ok = ok && readCommand(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionActiveV, vertpx);
tobyspark 23:46f42462a183 380
tobyspark 23:46f42462a183 381 return ok;
tobyspark 23:46f42462a183 382 }
tobyspark 23:46f42462a183 383
tobyspark 23:46f42462a183 384 SPKTVOne::aspectType SPKTVOne::getAspect()
tobyspark 23:46f42462a183 385 {
tobyspark 23:46f42462a183 386 aspectType aspect = aspectFit;;
tobyspark 23:46f42462a183 387
tobyspark 23:46f42462a183 388 int32_t payload1 = -1;
tobyspark 23:46f42462a183 389 readCommand(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceAspectCorrect, payload1);
tobyspark 23:46f42462a183 390
tobyspark 23:46f42462a183 391 int32_t payload2 = -1;
tobyspark 23:46f42462a183 392 readCommand(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceAspectCorrect, payload2);
tobyspark 23:46f42462a183 393
tobyspark 23:46f42462a183 394 if (payload1 == payload2)
tobyspark 23:46f42462a183 395 {
tobyspark 23:46f42462a183 396 if (payload1 == aspectFit) aspect = aspectFit;
tobyspark 23:46f42462a183 397 if (payload1 == aspectHFill) aspect = aspectSPKFill;
tobyspark 23:46f42462a183 398 if (payload1 == aspectVFill) aspect = aspectSPKFill;
tobyspark 23:46f42462a183 399 if (payload1 == aspect1to1) aspect = aspect1to1;
tobyspark 23:46f42462a183 400 }
tobyspark 23:46f42462a183 401 else if (((payload1 == aspectHFill) && (payload2 == aspectVFill)) || ((payload2 == aspectHFill) && (payload1 == aspectVFill)))
tobyspark 23:46f42462a183 402 {
tobyspark 23:46f42462a183 403 aspect = aspectSPKFill;
tobyspark 23:46f42462a183 404 }
tobyspark 23:46f42462a183 405 else
tobyspark 23:46f42462a183 406 {
tobyspark 23:46f42462a183 407 if (debug) debug->printf("SPKTVOne:getAspect got unknown aspect");
tobyspark 23:46f42462a183 408 }
tobyspark 23:46f42462a183 409
tobyspark 23:46f42462a183 410 return aspect;
tobyspark 23:46f42462a183 411 }
tobyspark 23:46f42462a183 412
tobyspark 23:46f42462a183 413 bool SPKTVOne::setAspect(aspectType aspect)
tobyspark 23:46f42462a183 414 {
tobyspark 23:46f42462a183 415 bool ok = true;
tobyspark 23:46f42462a183 416 aspectType aspectFor1 = aspect;
tobyspark 23:46f42462a183 417 aspectType aspectFor2 = aspect;
tobyspark 23:46f42462a183 418
tobyspark 23:46f42462a183 419 if (aspect == aspectSPKFill)
tobyspark 23:46f42462a183 420 {
tobyspark 23:46f42462a183 421 int resNumberOutput = getResolution();
tobyspark 23:46f42462a183 422 int horizOutput = 0;
tobyspark 23:46f42462a183 423 int vertOutput = 0;
tobyspark 23:46f42462a183 424 getResolutionParams(resNumberOutput, horizOutput, vertOutput);
tobyspark 23:46f42462a183 425
tobyspark 23:46f42462a183 426 if (resNumberOutput != -1)
tobyspark 23:46f42462a183 427 {
tobyspark 23:46f42462a183 428 float aspectOutput = (float)horizOutput / (float)vertOutput;
tobyspark 23:46f42462a183 429
tobyspark 23:46f42462a183 430 int sourceForWindowA = -1;
tobyspark 23:46f42462a183 431 int sourceForWindowB = -1;
tobyspark 23:46f42462a183 432 readCommand(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsWindowSource, sourceForWindowA);
tobyspark 23:46f42462a183 433 readCommand(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsWindowSource, sourceForWindowB);
tobyspark 23:46f42462a183 434
tobyspark 23:46f42462a183 435 int windowForRGB1 = -1;
tobyspark 23:46f42462a183 436 int windowForRGB2 = -1;
tobyspark 23:46f42462a183 437 switch (sourceForWindowA)
tobyspark 23:46f42462a183 438 {
tobyspark 23:46f42462a183 439 case kTV1SourceRGB1: windowForRGB1 = kTV1WindowIDA; break;
tobyspark 23:46f42462a183 440 case kTV1SourceRGB2: windowForRGB2 = kTV1WindowIDA; break;
tobyspark 23:46f42462a183 441 }
tobyspark 23:46f42462a183 442 switch (sourceForWindowB)
tobyspark 23:46f42462a183 443 {
tobyspark 23:46f42462a183 444 case kTV1SourceRGB1: windowForRGB1 = kTV1WindowIDB; break;
tobyspark 23:46f42462a183 445 case kTV1SourceRGB2: windowForRGB2 = kTV1WindowIDB; break;
tobyspark 23:46f42462a183 446 }
tobyspark 23:46f42462a183 447
tobyspark 23:46f42462a183 448 if ((windowForRGB1 != -1))
tobyspark 23:46f42462a183 449 {
tobyspark 23:46f42462a183 450 int resNumber1 = getResolution(windowForRGB1);
tobyspark 23:46f42462a183 451 int horiz1 = 0;
tobyspark 23:46f42462a183 452 int vert1 = 0;
tobyspark 23:46f42462a183 453 getResolutionParams(resNumber1, horiz1, vert1);
tobyspark 23:46f42462a183 454 float aspect1 = (float)horiz1 / (float)vert1;
tobyspark 23:46f42462a183 455 aspectFor1 = aspectOutput > aspect1 ? aspectHFill : aspectVFill;
tobyspark 23:46f42462a183 456 }
tobyspark 23:46f42462a183 457 else
tobyspark 23:46f42462a183 458 {
tobyspark 23:46f42462a183 459 aspectFor1 = aspectHFill;
tobyspark 23:46f42462a183 460 }
tobyspark 23:46f42462a183 461
tobyspark 23:46f42462a183 462 if (windowForRGB2 != -1)
tobyspark 23:46f42462a183 463 {
tobyspark 23:46f42462a183 464 int resNumber2 = getResolution(windowForRGB2);
tobyspark 23:46f42462a183 465 int horiz2 = 0;
tobyspark 23:46f42462a183 466 int vert2 = 0;
tobyspark 23:46f42462a183 467 getResolutionParams(resNumber2, horiz2, vert2);
tobyspark 23:46f42462a183 468 float aspect2 = (float)horiz2 / (float)vert2;
tobyspark 23:46f42462a183 469 aspectFor2 = aspectOutput > aspect2 ? aspectHFill : aspectVFill;
tobyspark 23:46f42462a183 470 }
tobyspark 23:46f42462a183 471 else
tobyspark 23:46f42462a183 472 {
tobyspark 23:46f42462a183 473 aspectFor2 = aspectHFill;
tobyspark 23:46f42462a183 474 }
tobyspark 23:46f42462a183 475 }
tobyspark 23:46f42462a183 476 }
tobyspark 23:46f42462a183 477
tobyspark 23:46f42462a183 478 ok = ok && command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceAspectCorrect, aspectFor1);
tobyspark 23:46f42462a183 479 ok = ok && command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceAspectCorrect, aspectFor2);
tobyspark 23:46f42462a183 480
tobyspark 23:46f42462a183 481 return ok;
tobyspark 23:46f42462a183 482 }
tobyspark 23:46f42462a183 483
tobyspark 11:90e5a72a0034 484 bool SPKTVOne::set1920x480(int resStoreNumber)
tobyspark 0:533cfae24a1b 485 {
tobyspark 11:90e5a72a0034 486 bool ok;
tobyspark 11:90e5a72a0034 487
tobyspark 24:4eec37b8387e 488 ok = command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 18:d765b0d9271c 489
tobyspark 24:4eec37b8387e 490 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 24:4eec37b8387e 491 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionFreqCoarseH, 31475);
tobyspark 24:4eec37b8387e 492 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionFreqFineH, 31475);
tobyspark 24:4eec37b8387e 493 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionActiveH, 1920);
tobyspark 24:4eec37b8387e 494 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionActiveV, 480);
tobyspark 24:4eec37b8387e 495 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionStartH, 240);
tobyspark 24:4eec37b8387e 496 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionStartV, 5);
tobyspark 24:4eec37b8387e 497 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionCLKS, 2400);
tobyspark 24:4eec37b8387e 498 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionLines, 525);
tobyspark 24:4eec37b8387e 499 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncH, 192);
tobyspark 24:4eec37b8387e 500 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncV, 30);
tobyspark 24:4eec37b8387e 501 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncPolarity, 0);
tobyspark 11:90e5a72a0034 502
tobyspark 11:90e5a72a0034 503 return ok;
tobyspark 0:533cfae24a1b 504 }
tobyspark 0:533cfae24a1b 505
tobyspark 11:90e5a72a0034 506 bool SPKTVOne::set1600x600(int resStoreNumber)
tobyspark 0:533cfae24a1b 507 {
tobyspark 11:90e5a72a0034 508 bool ok;
tobyspark 11:90e5a72a0034 509
tobyspark 24:4eec37b8387e 510 ok = command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 18:d765b0d9271c 511
tobyspark 24:4eec37b8387e 512 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 24:4eec37b8387e 513 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionFreqCoarseH, 37879);
tobyspark 24:4eec37b8387e 514 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionFreqFineH, 37879);
tobyspark 24:4eec37b8387e 515 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionActiveH, 1600);
tobyspark 24:4eec37b8387e 516 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionActiveV, 600);
tobyspark 24:4eec37b8387e 517 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionStartH, 192);
tobyspark 24:4eec37b8387e 518 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionStartV, 14);
tobyspark 24:4eec37b8387e 519 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionCLKS, 2112);
tobyspark 24:4eec37b8387e 520 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionLines, 628);
tobyspark 24:4eec37b8387e 521 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncH, 160);
tobyspark 24:4eec37b8387e 522 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncV, 13);
tobyspark 24:4eec37b8387e 523 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncPolarity, 0);
tobyspark 11:90e5a72a0034 524
tobyspark 11:90e5a72a0034 525 return ok;
tobyspark 0:533cfae24a1b 526 }
tobyspark 0:533cfae24a1b 527
tobyspark 24:4eec37b8387e 528 bool SPKTVOne::set2048x768(int resStoreNumber, bool de)
tobyspark 2:af9e9ab63b23 529 {
tobyspark 11:90e5a72a0034 530 bool ok;
tobyspark 11:90e5a72a0034 531
tobyspark 24:4eec37b8387e 532 ok = command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 18:d765b0d9271c 533
tobyspark 24:4eec37b8387e 534 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 24:4eec37b8387e 535 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionFreqCoarseH, 48363);
tobyspark 24:4eec37b8387e 536 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionFreqFineH, 48363);
tobyspark 24:4eec37b8387e 537 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionActiveH, 2048);
tobyspark 24:4eec37b8387e 538 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionActiveV, 768);
tobyspark 24:4eec37b8387e 539 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionStartH, de ? 224 : 152);
tobyspark 24:4eec37b8387e 540 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionStartV, de ? 11 : 20);
tobyspark 24:4eec37b8387e 541 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionCLKS, de ? 2688 : 2352);
tobyspark 24:4eec37b8387e 542 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionLines, de ? 806 : 806);
tobyspark 24:4eec37b8387e 543 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncH, de ? 368 : 64);
tobyspark 24:4eec37b8387e 544 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncV, de ? 24 : 15);
tobyspark 24:4eec37b8387e 545 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustResolutionSyncPolarity, 3);
tobyspark 11:90e5a72a0034 546
tobyspark 11:90e5a72a0034 547 return ok;
tobyspark 2:af9e9ab63b23 548 }
tobyspark 2:af9e9ab63b23 549
tobyspark 0:533cfae24a1b 550 void SPKTVOne::signErrorOff() {
tobyspark 0:533cfae24a1b 551 *errorDO = 0;
tobyspark 0:533cfae24a1b 552 }
tobyspark 14:da403a01f9ef 553
tobyspark 18:d765b0d9271c 554 SPKTVOne::processorType SPKTVOne::getProcessorType()
tobyspark 18:d765b0d9271c 555 {
tobyspark 18:d765b0d9271c 556 bool ok;
tobyspark 18:d765b0d9271c 557 int32_t payload = 0;
tobyspark 18:d765b0d9271c 558
tobyspark 18:d765b0d9271c 559 if (processor.version == -1)
tobyspark 18:d765b0d9271c 560 {
tobyspark 18:d765b0d9271c 561 ok = readCommand(0, kTV1WindowIDA, kTV1FunctionReadSoftwareVersion, payload);
tobyspark 18:d765b0d9271c 562 if (ok && payload > 0) processor.version = payload;
tobyspark 18:d765b0d9271c 563 }
tobyspark 18:d765b0d9271c 564
tobyspark 18:d765b0d9271c 565 if (processor.productType == -1)
tobyspark 18:d765b0d9271c 566 {
tobyspark 18:d765b0d9271c 567 ok = readCommand(0, kTV1WindowIDA, kTV1FunctionReadProductType, payload);
tobyspark 18:d765b0d9271c 568 if (ok && payload > 0) processor.productType = payload;
tobyspark 18:d765b0d9271c 569 }
tobyspark 18:d765b0d9271c 570
tobyspark 18:d765b0d9271c 571 if (processor.boardType == -1)
tobyspark 18:d765b0d9271c 572 {
tobyspark 18:d765b0d9271c 573 ok = readCommand(0, kTV1WindowIDA, kTV1FunctionReadBoardType, payload);
tobyspark 18:d765b0d9271c 574 if (ok && payload > 0) processor.boardType = payload;
tobyspark 18:d765b0d9271c 575 }
tobyspark 18:d765b0d9271c 576
tobyspark 18:d765b0d9271c 577 if (debug) debug->printf("v: %i, p: %i, b: %i", processor.version, processor.productType, processor.boardType);
tobyspark 18:d765b0d9271c 578
tobyspark 18:d765b0d9271c 579 return processor;
tobyspark 18:d765b0d9271c 580 }
tobyspark 18:d765b0d9271c 581
tobyspark 17:68b9bb89da2b 582 void SPKTVOne::timerCheck() {
tobyspark 17:68b9bb89da2b 583 // timers are based on 32-bit int microsecond counters, so can only time up to a maximum of 2^31-1 microseconds i.e. 30 minutes.
tobyspark 17:68b9bb89da2b 584 // this method is called once a minute, and resets the timer if we've been idle for 25mins.
tobyspark 18:d765b0d9271c 585 if (timer.read_ms() > 1000*60*25)
tobyspark 17:68b9bb89da2b 586 {
tobyspark 17:68b9bb89da2b 587 if (debug) debug->printf("TVOne Timer reset at %ims", timer.read_ms());
tobyspark 17:68b9bb89da2b 588 timer.reset();
tobyspark 17:68b9bb89da2b 589 }
tobyspark 17:68b9bb89da2b 590 }
tobyspark 17:68b9bb89da2b 591
tobyspark 16:ed8d08386034 592 bool SPKTVOne::uploadEDID(FILE *file, int edidSlotIndex)
tobyspark 14:da403a01f9ef 593 {
tobyspark 16:ed8d08386034 594 bool success;
tobyspark 14:da403a01f9ef 595
tobyspark 14:da403a01f9ef 596 // To write EDID, its broken into chunks and sent as a series of extra-long commands
tobyspark 14:da403a01f9ef 597 // Command: 8 bytes of command (see code below) + 32 bytes of EDID payload + End byte
tobyspark 14:da403a01f9ef 598 // Acknowledgement: 53 02 40 95 (Hex)
tobyspark 16:ed8d08386034 599 // We want to upload full EDID slot, ie. zero out to 256 even if edidData is only 128bytes.
tobyspark 14:da403a01f9ef 600
tobyspark 16:ed8d08386034 601 if (debug) debug->printf("Upload EDID to index %i \r\n", edidSlotIndex);
tobyspark 16:ed8d08386034 602
tobyspark 16:ed8d08386034 603 success = uploadFile(0x07, file, 256, edidSlotIndex);
tobyspark 16:ed8d08386034 604
tobyspark 16:ed8d08386034 605 return success;
tobyspark 16:ed8d08386034 606 }
tobyspark 16:ed8d08386034 607
tobyspark 16:ed8d08386034 608 bool SPKTVOne::uploadImage(FILE *file, int sisIndex)
tobyspark 16:ed8d08386034 609 {
tobyspark 16:ed8d08386034 610 bool success;
tobyspark 16:ed8d08386034 611
tobyspark 16:ed8d08386034 612 int imageDataLength = 0;
tobyspark 16:ed8d08386034 613
tobyspark 16:ed8d08386034 614 while (fgetc(file) != EOF) imageDataLength++ ;
tobyspark 16:ed8d08386034 615
tobyspark 16:ed8d08386034 616 if (debug) debug->printf("Upload Image with length %i to index %i \r\n", imageDataLength, sisIndex);
tobyspark 16:ed8d08386034 617
tobyspark 16:ed8d08386034 618 success = uploadFile(0x00, file, imageDataLength, sisIndex);
tobyspark 16:ed8d08386034 619
tobyspark 16:ed8d08386034 620 return success;
tobyspark 16:ed8d08386034 621 }
tobyspark 16:ed8d08386034 622
tobyspark 16:ed8d08386034 623 bool SPKTVOne::uploadFile(char instruction, FILE* file, int dataLength, int index)
tobyspark 16:ed8d08386034 624 {
tobyspark 16:ed8d08386034 625 // TASK: Upload Data
tobyspark 16:ed8d08386034 626
tobyspark 18:d765b0d9271c 627 // Lets be conservative with timings
tobyspark 18:d765b0d9271c 628 setCommandMinimumPeriod(100);
tobyspark 18:d765b0d9271c 629 setCommandTimeoutPeriod(300);
tobyspark 18:d765b0d9271c 630
tobyspark 16:ed8d08386034 631 // This command is reverse engineered. It implements an 'S' command, not the documented 'F'.
tobyspark 14:da403a01f9ef 632
tobyspark 14:da403a01f9ef 633 bool success = false;
tobyspark 14:da403a01f9ef 634
tobyspark 16:ed8d08386034 635 int dataChunkSize = 32;
tobyspark 14:da403a01f9ef 636 int ackLength = 4;
tobyspark 14:da403a01f9ef 637 char goodAck[] = {0x53, 0x02, 0x40, 0x95};
tobyspark 14:da403a01f9ef 638
tobyspark 16:ed8d08386034 639 fseek(file, 0, SEEK_SET);
tobyspark 16:ed8d08386034 640
tobyspark 16:ed8d08386034 641 for (int i=0; i<dataLength; i=i+dataChunkSize)
tobyspark 14:da403a01f9ef 642 {
tobyspark 16:ed8d08386034 643 int dataRemaining = dataLength - i;
tobyspark 18:d765b0d9271c 644 int actualDataChunkSize = (dataRemaining < dataChunkSize) ? dataRemaining : dataChunkSize;
tobyspark 16:ed8d08386034 645
tobyspark 16:ed8d08386034 646 int commandLength = 8+dataChunkSize+1;
tobyspark 14:da403a01f9ef 647 char command[commandLength];
tobyspark 14:da403a01f9ef 648
tobyspark 14:da403a01f9ef 649 command[0] = 0x53;
tobyspark 18:d765b0d9271c 650 command[1] = 6 + actualDataChunkSize + 1; // Subsequent number of bytes in command
tobyspark 14:da403a01f9ef 651 command[2] = 0x22;
tobyspark 16:ed8d08386034 652 command[3] = instruction;
tobyspark 16:ed8d08386034 653 command[4] = index;
tobyspark 14:da403a01f9ef 654 command[5] = 0;
tobyspark 16:ed8d08386034 655 command[6] = (i / dataChunkSize) & 0xFF; // chunk index LSB
tobyspark 16:ed8d08386034 656 command[7] = ((i / dataChunkSize) >> 8) & 0xFF; // chunk index MSB
tobyspark 14:da403a01f9ef 657
tobyspark 18:d765b0d9271c 658 for (int j=0; j<actualDataChunkSize; j++)
tobyspark 14:da403a01f9ef 659 {
tobyspark 16:ed8d08386034 660 char data = fgetc(file);
tobyspark 16:ed8d08386034 661 if (!feof(file))
tobyspark 16:ed8d08386034 662 *(command+8+j) = data;
tobyspark 14:da403a01f9ef 663 else
tobyspark 14:da403a01f9ef 664 *(command+8+j) = 0;
tobyspark 14:da403a01f9ef 665 }
tobyspark 14:da403a01f9ef 666
tobyspark 18:d765b0d9271c 667 command[8+actualDataChunkSize] = 0x3F;
tobyspark 14:da403a01f9ef 668
tobyspark 14:da403a01f9ef 669 if (debug)
tobyspark 14:da403a01f9ef 670 {
tobyspark 16:ed8d08386034 671 debug->printf("Command: ");
tobyspark 14:da403a01f9ef 672 for (int k=0; k < commandLength; k++) debug->printf(" %x", command[k]);
tobyspark 14:da403a01f9ef 673 debug->printf("\r\n");
tobyspark 14:da403a01f9ef 674 }
tobyspark 14:da403a01f9ef 675
tobyspark 18:d765b0d9271c 676 while (serial->readable() || timer.read_ms() < commandMinimumPeriod)
tobyspark 14:da403a01f9ef 677 {
tobyspark 14:da403a01f9ef 678 if (serial->readable()) serial->getc();
tobyspark 14:da403a01f9ef 679 }
tobyspark 14:da403a01f9ef 680
tobyspark 14:da403a01f9ef 681 for (int k=0; k < commandLength; k++) serial->putc(command[k]);
tobyspark 14:da403a01f9ef 682
tobyspark 14:da403a01f9ef 683 timer.reset();
tobyspark 14:da403a01f9ef 684
tobyspark 14:da403a01f9ef 685 char ackBuffer[4];
tobyspark 14:da403a01f9ef 686 int ackPos = 0;
tobyspark 18:d765b0d9271c 687 while (timer.read_ms() < commandTimeoutPeriod)
tobyspark 14:da403a01f9ef 688 {
tobyspark 14:da403a01f9ef 689 if (serial->readable()) ackBuffer[ackPos++] = serial->getc();
tobyspark 14:da403a01f9ef 690 if (ackPos == 4) break;
tobyspark 14:da403a01f9ef 691 }
tobyspark 16:ed8d08386034 692
tobyspark 14:da403a01f9ef 693 if (memcmp(ackBuffer, goodAck, ackLength) == 0)
tobyspark 14:da403a01f9ef 694 {
tobyspark 14:da403a01f9ef 695 success = true;
tobyspark 14:da403a01f9ef 696 }
tobyspark 14:da403a01f9ef 697 else
tobyspark 14:da403a01f9ef 698 {
tobyspark 14:da403a01f9ef 699 success = false;
tobyspark 14:da403a01f9ef 700 if (debug)
tobyspark 14:da403a01f9ef 701 {
tobyspark 18:d765b0d9271c 702 debug->printf("Data Part write failed. Ack:");
tobyspark 14:da403a01f9ef 703 for (int k = 0; k < ackLength; k++) debug->printf(" %x", ackBuffer[k]);
tobyspark 14:da403a01f9ef 704 debug->printf("\r\n");
tobyspark 14:da403a01f9ef 705 }
tobyspark 14:da403a01f9ef 706 break;
tobyspark 14:da403a01f9ef 707 }
tobyspark 14:da403a01f9ef 708 }
tobyspark 14:da403a01f9ef 709
tobyspark 18:d765b0d9271c 710 resetCommandPeriods();
tobyspark 18:d765b0d9271c 711
tobyspark 14:da403a01f9ef 712 return success;
tobyspark 14:da403a01f9ef 713 }