RS232 control for TVOne products

Dependents:   SPK-DVIMXR

Committer:
tobyspark
Date:
Sun Oct 07 23:13:42 2012 +0000
Revision:
6:767acf32fed5
Parent:
5:4b0bf9a724a4
MBED Serial object is broken. Will hang if rx while tx.

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 0:533cfae24a1b 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 0:533cfae24a1b 39 // Link up debug Serial object
tobyspark 0:533cfae24a1b 40 // Passing in shared object as debugging is shared between all DVI mixer functions
tobyspark 0:533cfae24a1b 41 debug = debugSerial;
tobyspark 0:533cfae24a1b 42 }
tobyspark 0:533cfae24a1b 43
tobyspark 0:533cfae24a1b 44 bool SPKTVOne::command(uint8_t channel, uint8_t window, int32_t func, int32_t payload)
tobyspark 0:533cfae24a1b 45 {
tobyspark 5:4b0bf9a724a4 46 if (debug) debug->printf("TVOne command: IN. ");
tobyspark 5:4b0bf9a724a4 47
tobyspark 0:533cfae24a1b 48 char i;
tobyspark 6:767acf32fed5 49 Timer timer;
tobyspark 0:533cfae24a1b 50
tobyspark 0:533cfae24a1b 51 // TASK: Sign start of serial command write
tobyspark 0:533cfae24a1b 52 if (writeDO) *writeDO = 1;
tobyspark 5:4b0bf9a724a4 53
tobyspark 6:767acf32fed5 54 // TASK: Clear read buffer, and make sure we're not still receiving.
tobyspark 6:767acf32fed5 55
tobyspark 6:767acf32fed5 56 if (serial->readable())
tobyspark 5:4b0bf9a724a4 57 {
tobyspark 6:767acf32fed5 58 timer.start();
tobyspark 6:767acf32fed5 59 if (debug) debug->printf("Serial incoming: ");
tobyspark 6:767acf32fed5 60 while (timer.read_ms() < 30)
tobyspark 6:767acf32fed5 61 {
tobyspark 6:767acf32fed5 62 if (serial->readable())
tobyspark 6:767acf32fed5 63 {
tobyspark 6:767acf32fed5 64 if (debug) debug->printf("%c", (char)serial->getc());
tobyspark 6:767acf32fed5 65 else serial->getc();
tobyspark 6:767acf32fed5 66 timer.reset();
tobyspark 6:767acf32fed5 67 }
tobyspark 6:767acf32fed5 68 }
tobyspark 6:767acf32fed5 69 if (debug) debug->printf("\r\n");
tobyspark 6:767acf32fed5 70 timer.stop();
tobyspark 6:767acf32fed5 71 timer.reset();
tobyspark 0:533cfae24a1b 72 }
tobyspark 6:767acf32fed5 73
tobyspark 0:533cfae24a1b 74 // TASK: Create the bytes of command
tobyspark 0:533cfae24a1b 75
tobyspark 0:533cfae24a1b 76 uint8_t cmd[8];
tobyspark 0:533cfae24a1b 77 uint8_t checksum = 0;
tobyspark 0:533cfae24a1b 78
tobyspark 0:533cfae24a1b 79 // CMD
tobyspark 0:533cfae24a1b 80 cmd[0] = 1<<2; // write
tobyspark 0:533cfae24a1b 81 // CHA
tobyspark 0:533cfae24a1b 82 cmd[1] = channel;
tobyspark 0:533cfae24a1b 83 // WINDOW
tobyspark 0:533cfae24a1b 84 cmd[2] = window;
tobyspark 0:533cfae24a1b 85 // OUTPUT & FUNCTION
tobyspark 0:533cfae24a1b 86 // cmd[3] cmd[4]
tobyspark 0:533cfae24a1b 87 // output 0 = 0000xxx xxxxxxx
tobyspark 0:533cfae24a1b 88 // function = xxxXXXX XXXXXXX
tobyspark 0:533cfae24a1b 89 cmd[3] = func >> 8;
tobyspark 0:533cfae24a1b 90 cmd[4] = func & 0xFF;
tobyspark 0:533cfae24a1b 91 // PAYLOAD
tobyspark 0:533cfae24a1b 92 cmd[5] = (payload >> 16) & 0xFF;
tobyspark 0:533cfae24a1b 93 cmd[6] = (payload >> 8) & 0xFF;
tobyspark 0:533cfae24a1b 94 cmd[7] = payload & 0xFF;
tobyspark 0:533cfae24a1b 95
tobyspark 0:533cfae24a1b 96 // TASK: Write the bytes of command to RS232 as correctly packaged 20 characters of ASCII
tobyspark 0:533cfae24a1b 97
tobyspark 0:533cfae24a1b 98 for (i=0; i<8; i++)
tobyspark 0:533cfae24a1b 99 {
tobyspark 0:533cfae24a1b 100 checksum += cmd[i];
tobyspark 0:533cfae24a1b 101 }
tobyspark 0:533cfae24a1b 102
tobyspark 6:767acf32fed5 103 // MBED library sub-par: printf will hang on rx interrupt, have to sprintf and loop putc instead.
tobyspark 6:767acf32fed5 104 // FFS. Still not fixed.
tobyspark 6:767acf32fed5 105 char buffer[21];
tobyspark 6:767acf32fed5 106 sprintf(buffer,"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 6:767acf32fed5 107 for (i = 0; i < 20; i++)
tobyspark 6:767acf32fed5 108 {
tobyspark 6:767acf32fed5 109 __disable_irq();
tobyspark 6:767acf32fed5 110 serial->putc(buffer[i]);
tobyspark 6:767acf32fed5 111 __enable_irq();
tobyspark 6:767acf32fed5 112 }
tobyspark 6:767acf32fed5 113
tobyspark 0:533cfae24a1b 114 // TASK: Check the unit's return string, to enable return to main program as soon as unit is ready
tobyspark 0:533cfae24a1b 115
tobyspark 0:533cfae24a1b 116 // Handling the timing of this return is critical to effective control.
tobyspark 0:533cfae24a1b 117 // Returning the instant something is received back overloads the processor, as does anything until the full 20 char acknowledgement.
tobyspark 0:533cfae24a1b 118 // TVOne turn out to say that receipt of the ack doesn't guarantee the unit is ready for the next command.
tobyspark 0:533cfae24a1b 119 // According to the manual, operations typically take 30ms, and to simplify programming you can throttle commands to every 100ms.
tobyspark 0:533cfae24a1b 120 // 100ms is too slow for us. Going with returning after 30ms if we've received an acknowledgement, returning after 100ms otherwise.
tobyspark 0:533cfae24a1b 121
tobyspark 0:533cfae24a1b 122 int ack[20];
tobyspark 0:533cfae24a1b 123 int safePeriod = 100;
tobyspark 0:533cfae24a1b 124 int clearPeriod = 30;
tobyspark 0:533cfae24a1b 125 bool ackReceived = false;
tobyspark 0:533cfae24a1b 126 bool success = false;
tobyspark 0:533cfae24a1b 127
tobyspark 6:767acf32fed5 128 timer.reset();
tobyspark 0:533cfae24a1b 129 timer.start();
tobyspark 0:533cfae24a1b 130 i = 0;
tobyspark 0:533cfae24a1b 131 while (timer.read_ms() < safePeriod) {
tobyspark 0:533cfae24a1b 132 if (serial->readable())
tobyspark 0:533cfae24a1b 133 {
tobyspark 0:533cfae24a1b 134 ack[i] = serial->getc();
tobyspark 0:533cfae24a1b 135 i++;
tobyspark 0:533cfae24a1b 136 if (i >= 20)
tobyspark 0:533cfae24a1b 137 {
tobyspark 0:533cfae24a1b 138 ackReceived = true;
tobyspark 0:533cfae24a1b 139 if (ack[0] == 'F' && ack[1] == '4') // TVOne start of message, acknowledgement with no error, rest will be repeat of sent command
tobyspark 0:533cfae24a1b 140 {
tobyspark 0:533cfae24a1b 141 success = true;
tobyspark 0:533cfae24a1b 142 }
tobyspark 0:533cfae24a1b 143 }
tobyspark 0:533cfae24a1b 144 }
tobyspark 0:533cfae24a1b 145 if (ackReceived && (timer.read_ms() > clearPeriod)) break;
tobyspark 0:533cfae24a1b 146 }
tobyspark 0:533cfae24a1b 147 timer.stop();
tobyspark 0:533cfae24a1b 148
tobyspark 0:533cfae24a1b 149 // TASK: Sign end of write
tobyspark 5:4b0bf9a724a4 150
tobyspark 0:533cfae24a1b 151 if (writeDO) *writeDO = 0;
tobyspark 0:533cfae24a1b 152
tobyspark 0:533cfae24a1b 153 if (!success) {
tobyspark 0:533cfae24a1b 154 if (errorDO) {
tobyspark 0:533cfae24a1b 155 signErrorTimeout.detach();
tobyspark 0:533cfae24a1b 156 signErrorTimeout.attach(this, &SPKTVOne::signErrorOff, 0.25);
tobyspark 0:533cfae24a1b 157 *errorDO = 1;
tobyspark 0:533cfae24a1b 158 }
tobyspark 0:533cfae24a1b 159
tobyspark 0:533cfae24a1b 160 if (debug) {
tobyspark 0:533cfae24a1b 161 debug->printf("Serial command write error. Time from write finish: %ims \r\n", timer.read_ms());
tobyspark 0:533cfae24a1b 162 }
tobyspark 0:533cfae24a1b 163 };
tobyspark 0:533cfae24a1b 164
tobyspark 5:4b0bf9a724a4 165 if (debug) debug->printf("OUT. Success = %s \r\n", success ? "true" : "false");
tobyspark 6:767acf32fed5 166
tobyspark 0:533cfae24a1b 167 return success;
tobyspark 0:533cfae24a1b 168 }
tobyspark 0:533cfae24a1b 169
tobyspark 0:533cfae24a1b 170 void SPKTVOne::setCustomResolutions()
tobyspark 0:533cfae24a1b 171 {
tobyspark 6:767acf32fed5 172 int32_t unlock = 0;
tobyspark 6:767acf32fed5 173 int32_t lock = 1;
tobyspark 6:767acf32fed5 174
tobyspark 6:767acf32fed5 175 // Lock front panel
tobyspark 6:767acf32fed5 176 command(0, 0, kTV1FunctionAdjustFrontPanelLock, lock);
tobyspark 6:767acf32fed5 177
tobyspark 6:767acf32fed5 178 // Set resolutions
tobyspark 0:533cfae24a1b 179 set1920x480(kTV1ResolutionTripleHeadVGAp60);
tobyspark 0:533cfae24a1b 180 set1600x600(kTV1ResolutionDualHeadSVGAp60);
tobyspark 2:af9e9ab63b23 181 set2048x768(kTV1ResolutionDualHeadXGAp60);
tobyspark 6:767acf32fed5 182
tobyspark 6:767acf32fed5 183 // Unlock front panel
tobyspark 6:767acf32fed5 184 command(0, 0, kTV1FunctionAdjustFrontPanelLock, unlock);
tobyspark 0:533cfae24a1b 185 }
tobyspark 0:533cfae24a1b 186
tobyspark 3:03e7e7b7a870 187 bool SPKTVOne::setHDCPOn(bool state)
tobyspark 0:533cfae24a1b 188 {
tobyspark 0:533cfae24a1b 189 bool ok = false;
tobyspark 0:533cfae24a1b 190
tobyspark 0:533cfae24a1b 191 // Turn HDCP off on the output
tobyspark 3:03e7e7b7a870 192 ok = command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsHDCPRequired, state);
tobyspark 3:03e7e7b7a870 193 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsHDCPStatus, state);
tobyspark 0:533cfae24a1b 194 // Likewise on inputs A and B
tobyspark 3:03e7e7b7a870 195 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPAdvertize, state);
tobyspark 3:03e7e7b7a870 196 ok = ok && command(0, kTV1WindowIDB, kTV1FunctionAdjustSourceHDCPAdvertize, state);
tobyspark 3:03e7e7b7a870 197 ok = ok && command(0, kTV1WindowIDA, kTV1FunctionAdjustSourceHDCPStatus, state);
tobyspark 3:03e7e7b7a870 198 ok = ok && command(0, kTV1WindowIDB, kTV1FunctionAdjustSourceHDCPStatus, state);
tobyspark 0:533cfae24a1b 199
tobyspark 0:533cfae24a1b 200 return ok;
tobyspark 0:533cfae24a1b 201 }
tobyspark 0:533cfae24a1b 202
tobyspark 0:533cfae24a1b 203 void SPKTVOne::set1920x480(int resStoreNumber)
tobyspark 0:533cfae24a1b 204 {
tobyspark 0:533cfae24a1b 205 command(0, 0, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 0:533cfae24a1b 206 command(0, 0, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 0:533cfae24a1b 207 command(0, 0, kTV1FunctionAdjustResolutionFreqCoarseH, 31400);
tobyspark 0:533cfae24a1b 208 command(0, 0, kTV1FunctionAdjustResolutionFreqFineH, 31475);
tobyspark 0:533cfae24a1b 209 command(0, 0, kTV1FunctionAdjustResolutionActiveH, 1920);
tobyspark 0:533cfae24a1b 210 command(0, 0, kTV1FunctionAdjustResolutionActiveV, 480);
tobyspark 0:533cfae24a1b 211 command(0, 0, kTV1FunctionAdjustResolutionStartH, 192);
tobyspark 0:533cfae24a1b 212 command(0, 0, kTV1FunctionAdjustResolutionStartV, 32);
tobyspark 0:533cfae24a1b 213 command(0, 0, kTV1FunctionAdjustResolutionCLKS, 2400);
tobyspark 0:533cfae24a1b 214 command(0, 0, kTV1FunctionAdjustResolutionLines, 525);
tobyspark 0:533cfae24a1b 215 command(0, 0, kTV1FunctionAdjustResolutionSyncH, 240);
tobyspark 0:533cfae24a1b 216 command(0, 0, kTV1FunctionAdjustResolutionSyncV, 5);
tobyspark 0:533cfae24a1b 217 command(0, 0, kTV1FunctionAdjustResolutionSyncPolarity, 0);
tobyspark 0:533cfae24a1b 218 }
tobyspark 0:533cfae24a1b 219
tobyspark 0:533cfae24a1b 220 void SPKTVOne::set1600x600(int resStoreNumber)
tobyspark 0:533cfae24a1b 221 {
tobyspark 0:533cfae24a1b 222 command(0, 0, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 0:533cfae24a1b 223 command(0, 0, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 0:533cfae24a1b 224 command(0, 0, kTV1FunctionAdjustResolutionFreqCoarseH, 37879);
tobyspark 0:533cfae24a1b 225 command(0, 0, kTV1FunctionAdjustResolutionFreqFineH, 37879);
tobyspark 0:533cfae24a1b 226 command(0, 0, kTV1FunctionAdjustResolutionActiveH, 1600);
tobyspark 0:533cfae24a1b 227 command(0, 0, kTV1FunctionAdjustResolutionActiveV, 600);
tobyspark 0:533cfae24a1b 228 command(0, 0, kTV1FunctionAdjustResolutionStartH, 160);
tobyspark 0:533cfae24a1b 229 command(0, 0, kTV1FunctionAdjustResolutionStartV, 1);
tobyspark 0:533cfae24a1b 230 command(0, 0, kTV1FunctionAdjustResolutionCLKS, 2112);
tobyspark 0:533cfae24a1b 231 command(0, 0, kTV1FunctionAdjustResolutionLines, 628);
tobyspark 0:533cfae24a1b 232 command(0, 0, kTV1FunctionAdjustResolutionSyncH, 192);
tobyspark 0:533cfae24a1b 233 command(0, 0, kTV1FunctionAdjustResolutionSyncV, 14);
tobyspark 0:533cfae24a1b 234 command(0, 0, kTV1FunctionAdjustResolutionSyncPolarity, 0);
tobyspark 0:533cfae24a1b 235 }
tobyspark 0:533cfae24a1b 236
tobyspark 2:af9e9ab63b23 237 void SPKTVOne::set2048x768(int resStoreNumber)
tobyspark 2:af9e9ab63b23 238 {
tobyspark 2:af9e9ab63b23 239 command(0, 0, kTV1FunctionAdjustResolutionImageToAdjust, resStoreNumber);
tobyspark 2:af9e9ab63b23 240 command(0, 0, kTV1FunctionAdjustResolutionInterlaced, 0);
tobyspark 2:af9e9ab63b23 241 command(0, 0, kTV1FunctionAdjustResolutionFreqCoarseH, 48363);
tobyspark 2:af9e9ab63b23 242 command(0, 0, kTV1FunctionAdjustResolutionFreqFineH, 48363);
tobyspark 2:af9e9ab63b23 243 command(0, 0, kTV1FunctionAdjustResolutionActiveH, 2048);
tobyspark 2:af9e9ab63b23 244 command(0, 0, kTV1FunctionAdjustResolutionActiveV, 768);
tobyspark 2:af9e9ab63b23 245 command(0, 0, kTV1FunctionAdjustResolutionStartH, 368);
tobyspark 2:af9e9ab63b23 246 command(0, 0, kTV1FunctionAdjustResolutionStartV, 24);
tobyspark 2:af9e9ab63b23 247 command(0, 0, kTV1FunctionAdjustResolutionCLKS, 2688);
tobyspark 2:af9e9ab63b23 248 command(0, 0, kTV1FunctionAdjustResolutionLines, 806);
tobyspark 2:af9e9ab63b23 249 command(0, 0, kTV1FunctionAdjustResolutionSyncH, 224);
tobyspark 2:af9e9ab63b23 250 command(0, 0, kTV1FunctionAdjustResolutionSyncV, 11);
tobyspark 2:af9e9ab63b23 251 command(0, 0, kTV1FunctionAdjustResolutionSyncPolarity, 0);
tobyspark 2:af9e9ab63b23 252 }
tobyspark 2:af9e9ab63b23 253
tobyspark 0:533cfae24a1b 254 void SPKTVOne::signErrorOff() {
tobyspark 0:533cfae24a1b 255 *errorDO = 0;
tobyspark 0:533cfae24a1b 256 }