RS232 control for TVOne products

Dependents:   SPK-DVIMXR

Committer:
tobyspark
Date:
Tue Dec 04 19:09:06 2012 +0000
Revision:
17:68b9bb89da2b
Parent:
16:ed8d08386034
Child:
18:d765b0d9271c
Timer overflow if idle fix (unverified)

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 14:da403a01f9ef 39 timeoutCommandPeriod = 100;
tobyspark 14:da403a01f9ef 40 minimumCommandPeriod = 30;
tobyspark 14:da403a01f9ef 41
tobyspark 14:da403a01f9ef 42 timer.start();
tobyspark 17:68b9bb89da2b 43 timerCheckTicker.attach(this, &SPKTVOne::timerCheck, 60);
tobyspark 14:da403a01f9ef 44
tobyspark 0:533cfae24a1b 45 // Link up debug Serial object
tobyspark 0:533cfae24a1b 46 // Passing in shared object as debugging is shared between all DVI mixer functions
tobyspark 0:533cfae24a1b 47 debug = debugSerial;
tobyspark 0:533cfae24a1b 48 }
tobyspark 0:533cfae24a1b 49
tobyspark 10:5f398fc9b5c1 50 bool SPKTVOne::command(uint8_t channel, uint8_t window, int32_t func, int32_t payload)
tobyspark 10:5f398fc9b5c1 51 {
tobyspark 14:da403a01f9ef 52 int ackBuff[standardAckLength] = {0};
tobyspark 10:5f398fc9b5c1 53
tobyspark 11:90e5a72a0034 54 bool success = command(writeCommandType, ackBuff, standardAckLength, channel, window, func, payload);
tobyspark 11:90e5a72a0034 55
tobyspark 11:90e5a72a0034 56 // TASK: Check return payload is what we tried to set it to
tobyspark 11:90e5a72a0034 57 char payloadStr[7];
tobyspark 11:90e5a72a0034 58 for (int i = 0; i < 6; i++)
tobyspark 11:90e5a72a0034 59 {
tobyspark 11:90e5a72a0034 60 payloadStr[i] = ackBuff[11+i];
tobyspark 11:90e5a72a0034 61 }
tobyspark 11:90e5a72a0034 62 payloadStr[6] = NULL;
tobyspark 11:90e5a72a0034 63
tobyspark 11:90e5a72a0034 64 int payloadBack = strtol (payloadStr, NULL, 16);
tobyspark 11:90e5a72a0034 65
tobyspark 11:90e5a72a0034 66 if (payload != payloadBack)
tobyspark 11:90e5a72a0034 67 {
tobyspark 11:90e5a72a0034 68 success = false;
tobyspark 13:4d659b89a457 69 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 70 }
tobyspark 11:90e5a72a0034 71 return success;
tobyspark 11:90e5a72a0034 72 }
tobyspark 11:90e5a72a0034 73
tobyspark 11:90e5a72a0034 74 bool SPKTVOne::readCommand(uint8_t channel, uint8_t window, int32_t func, int32_t &payload)
tobyspark 11:90e5a72a0034 75 {
tobyspark 14:da403a01f9ef 76 int ackBuff[standardAckLength] = {0};
tobyspark 11:90e5a72a0034 77
tobyspark 11:90e5a72a0034 78 bool success = command(readCommandType, ackBuff, standardAckLength, channel, window, func, payload);
tobyspark 11:90e5a72a0034 79
tobyspark 11:90e5a72a0034 80 char payloadStr[7];
tobyspark 11:90e5a72a0034 81 for (int i = 0; i < 6; i++)
tobyspark 11:90e5a72a0034 82 {
tobyspark 11:90e5a72a0034 83 payloadStr[i] = ackBuff[11+i];
tobyspark 11:90e5a72a0034 84 }
tobyspark 11:90e5a72a0034 85 payloadStr[6] = NULL;
tobyspark 11:90e5a72a0034 86
tobyspark 11:90e5a72a0034 87 payload = strtol (payloadStr, NULL, 16);
tobyspark 10:5f398fc9b5c1 88
tobyspark 10:5f398fc9b5c1 89 return success;
tobyspark 10:5f398fc9b5c1 90 }
tobyspark 10:5f398fc9b5c1 91
tobyspark 10:5f398fc9b5c1 92 bool SPKTVOne::command(commandType readWrite, int* ackBuffer, int ackLength, uint8_t channel, uint8_t window, int32_t func, int32_t payload)
tobyspark 14:da403a01f9ef 93 {
tobyspark 14:da403a01f9ef 94 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 95
tobyspark 0:533cfae24a1b 96 // TASK: Sign start of serial command write
tobyspark 0:533cfae24a1b 97 if (writeDO) *writeDO = 1;
tobyspark 0:533cfae24a1b 98
tobyspark 14:da403a01f9ef 99 // TASK: Prepare to issue command to the TVOne unit
tobyspark 14:da403a01f9ef 100 // - discard anything waiting to be read in the return serial buffer
tobyspark 14:da403a01f9ef 101 // - make sure we're past the minimum time between command sends as the unit can get overloaded
tobyspark 14:da403a01f9ef 102 while (serial->readable() || timer.read_ms() < minimumCommandPeriod) {
tobyspark 14:da403a01f9ef 103 if (serial->readable()) serial->getc();
tobyspark 0:533cfae24a1b 104 }
tobyspark 0:533cfae24a1b 105
tobyspark 0:533cfae24a1b 106 // TASK: Create the bytes of command
tobyspark 0:533cfae24a1b 107
tobyspark 0:533cfae24a1b 108 uint8_t cmd[8];
tobyspark 0:533cfae24a1b 109 uint8_t checksum = 0;
tobyspark 0:533cfae24a1b 110
tobyspark 0:533cfae24a1b 111 // CMD
tobyspark 10:5f398fc9b5c1 112 cmd[0] = readWrite<<7 | 1<<2;
tobyspark 0:533cfae24a1b 113 // CHA
tobyspark 0:533cfae24a1b 114 cmd[1] = channel;
tobyspark 0:533cfae24a1b 115 // WINDOW
tobyspark 0:533cfae24a1b 116 cmd[2] = window;
tobyspark 0:533cfae24a1b 117 // OUTPUT & FUNCTION
tobyspark 0:533cfae24a1b 118 // cmd[3] cmd[4]
tobyspark 0:533cfae24a1b 119 // output 0 = 0000xxx xxxxxxx
tobyspark 0:533cfae24a1b 120 // function = xxxXXXX XXXXXXX
tobyspark 0:533cfae24a1b 121 cmd[3] = func >> 8;
tobyspark 0:533cfae24a1b 122 cmd[4] = func & 0xFF;
tobyspark 0:533cfae24a1b 123 // PAYLOAD
tobyspark 0:533cfae24a1b 124 cmd[5] = (payload >> 16) & 0xFF;
tobyspark 0:533cfae24a1b 125 cmd[6] = (payload >> 8) & 0xFF;
tobyspark 0:533cfae24a1b 126 cmd[7] = payload & 0xFF;
tobyspark 0:533cfae24a1b 127
tobyspark 0:533cfae24a1b 128 // TASK: Write the bytes of command to RS232 as correctly packaged 20 characters of ASCII
tobyspark 10:5f398fc9b5c1 129
tobyspark 11:90e5a72a0034 130 if (readWrite == writeCommandType)
tobyspark 0:533cfae24a1b 131 {
tobyspark 14:da403a01f9ef 132 for (int i=0; i<8; i++) checksum += cmd[i];
tobyspark 10:5f398fc9b5c1 133 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 134 }
tobyspark 11:90e5a72a0034 135 if (readWrite == readCommandType)
tobyspark 10:5f398fc9b5c1 136 {
tobyspark 14:da403a01f9ef 137 for (int i=0; i<5; i++) checksum += cmd[i];
tobyspark 10:5f398fc9b5c1 138 serial->printf("F%02X%02X%02X%02X%02X%02X\r", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], checksum);
tobyspark 10:5f398fc9b5c1 139 }
tobyspark 10:5f398fc9b5c1 140
tobyspark 0:533cfae24a1b 141 // TASK: Check the unit's return string, to enable return to main program as soon as unit is ready
tobyspark 0:533cfae24a1b 142
tobyspark 0:533cfae24a1b 143 // Handling the timing of this return is critical to effective control.
tobyspark 0:533cfae24a1b 144 // Returning the instant something is received back overloads the processor, as does anything until the full 20 char acknowledgement.
tobyspark 0:533cfae24a1b 145 // TVOne turn out to say that receipt of the ack doesn't guarantee the unit is ready for the next command.
tobyspark 0:533cfae24a1b 146 // According to the manual, operations typically take 30ms, and to simplify programming you can throttle commands to every 100ms.
tobyspark 0:533cfae24a1b 147 // 100ms is too slow for us. Going with returning after 30ms if we've received an acknowledgement, returning after 100ms otherwise.
tobyspark 10:5f398fc9b5c1 148
tobyspark 14:da403a01f9ef 149 bool success = false;
tobyspark 14:da403a01f9ef 150 int ackPos = 0;
tobyspark 14:da403a01f9ef 151 timer.reset();
tobyspark 0:533cfae24a1b 152
tobyspark 14:da403a01f9ef 153 while (timer.read_ms() < timeoutCommandPeriod)
tobyspark 10:5f398fc9b5c1 154 {
tobyspark 14:da403a01f9ef 155 if (serial->readable())
tobyspark 10:5f398fc9b5c1 156 {
tobyspark 14:da403a01f9ef 157 if (ackPos == 0)
tobyspark 9:42c83cac2f6d 158 {
tobyspark 14:da403a01f9ef 159 ackBuffer[0] = serial->getc();
tobyspark 14:da403a01f9ef 160 if (ackBuffer[0] == 'F') ackPos = 1;
tobyspark 14:da403a01f9ef 161 }
tobyspark 14:da403a01f9ef 162 else
tobyspark 14:da403a01f9ef 163 {
tobyspark 14:da403a01f9ef 164 ackBuffer[ackPos] = serial->getc();
tobyspark 14:da403a01f9ef 165 ackPos++;
tobyspark 14:da403a01f9ef 166 if (ackPos == ackLength) break;
tobyspark 0:533cfae24a1b 167 }
tobyspark 10:5f398fc9b5c1 168 }
tobyspark 9:42c83cac2f6d 169 }
tobyspark 14:da403a01f9ef 170
tobyspark 14:da403a01f9ef 171 // Return true if we got the no error acknowledgement from the unit. The rest of the ack will be verified elsewhere if needed.
tobyspark 14:da403a01f9ef 172 if (ackPos > 2 && ackBuffer[1] == '4')
tobyspark 14:da403a01f9ef 173 {
tobyspark 14:da403a01f9ef 174 success = true;
tobyspark 14:da403a01f9ef 175 }
tobyspark 0:533cfae24a1b 176
tobyspark 0:533cfae24a1b 177 // TASK: Sign end of write
tobyspark 0:533cfae24a1b 178
tobyspark 0:533cfae24a1b 179 if (writeDO) *writeDO = 0;
tobyspark 0:533cfae24a1b 180
tobyspark 0:533cfae24a1b 181 if (!success) {
tobyspark 0:533cfae24a1b 182 if (errorDO) {
tobyspark 0:533cfae24a1b 183 signErrorTimeout.detach();
tobyspark 0:533cfae24a1b 184 signErrorTimeout.attach(this, &SPKTVOne::signErrorOff, 0.25);
tobyspark 0:533cfae24a1b 185 *errorDO = 1;
tobyspark 0:533cfae24a1b 186 }
tobyspark 0:533cfae24a1b 187
tobyspark 0:533cfae24a1b 188 if (debug) {
tobyspark 14:da403a01f9ef 189 debug->printf("TVOne serial error. Time from finishing writing command: %ims. Received %i ack chars:", timer.read_ms(), ackPos);
tobyspark 14:da403a01f9ef 190 for (int i = 0; i<ackLength; i++)
tobyspark 14:da403a01f9ef 191 {
tobyspark 14:da403a01f9ef 192 debug->printf("%c", ackBuffer[i]);
tobyspark 14:da403a01f9ef 193 }
tobyspark 14:da403a01f9ef 194 debug->printf("\r\n");
tobyspark 0:533cfae24a1b 195 }
tobyspark 0:533cfae24a1b 196 };
tobyspark 0:533cfae24a1b 197
tobyspark 0:533cfae24a1b 198 return success;
tobyspark 0:533cfae24a1b 199 }
tobyspark 0:533cfae24a1b 200
tobyspark 14:da403a01f9ef 201 int SPKTVOne::millisSinceLastCommandSent()
tobyspark 14:da403a01f9ef 202 {
tobyspark 14:da403a01f9ef 203 return timer.read_ms();
tobyspark 14:da403a01f9ef 204 }
tobyspark 14:da403a01f9ef 205
tobyspark 11:90e5a72a0034 206 bool SPKTVOne::setCustomResolutions()
tobyspark 0:533cfae24a1b 207 {
tobyspark 11:90e5a72a0034 208 bool ok = true;;
tobyspark 11:90e5a72a0034 209 int unlocked = 0;
tobyspark 11:90e5a72a0034 210 int locked = 1;
tobyspark 11:90e5a72a0034 211
tobyspark 11:90e5a72a0034 212 ok = ok && command(0, 0, kTV1FunctionAdjustFrontPanelLock, locked);
tobyspark 11:90e5a72a0034 213
tobyspark 11:90e5a72a0034 214 ok = ok && set1920x480(kTV1ResolutionTripleHeadVGAp60);
tobyspark 11:90e5a72a0034 215 ok = ok && set1600x600(kTV1ResolutionDualHeadSVGAp60);
tobyspark 11:90e5a72a0034 216 ok = ok && set2048x768(kTV1ResolutionDualHeadXGAp60);
tobyspark 11:90e5a72a0034 217
tobyspark 11:90e5a72a0034 218 ok = ok && command(0, 0, kTV1FunctionAdjustFrontPanelLock, unlocked);
tobyspark 11:90e5a72a0034 219
tobyspark 11:90e5a72a0034 220 return ok;
tobyspark 0:533cfae24a1b 221 }
tobyspark 0:533cfae24a1b 222
tobyspark 3:03e7e7b7a870 223 bool SPKTVOne::setHDCPOn(bool state)
tobyspark 0:533cfae24a1b 224 {
tobyspark 11:90e5a72a0034 225 bool ok;
tobyspark 0:533cfae24a1b 226
tobyspark 0:533cfae24a1b 227 // Turn HDCP off on the output
tobyspark 3:03e7e7b7a870 228 ok = command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsHDCPRequired, state);
tobyspark 3:03e7e7b7a870 229 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsHDCPStatus, state);
tobyspark 0:533cfae24a1b 230 // Likewise on inputs A and B
tobyspark 3:03e7e7b7a870 231 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPAdvertize, state);
tobyspark 3:03e7e7b7a870 232 ok = ok && command(0, kTV1WindowIDB, kTV1FunctionAdjustSourceHDCPAdvertize, state);
tobyspark 3:03e7e7b7a870 233 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPStatus, state);
tobyspark 3:03e7e7b7a870 234 ok = ok && command(0, kTV1WindowIDB, kTV1FunctionAdjustSourceHDCPStatus, state);
tobyspark 0:533cfae24a1b 235
tobyspark 0:533cfae24a1b 236 return ok;
tobyspark 0:533cfae24a1b 237 }
tobyspark 0:533cfae24a1b 238
tobyspark 11:90e5a72a0034 239 bool SPKTVOne::set1920x480(int resStoreNumber)
tobyspark 0:533cfae24a1b 240 {
tobyspark 11:90e5a72a0034 241 bool ok;
tobyspark 11:90e5a72a0034 242
tobyspark 11:90e5a72a0034 243 ok = command(0, 0, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 11:90e5a72a0034 244 if (ok)
tobyspark 11:90e5a72a0034 245 {
tobyspark 11:90e5a72a0034 246 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 11:90e5a72a0034 247 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionFreqCoarseH, 31475);
tobyspark 11:90e5a72a0034 248 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionFreqFineH, 31475);
tobyspark 11:90e5a72a0034 249 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionActiveH, 1920);
tobyspark 11:90e5a72a0034 250 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionActiveV, 480);
tobyspark 11:90e5a72a0034 251 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionStartH, 240);
tobyspark 11:90e5a72a0034 252 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionStartV, 5);
tobyspark 11:90e5a72a0034 253 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionCLKS, 2400);
tobyspark 11:90e5a72a0034 254 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionLines, 525);
tobyspark 11:90e5a72a0034 255 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncH, 192);
tobyspark 11:90e5a72a0034 256 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncV, 30);
tobyspark 11:90e5a72a0034 257 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncPolarity, 0);
tobyspark 11:90e5a72a0034 258 }
tobyspark 11:90e5a72a0034 259
tobyspark 11:90e5a72a0034 260 return ok;
tobyspark 0:533cfae24a1b 261 }
tobyspark 0:533cfae24a1b 262
tobyspark 11:90e5a72a0034 263 bool SPKTVOne::set1600x600(int resStoreNumber)
tobyspark 0:533cfae24a1b 264 {
tobyspark 11:90e5a72a0034 265 bool ok;
tobyspark 11:90e5a72a0034 266
tobyspark 11:90e5a72a0034 267 ok = command(0, 0, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 11:90e5a72a0034 268 if (ok)
tobyspark 11:90e5a72a0034 269 {
tobyspark 11:90e5a72a0034 270 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 11:90e5a72a0034 271 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionFreqCoarseH, 37879);
tobyspark 11:90e5a72a0034 272 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionFreqFineH, 37879);
tobyspark 11:90e5a72a0034 273 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionActiveH, 1600);
tobyspark 11:90e5a72a0034 274 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionActiveV, 600);
tobyspark 11:90e5a72a0034 275 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionStartH, 192);
tobyspark 11:90e5a72a0034 276 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionStartV, 14);
tobyspark 11:90e5a72a0034 277 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionCLKS, 2112);
tobyspark 11:90e5a72a0034 278 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionLines, 628);
tobyspark 11:90e5a72a0034 279 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncH, 160);
tobyspark 11:90e5a72a0034 280 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncV, 13);
tobyspark 11:90e5a72a0034 281 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncPolarity, 0);
tobyspark 11:90e5a72a0034 282 }
tobyspark 11:90e5a72a0034 283
tobyspark 11:90e5a72a0034 284 return ok;
tobyspark 0:533cfae24a1b 285 }
tobyspark 0:533cfae24a1b 286
tobyspark 11:90e5a72a0034 287 bool SPKTVOne::set2048x768(int resStoreNumber)
tobyspark 2:af9e9ab63b23 288 {
tobyspark 11:90e5a72a0034 289 bool ok;
tobyspark 11:90e5a72a0034 290
tobyspark 11:90e5a72a0034 291 ok = command(0, 0, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 11:90e5a72a0034 292 if (ok)
tobyspark 11:90e5a72a0034 293 {
tobyspark 11:90e5a72a0034 294 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 11:90e5a72a0034 295 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionFreqCoarseH, 48363);
tobyspark 11:90e5a72a0034 296 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionFreqFineH, 48363);
tobyspark 11:90e5a72a0034 297 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionActiveH, 2048);
tobyspark 11:90e5a72a0034 298 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionActiveV, 768);
tobyspark 11:90e5a72a0034 299 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionStartH, 224);
tobyspark 11:90e5a72a0034 300 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionStartV, 11);
tobyspark 11:90e5a72a0034 301 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionCLKS, 2688);
tobyspark 11:90e5a72a0034 302 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionLines, 806);
tobyspark 11:90e5a72a0034 303 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncH, 368);
tobyspark 11:90e5a72a0034 304 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncV, 24);
tobyspark 11:90e5a72a0034 305 ok = ok && command(0, 0, kTV1FunctionAdjustResolutionSyncPolarity, 0);
tobyspark 11:90e5a72a0034 306 }
tobyspark 11:90e5a72a0034 307
tobyspark 11:90e5a72a0034 308 return ok;
tobyspark 2:af9e9ab63b23 309 }
tobyspark 2:af9e9ab63b23 310
tobyspark 0:533cfae24a1b 311 void SPKTVOne::signErrorOff() {
tobyspark 0:533cfae24a1b 312 *errorDO = 0;
tobyspark 0:533cfae24a1b 313 }
tobyspark 14:da403a01f9ef 314
tobyspark 17:68b9bb89da2b 315 void SPKTVOne::timerCheck() {
tobyspark 17:68b9bb89da2b 316 // 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 317 // this method is called once a minute, and resets the timer if we've been idle for 25mins.
tobyspark 17:68b9bb89da2b 318 if (timer.read_ms() > 1000*25)
tobyspark 17:68b9bb89da2b 319 {
tobyspark 17:68b9bb89da2b 320 if (debug) debug->printf("TVOne Timer reset at %ims", timer.read_ms());
tobyspark 17:68b9bb89da2b 321 timer.reset();
tobyspark 17:68b9bb89da2b 322 }
tobyspark 17:68b9bb89da2b 323 }
tobyspark 17:68b9bb89da2b 324
tobyspark 16:ed8d08386034 325 bool SPKTVOne::uploadEDID(FILE *file, int edidSlotIndex)
tobyspark 14:da403a01f9ef 326 {
tobyspark 16:ed8d08386034 327 bool success;
tobyspark 14:da403a01f9ef 328
tobyspark 14:da403a01f9ef 329 // To write EDID, its broken into chunks and sent as a series of extra-long commands
tobyspark 14:da403a01f9ef 330 // Command: 8 bytes of command (see code below) + 32 bytes of EDID payload + End byte
tobyspark 14:da403a01f9ef 331 // Acknowledgement: 53 02 40 95 (Hex)
tobyspark 16:ed8d08386034 332 // We want to upload full EDID slot, ie. zero out to 256 even if edidData is only 128bytes.
tobyspark 14:da403a01f9ef 333
tobyspark 16:ed8d08386034 334 if (debug) debug->printf("Upload EDID to index %i \r\n", edidSlotIndex);
tobyspark 16:ed8d08386034 335
tobyspark 16:ed8d08386034 336 success = uploadFile(0x07, file, 256, edidSlotIndex);
tobyspark 16:ed8d08386034 337
tobyspark 16:ed8d08386034 338 return success;
tobyspark 16:ed8d08386034 339 }
tobyspark 16:ed8d08386034 340
tobyspark 16:ed8d08386034 341 bool SPKTVOne::uploadImage(FILE *file, int sisIndex)
tobyspark 16:ed8d08386034 342 {
tobyspark 16:ed8d08386034 343 bool success;
tobyspark 16:ed8d08386034 344
tobyspark 16:ed8d08386034 345 int imageDataLength = 0;
tobyspark 16:ed8d08386034 346
tobyspark 16:ed8d08386034 347 while (fgetc(file) != EOF) imageDataLength++ ;
tobyspark 16:ed8d08386034 348
tobyspark 16:ed8d08386034 349 if (debug) debug->printf("Upload Image with length %i to index %i \r\n", imageDataLength, sisIndex);
tobyspark 16:ed8d08386034 350
tobyspark 16:ed8d08386034 351 success = uploadFile(0x00, file, imageDataLength, sisIndex);
tobyspark 16:ed8d08386034 352
tobyspark 16:ed8d08386034 353 return success;
tobyspark 16:ed8d08386034 354 }
tobyspark 16:ed8d08386034 355
tobyspark 16:ed8d08386034 356 bool SPKTVOne::uploadFile(char instruction, FILE* file, int dataLength, int index)
tobyspark 16:ed8d08386034 357 {
tobyspark 16:ed8d08386034 358 // TASK: Upload Data
tobyspark 16:ed8d08386034 359
tobyspark 16:ed8d08386034 360 // This command is reverse engineered. It implements an 'S' command, not the documented 'F'.
tobyspark 14:da403a01f9ef 361
tobyspark 14:da403a01f9ef 362 bool success = false;
tobyspark 14:da403a01f9ef 363
tobyspark 16:ed8d08386034 364 int dataChunkSize = 32;
tobyspark 14:da403a01f9ef 365 int ackLength = 4;
tobyspark 14:da403a01f9ef 366 char goodAck[] = {0x53, 0x02, 0x40, 0x95};
tobyspark 14:da403a01f9ef 367
tobyspark 16:ed8d08386034 368 fseek(file, 0, SEEK_SET);
tobyspark 16:ed8d08386034 369
tobyspark 16:ed8d08386034 370 for (int i=0; i<dataLength; i=i+dataChunkSize)
tobyspark 14:da403a01f9ef 371 {
tobyspark 16:ed8d08386034 372 int dataRemaining = dataLength - i;
tobyspark 16:ed8d08386034 373 if (dataRemaining < dataChunkSize) dataChunkSize = dataRemaining;
tobyspark 16:ed8d08386034 374
tobyspark 16:ed8d08386034 375 int commandLength = 8+dataChunkSize+1;
tobyspark 14:da403a01f9ef 376 char command[commandLength];
tobyspark 14:da403a01f9ef 377
tobyspark 14:da403a01f9ef 378 command[0] = 0x53;
tobyspark 16:ed8d08386034 379 command[1] = 6 + dataChunkSize + 1; // Subsequent number of bytes in command
tobyspark 14:da403a01f9ef 380 command[2] = 0x22;
tobyspark 16:ed8d08386034 381 command[3] = instruction;
tobyspark 16:ed8d08386034 382 command[4] = index;
tobyspark 14:da403a01f9ef 383 command[5] = 0;
tobyspark 16:ed8d08386034 384 command[6] = (i / dataChunkSize) & 0xFF; // chunk index LSB
tobyspark 16:ed8d08386034 385 command[7] = ((i / dataChunkSize) >> 8) & 0xFF; // chunk index MSB
tobyspark 14:da403a01f9ef 386
tobyspark 16:ed8d08386034 387 for (int j=0; j<dataChunkSize; j++)
tobyspark 14:da403a01f9ef 388 {
tobyspark 16:ed8d08386034 389 char data = fgetc(file);
tobyspark 16:ed8d08386034 390 if (!feof(file))
tobyspark 16:ed8d08386034 391 *(command+8+j) = data;
tobyspark 14:da403a01f9ef 392 else
tobyspark 14:da403a01f9ef 393 *(command+8+j) = 0;
tobyspark 14:da403a01f9ef 394 }
tobyspark 14:da403a01f9ef 395
tobyspark 16:ed8d08386034 396 command[8+dataChunkSize] = 0x3F;
tobyspark 14:da403a01f9ef 397
tobyspark 14:da403a01f9ef 398 if (debug)
tobyspark 14:da403a01f9ef 399 {
tobyspark 16:ed8d08386034 400 debug->printf("Command: ");
tobyspark 14:da403a01f9ef 401 for (int k=0; k < commandLength; k++) debug->printf(" %x", command[k]);
tobyspark 14:da403a01f9ef 402 debug->printf("\r\n");
tobyspark 14:da403a01f9ef 403 }
tobyspark 14:da403a01f9ef 404
tobyspark 16:ed8d08386034 405 while (serial->readable() || timer.read_ms() < 100)
tobyspark 14:da403a01f9ef 406 {
tobyspark 14:da403a01f9ef 407 if (serial->readable()) serial->getc();
tobyspark 14:da403a01f9ef 408 }
tobyspark 14:da403a01f9ef 409
tobyspark 14:da403a01f9ef 410 for (int k=0; k < commandLength; k++) serial->putc(command[k]);
tobyspark 14:da403a01f9ef 411
tobyspark 14:da403a01f9ef 412 timer.reset();
tobyspark 14:da403a01f9ef 413
tobyspark 14:da403a01f9ef 414 char ackBuffer[4];
tobyspark 14:da403a01f9ef 415 int ackPos = 0;
tobyspark 14:da403a01f9ef 416 while (timer.read_ms() < 1000)
tobyspark 14:da403a01f9ef 417 {
tobyspark 14:da403a01f9ef 418 if (serial->readable()) ackBuffer[ackPos++] = serial->getc();
tobyspark 14:da403a01f9ef 419 if (ackPos == 4) break;
tobyspark 14:da403a01f9ef 420 }
tobyspark 16:ed8d08386034 421
tobyspark 14:da403a01f9ef 422 if (memcmp(ackBuffer, goodAck, ackLength) == 0)
tobyspark 14:da403a01f9ef 423 {
tobyspark 14:da403a01f9ef 424 success = true;
tobyspark 14:da403a01f9ef 425 }
tobyspark 14:da403a01f9ef 426 else
tobyspark 14:da403a01f9ef 427 {
tobyspark 14:da403a01f9ef 428 success = false;
tobyspark 14:da403a01f9ef 429 if (debug)
tobyspark 14:da403a01f9ef 430 {
tobyspark 14:da403a01f9ef 431 debug->printf("EDID Part write failed. Ack:");
tobyspark 14:da403a01f9ef 432 for (int k = 0; k < ackLength; k++) debug->printf(" %x", ackBuffer[k]);
tobyspark 14:da403a01f9ef 433 debug->printf("\r\n");
tobyspark 14:da403a01f9ef 434 }
tobyspark 14:da403a01f9ef 435 break;
tobyspark 14:da403a01f9ef 436 }
tobyspark 14:da403a01f9ef 437 }
tobyspark 14:da403a01f9ef 438
tobyspark 14:da403a01f9ef 439 return success;
tobyspark 14:da403a01f9ef 440 }