RS232 control for TVOne products
Diff: spk_tvone_mbed.cpp
- Revision:
- 14:da403a01f9ef
- Parent:
- 13:4d659b89a457
- Child:
- 16:ed8d08386034
--- a/spk_tvone_mbed.cpp Sat Nov 03 20:09:46 2012 +0000 +++ b/spk_tvone_mbed.cpp Mon Nov 05 19:35:17 2012 +0000 @@ -36,6 +36,11 @@ if (signErrorPin != NC) errorDO = new DigitalOut(signErrorPin); else errorDO = NULL; + timeoutCommandPeriod = 100; + minimumCommandPeriod = 30; + + timer.start(); + // Link up debug Serial object // Passing in shared object as debugging is shared between all DVI mixer functions debug = debugSerial; @@ -43,7 +48,7 @@ bool SPKTVOne::command(uint8_t channel, uint8_t window, int32_t func, int32_t payload) { - int ackBuff[standardAckLength]; + int ackBuff[standardAckLength] = {0}; bool success = command(writeCommandType, ackBuff, standardAckLength, channel, window, func, payload); @@ -67,7 +72,7 @@ bool SPKTVOne::readCommand(uint8_t channel, uint8_t window, int32_t func, int32_t &payload) { - int ackBuff[standardAckLength]; + int ackBuff[standardAckLength] = {0}; bool success = command(readCommandType, ackBuff, standardAckLength, channel, window, func, payload); @@ -84,15 +89,17 @@ } bool SPKTVOne::command(commandType readWrite, int* ackBuffer, int ackLength, uint8_t channel, uint8_t window, int32_t func, int32_t payload) -{ - char i; - +{ + if (debug) debug->printf("TVOne %s Channel: %#x, Window: %#x, Function: %#x Payload: %i \r\n", (readWrite == writeCommandType) ? "Write" : "Read", channel, window, func, payload); + // TASK: Sign start of serial command write if (writeDO) *writeDO = 1; - // TASK: discard anything waiting to be read - while (serial->readable()) { - serial->getc(); + // TASK: Prepare to issue command to the TVOne unit + // - discard anything waiting to be read in the return serial buffer + // - make sure we're past the minimum time between command sends as the unit can get overloaded + while (serial->readable() || timer.read_ms() < minimumCommandPeriod) { + if (serial->readable()) serial->getc(); } // TASK: Create the bytes of command @@ -121,12 +128,12 @@ if (readWrite == writeCommandType) { - for (i=0; i<8; i++) checksum += cmd[i]; + for (int 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); } if (readWrite == readCommandType) { - for (i=0; i<5; i++) checksum += cmd[i]; + for (int i=0; i<5; i++) checksum += cmd[i]; serial->printf("F%02X%02X%02X%02X%02X%02X\r", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], checksum); } @@ -138,36 +145,33 @@ // 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. - const int safePeriod = 100; - const int clearPeriod = 30; - - bool ackReceived = false; - bool success = false; - Timer timer; + bool success = false; + int ackPos = 0; + timer.reset(); - i = 0; - timer.start(); - while (timer.read_ms() < safePeriod) + while (timer.read_ms() < timeoutCommandPeriod) { - if (ackReceived && timer.read_ms() > clearPeriod) + if (serial->readable()) { - break; - } - if (!ackReceived && serial->readable()) - { - ackBuffer[i] = serial->getc(); - i++; - if (i == ackLength) + if (ackPos == 0) { - ackReceived = true; - if (ackBuffer[0] == 'F' && ackBuffer[1] == '4') // TVOne start of message, acknowledgement with no error, rest will be repeat of sent command - { - success = true; - } + ackBuffer[0] = serial->getc(); + if (ackBuffer[0] == 'F') ackPos = 1; + } + else + { + ackBuffer[ackPos] = serial->getc(); + ackPos++; + if (ackPos == ackLength) break; } } } - timer.stop(); + + // Return true if we got the no error acknowledgement from the unit. The rest of the ack will be verified elsewhere if needed. + if (ackPos > 2 && ackBuffer[1] == '4') + { + success = true; + } // TASK: Sign end of write @@ -181,13 +185,23 @@ } if (debug) { - debug->printf("TVOne serial error. Time from finishing writing command: %ims \r\n", timer.read_ms()); + debug->printf("TVOne serial error. Time from finishing writing command: %ims. Received %i ack chars:", timer.read_ms(), ackPos); + for (int i = 0; i<ackLength; i++) + { + debug->printf("%c", ackBuffer[i]); + } + debug->printf("\r\n"); } }; return success; } +int SPKTVOne::millisSinceLastCommandSent() +{ + return timer.read_ms(); +} + bool SPKTVOne::setCustomResolutions() { bool ok = true;; @@ -296,3 +310,89 @@ void SPKTVOne::signErrorOff() { *errorDO = 0; } + +bool SPKTVOne::uploadEDID(char* edidData, int edidDataLength, int edidSlotIndex) +{ + // TASK: Upload EDID + + // This command is reverse engineered from a VB snippet and RS232 comms logged between TVOne test app and unit + + // To write EDID, its broken into chunks and sent as a series of extra-long commands + // Command: 8 bytes of command (see code below) + 32 bytes of EDID payload + End byte + // Acknowledgement: 53 02 40 95 (Hex) + + if (debug) debug->printf("Upload EDID, length %i to index %i \r\n", edidDataLength, edidSlotIndex); + + bool success = false; + + int commandLength = 8+32+1; + int ackLength = 4; + char goodAck[] = {0x53, 0x02, 0x40, 0x95}; + + // We want to upload full EDID slot, ie. zero out to 256 even if edidData is only 128bytes. + for (int i=0; i<256; i=i+32) + { + char command[commandLength]; + + command[0] = 0x53; + command[1] = 0x27; + command[2] = 0x22; + command[3] = 0x7; + command[4] = edidSlotIndex; + command[5] = 0; + command[6] = i / 32; // ie. chunk index + command[7] = 0; + + for (int j=0; j<32; j++) + { + if (i+j < edidDataLength) + *(command+8+j) = edidData[i+j]; + else + *(command+8+j) = 0; + } + + command[8+32] = 0x3F; + + if (debug) + { + debug->printf("EDID command: "); + for (int k=0; k < commandLength; k++) debug->printf(" %x", command[k]); + debug->printf("\r\n"); + } + + while (serial->readable() || timer.read_ms() < 1000) + { + if (serial->readable()) serial->getc(); + } + + for (int k=0; k < commandLength; k++) serial->putc(command[k]); + + timer.reset(); + + char ackBuffer[4]; + int ackPos = 0; + while (timer.read_ms() < 1000) + { + if (serial->readable()) ackBuffer[ackPos++] = serial->getc(); + if (ackPos == 4) break; + } + + if (memcmp(ackBuffer, goodAck, ackLength) == 0) + { + success = true; + } + else + { + success = false; + if (debug) + { + debug->printf("EDID Part write failed. Ack:"); + for (int k = 0; k < ackLength; k++) debug->printf(" %x", ackBuffer[k]); + debug->printf("\r\n"); + } + break; + } + } + + return success; +}