/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.driver.video.ddc;
/**
* Class used to read DDC1 data from a display device
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public class DDC1Reader implements EDIDConstants {
private final DisplayDataChannelAPI api;
/**
* Create a new instance
*
* @param api
*/
public DDC1Reader(DisplayDataChannelAPI api) {
this.api = api;
}
/**
* Read a DDC1 EDID packet
*
* @return The parsed EDID packet
* @throws DDC1NoSignalException No DDC1 signal is found, the monitor does
* not send it, or the videocard does not support it.
* @throws DDC1ParseException No valid EDID datablock was found. This can be
* the result of a small hickup in the connection, so is does
* not hurd to try it again.
*/
public EDID read() throws DDC1NoSignalException, DDC1ParseException {
api.setupDDC1();
try {
testSignal();
final boolean[] bits = readBits();
final int start = findStartBit(bits);
final int length = bits.length;
final byte[] data = new byte[EDID1_LEN];
// Convert bits to bytes
int idx = start;
for (int i = 0; i < EDID1_LEN; i++) {
int v = 0;
for (int j = 0; j < 8; j++) {
v = v << 1;
if (bits[idx++]) {
v |= 0x01;
}
if (idx == length) {
idx = 0;
}
}
data[i] = (byte) v;
idx++;
if (idx == length) {
idx = 0;
}
}
return new EDID(resort(data));
} finally {
api.closeDDC1();
}
}
/**
* Read a complete packet of EDID1 bits
*
* @return
*/
private boolean[] readBits() {
final int max = EDID1_LEN * BITS_PER_BYTE;
final boolean[] bits = new boolean[max];
for (int i = 0; i < max; i++) {
bits[i] = api.getDDC1Bit();
}
return bits;
}
/**
* Find the start bit
*
* @param bits
* @return
*/
private int findStartBit(boolean[] bits) throws DDC1ParseException {
final boolean[] comp = new boolean[BITS_PER_BYTE];
final boolean[] test = new boolean[BITS_PER_BYTE];
int idx = 0;
for (int i = 0; i < 9; i++) {
comp[i] = bits[idx++];
test[i] = true;
}
for (int i = 0; i < 127; i++) {
for (int j = 0; j < 9; j++) {
test[j] = test[j] & !(comp[j] ^ bits[idx++]);
}
}
for (int i = 0; i < 9; i++) {
if (test[i]) {
return (i + 1);
}
}
throw new DDC1ParseException("Start bit not found");
}
private byte[] resort(byte[] data) throws DDC1ParseException {
final int max = data.length;
final byte[] dbldata = new byte[max * 2];
System.arraycopy(data, 0, dbldata, 0, max);
System.arraycopy(data, 0, dbldata, max, max);
final int hdrmax = HEADER_SIGNATURE.length;
for (int i = 0; i < max; i++) {
int j;
for (j = 0; j < hdrmax; j++) {
if (data[i + j] != HEADER_SIGNATURE[j]) {
break;
}
}
if (j == hdrmax) {
// We found the header signature at index i
final byte[] result = new byte[max];
System.arraycopy(dbldata, i, result, 0, max);
return result;
}
}
throw new DDC1ParseException("Header not found");
}
/**
* Test for the presence of a DDC1 signal
*
* @throws DDC1NoSignalException
*/
private void testSignal() throws DDC1NoSignalException {
final boolean old = api.getDDC1Bit();
for (int count = HEADER * BITS_PER_BYTE; count > 0; count--) {
if (old != api.getDDC1Bit()) {
return;
}
}
throw new DDC1NoSignalException("No DDC1 signal detected");
}
}