/*
 * Copyright (C) 2014 Satoshi Noguchi
 * Copyright (C) 2014 Synaptics Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <alloca.h>
#include <time.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>

#include "testutil.h"
#include "f54test.h"
#include "rmidevice.h"
#include "display.h"

/* Most recent device status event */
#define RMI_F01_STATUS_CODE(status)		((status) & 0x0f)
/* Indicates that flash programming is enabled (bootloader mode). */
#define RMI_F01_STATUS_BOOTLOADER(status)	(!!((status) & 0x40))

/*
 * Sleep mode controls power management on the device and affects all
 * functions of the device.
 */
#define RMI_F01_CTRL0_SLEEP_MODE_MASK	0x03

#define RMI_SLEEP_MODE_NORMAL		0x00
#define RMI_SLEEP_MODE_SENSOR_SLEEP	0x01
#define RMI_SLEEP_MODE_RESERVED0	0x02
#define RMI_SLEEP_MODE_RESERVED1	0x03

/*
 * This bit disables whatever sleep mode may be selected by the sleep_mode
 * field and forces the device to run at full power without sleeping.
 */
#define RMI_F01_CRTL0_NOSLEEP_BIT	(1 << 2)

F54Test::~F54Test()
{
	if (m_txAssignment != NULL) delete [] m_txAssignment;
	if (m_rxAssignment != NULL) delete [] m_rxAssignment;
}

int F54Test::Prepare(f54_report_types reportType)
{
	int retval;
	unsigned char data;

	retval = FindTestFunctions();
	if (retval != TEST_SUCCESS)
		return retval;

	retval = m_device.QueryBasicProperties();
	if (retval < 0)
		return TEST_FAIL_QUERY_BASIC_PROPERTIES;

	retval = ReadF54Queries();
	if (retval != TEST_SUCCESS)
		return retval;

	retval = SetupF54Controls();
	if (retval != TEST_SUCCESS)
		return retval;

	retval = ReadF55Queries();
	if (retval != TEST_SUCCESS)
		return retval;

	retval = SetF54ReportType(reportType);
	if (retval != TEST_SUCCESS)
		return retval;

	retval = SetF54Interrupt();
	if (retval != TEST_SUCCESS)
		return retval;

	data = (unsigned char)m_reportType;
	retval = m_device.Write(m_f54.GetDataBase(), &data, 1);
	if (retval < 0)
		return retval;

	return TEST_SUCCESS;
}

int F54Test::Run()
{
	int retval;
	unsigned char command;

	command = (unsigned char)COMMAND_GET_REPORT;
	retval = DoF54Command(command);
	if (retval != TEST_SUCCESS)
		return retval;

	retval = ReadF54Report();
	if (retval != TEST_SUCCESS)
		return retval;

	retval = ShowF54Report();
	if (retval != TEST_SUCCESS)
		return retval;

	return TEST_SUCCESS;
}

int F54Test::SetF54ReportType(f54_report_types report_type)
{
	switch (report_type) {
	case F54_8BIT_IMAGE:
	case F54_16BIT_IMAGE:
	case F54_RAW_16BIT_IMAGE:
	case F54_HIGH_RESISTANCE:
	case F54_TX_TO_TX_SHORTS:
	case F54_RX_TO_RX_SHORTS_1:
	case F54_TRUE_BASELINE:
	case F54_FULL_RAW_CAP_MIN_MAX:
	case F54_RX_OPENS_1:
	case F54_TX_OPENS:
	case F54_TX_TO_GND_SHORTS:
	case F54_RX_TO_RX_SHORTS_2:
	case F54_RX_OPENS_2:
	case F54_FULL_RAW_CAP:
	case F54_FULL_RAW_CAP_NO_RX_COUPLING:
	case F54_SENSOR_SPEED:
	case F54_ADC_RANGE:
	case F54_TRX_OPENS:
	case F54_TRX_TO_GND_SHORTS:
	case F54_TRX_SHORTS:
	case F54_ABS_RAW_CAP:
	case F54_ABS_DELTA_CAP:
		m_reportType = report_type;
		return SetF54ReportSize(report_type);
	default:
		m_reportType = INVALID_REPORT_TYPE;
		m_reportSize = 0;
		return TEST_FAIL_INVALID_PARAMETER;
	}
}

int F54Test::SetF54ReportSize(f54_report_types report_type)
{
	int retval;
	unsigned char tx = m_txAssigned;
	unsigned char rx = m_rxAssigned;

	switch (report_type) {
	case F54_8BIT_IMAGE:
		m_reportSize = tx * rx;
		break;
	case F54_16BIT_IMAGE:
	case F54_RAW_16BIT_IMAGE:
	case F54_TRUE_BASELINE:
	case F54_FULL_RAW_CAP:
	case F54_FULL_RAW_CAP_NO_RX_COUPLING:
	case F54_SENSOR_SPEED:
		m_reportSize = 2 * tx * rx;
		break;
	case F54_HIGH_RESISTANCE:
		m_reportSize = HIGH_RESISTANCE_DATA_SIZE;
		break;
	case F54_TX_TO_TX_SHORTS:
	case F54_TX_OPENS:
	case F54_TX_TO_GND_SHORTS:
		m_reportSize = (tx + 7) / 8;
		break;
	case F54_RX_TO_RX_SHORTS_1:
	case F54_RX_OPENS_1:
		if (rx < tx)
			m_reportSize = 2 * rx * rx;
		else
			m_reportSize = 2 * tx * rx;
		break;
	case F54_FULL_RAW_CAP_MIN_MAX:
		m_reportSize = FULL_RAW_CAP_MIN_MAX_DATA_SIZE;
		break;
	case F54_RX_TO_RX_SHORTS_2:
	case F54_RX_OPENS_2:
		if (rx <= tx)
			m_reportSize = 0;
		else
			m_reportSize = 2 * rx * (rx - tx);
		break;
	case F54_ADC_RANGE:
		if (m_f54Query.has_signal_clarity) {

			retval = m_device.Read(m_f54Control.reg_41.address,
					m_f54Control.reg_41.data,
					sizeof(m_f54Control.reg_41.data));
			if (retval < 0) {
				m_reportSize = 0;
				break;
			}
			if (m_f54Control.reg_41.no_signal_clarity) {
				if (tx % 4)
					tx += 4 - (tx % 4);
			}
		}
		m_reportSize = 2 * tx * rx;
		break;
	case F54_TRX_OPENS:
	case F54_TRX_TO_GND_SHORTS:
	case F54_TRX_SHORTS:
		m_reportSize = TRX_OPEN_SHORT_DATA_SIZE;
		break;
	case F54_ABS_RAW_CAP:
	case F54_ABS_DELTA_CAP:
		m_reportSize = 4 * (tx + rx);
		break;
	default:
		m_reportSize = 0;
		return TEST_FAIL_INVALID_PARAMETER;
	}

	return TEST_SUCCESS;
}

int F54Test::FindTestFunctions()
{
	if (0 > m_device.ScanPDT(0x00, 10))
		return TEST_FAIL_SCAN_PDT;

	if (!m_device.GetFunction(m_f01, 0x01))
		return TEST_FAIL_NO_FUNCTION_01;

	if (!m_device.GetFunction(m_f54, 0x54))
		return TEST_FAIL_NO_FUNCTION_54;

	if (!m_device.GetFunction(m_f55, 0x55))
		return TEST_FAIL_NO_FUNCTION_55;

	return TEST_SUCCESS;
}

int F54Test::ReadF54Queries()
{
	int retval;
	unsigned short query_addr = m_f54.GetQueryBase();
	unsigned char offset;

	retval = m_device.Read(query_addr,
			       m_f54Query.data,
			       sizeof(m_f54Query.data));
	if (retval < 0)
		return retval;

	offset = sizeof(m_f54Query.data);

	/* query 12 */
	if (m_f54Query.has_sense_frequency_control == 0)
		offset -= 1;

	/* query 13 */
	if (m_f54Query.has_query13) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_13.data,
				sizeof(m_f54Query_13.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 14 */
	if ((m_f54Query.has_query13) && (m_f54Query_13.has_ctrl87))
		offset += 1;

	/* query 15 */
	if (m_f54Query.has_query15) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_15.data,
				sizeof(m_f54Query_15.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 16 */
	if ((m_f54Query.has_query15) && (m_f54Query_15.has_query16)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_16.data,
				sizeof(m_f54Query_16.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 17 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query16) &&
			(m_f54Query_16.has_query17))
		offset += 1;

	/* query 18 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query16) &&
			(m_f54Query_16.has_ctrl94_query18))
		offset += 1;

	/* query 19 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query16) &&
			(m_f54Query_16.has_ctrl95_query19))
		offset += 1;

	/* query 20 */
	if ((m_f54Query.has_query15) && (m_f54Query_15.has_query20))
		offset += 1;

	/* query 21 */
	if ((m_f54Query.has_query15) && (m_f54Query_15.has_query21)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_21.data,
				sizeof(m_f54Query_21.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 22 */
	if ((m_f54Query.has_query15) && (m_f54Query_15.has_query22)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_22.data,
				sizeof(m_f54Query_22.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 23 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query22) &&
			(m_f54Query_22.has_query23)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_23.data,
				sizeof(m_f54Query_23.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 24 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query21) &&
			(m_f54Query_21.has_query24_data18))
		offset += 1;

	/* query 25 */
	if ((m_f54Query.has_query15) && (m_f54Query_15.has_query25)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_25.data,
				sizeof(m_f54Query_25.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 26 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query22) &&
			(m_f54Query_22.has_ctrl103_query26))
		offset += 1;

	/* query 27 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_27.data,
				sizeof(m_f54Query_27.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 28 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query22) &&
			(m_f54Query_22.has_query28))
		offset += 1;

	/* query 29 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_29.data,
				sizeof(m_f54Query_29.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 30 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_30.data,
				sizeof(m_f54Query_30.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 31 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_ctrl122_query31))
		offset += 1;

	/* query 32 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_32.data,
				sizeof(m_f54Query_32.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 33 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_33.data,
				sizeof(m_f54Query_33.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 34 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query34))
		offset += 1;

	/* query 35 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query35)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_35.data,
				sizeof(m_f54Query_35.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 36 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_36.data,
				sizeof(m_f54Query_36.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	/* query 37 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_query37))
		offset += 1;

	/* query 38 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_query38)) {
		retval = m_device.Read(query_addr + offset,
				m_f54Query_38.data,
				sizeof(m_f54Query_38.data));
		if (retval < 0)
			return retval;
		offset += 1;
	}

	return TEST_SUCCESS;;
}

int F54Test::SetupF54Controls()
{
	unsigned char length;
	unsigned char num_of_sensing_freqs;
	unsigned short reg_addr = m_f54.GetControlBase();

	num_of_sensing_freqs = m_f54Query.number_of_sensing_frequencies;

	/* control 0 */
	reg_addr += CONTROL_0_SIZE;

	/* control 1 */
	if ((m_f54Query.touch_controller_family == 0) ||
			(m_f54Query.touch_controller_family == 1))
		reg_addr += CONTROL_1_SIZE;

	/* control 2 */
	reg_addr += CONTROL_2_SIZE;

	/* control 3 */
	if (m_f54Query.has_pixel_touch_threshold_adjustment == 1)
		reg_addr += CONTROL_3_SIZE;

	/* controls 4 5 6 */
	if ((m_f54Query.touch_controller_family == 0) ||
			(m_f54Query.touch_controller_family == 1))
		reg_addr += CONTROL_4_6_SIZE;

	/* control 7 */
	if (m_f54Query.touch_controller_family == 1) {
		m_f54Control.reg_7.address = reg_addr;
		reg_addr += CONTROL_7_SIZE;
	}

	/* controls 8 9 */
	if ((m_f54Query.touch_controller_family == 0) ||
			(m_f54Query.touch_controller_family == 1))
		reg_addr += CONTROL_8_9_SIZE;

	/* control 10 */
	if (m_f54Query.has_interference_metric == 1)
		reg_addr += CONTROL_10_SIZE;

	/* control 11 */
	if (m_f54Query.has_ctrl11 == 1)
		reg_addr += CONTROL_11_SIZE;

	/* controls 12 13 */
	if (m_f54Query.has_relaxation_control == 1)
		reg_addr += CONTROL_12_13_SIZE;

	/* controls 14 15 16 */
	if (m_f54Query.has_sensor_assignment == 1) {
		reg_addr += CONTROL_14_SIZE;
		reg_addr += CONTROL_15_SIZE * m_f54Query.num_of_rx_electrodes;
		reg_addr += CONTROL_16_SIZE * m_f54Query.num_of_tx_electrodes;
	}

	/* controls 17 18 19 */
	if (m_f54Query.has_sense_frequency_control == 1) {
		reg_addr += CONTROL_17_SIZE * num_of_sensing_freqs;
		reg_addr += CONTROL_18_SIZE * num_of_sensing_freqs;
		reg_addr += CONTROL_19_SIZE * num_of_sensing_freqs;
	}

	/* control 20 */
	reg_addr += CONTROL_20_SIZE;

	/* control 21 */
	if (m_f54Query.has_sense_frequency_control == 1)
		reg_addr += CONTROL_21_SIZE;

	/* controls 22 23 24 25 26 */
	if (m_f54Query.has_firmware_noise_mitigation == 1)
		reg_addr += CONTROL_22_26_SIZE;

	/* control 27 */
	if (m_f54Query.has_iir_filter == 1)
		reg_addr += CONTROL_27_SIZE;

	/* control 28 */
	if (m_f54Query.has_firmware_noise_mitigation == 1)
		reg_addr += CONTROL_28_SIZE;

	/* control 29 */
	if (m_f54Query.has_cmn_removal == 1)
		reg_addr += CONTROL_29_SIZE;

	/* control 30 */
	if (m_f54Query.has_cmn_maximum == 1)
		reg_addr += CONTROL_30_SIZE;

	/* control 31 */
	if (m_f54Query.has_touch_hysteresis == 1)
		reg_addr += CONTROL_31_SIZE;

	/* controls 32 33 34 35 */
	if (m_f54Query.has_edge_compensation == 1)
		reg_addr += CONTROL_32_35_SIZE;

	/* control 36 */
	if ((m_f54Query.curve_compensation_mode == 1) ||
			(m_f54Query.curve_compensation_mode == 2)) {
		if (m_f54Query.curve_compensation_mode == 1) {
			length = std::max(m_f54Query.num_of_rx_electrodes,
					m_f54Query.num_of_tx_electrodes);
		} else if (m_f54Query.curve_compensation_mode == 2) {
			length = m_f54Query.num_of_rx_electrodes;
		}
		reg_addr += CONTROL_36_SIZE * length;
	}

	/* control 37 */
	if (m_f54Query.curve_compensation_mode == 2)
		reg_addr += CONTROL_37_SIZE * m_f54Query.num_of_tx_electrodes;

	/* controls 38 39 40 */
	if (m_f54Query.has_per_frequency_noise_control == 1) {
		reg_addr += CONTROL_38_SIZE * num_of_sensing_freqs;
		reg_addr += CONTROL_39_SIZE * num_of_sensing_freqs;
		reg_addr += CONTROL_40_SIZE * num_of_sensing_freqs;
	}

	/* control 41 */
	if (m_f54Query.has_signal_clarity == 1) {
		m_f54Control.reg_41.address = reg_addr;
		reg_addr += CONTROL_41_SIZE;
	}

	/* control 42 */
	if (m_f54Query.has_variance_metric == 1)
		reg_addr += CONTROL_42_SIZE;

	/* controls 43 44 45 46 47 48 49 50 51 52 53 54 */
	if (m_f54Query.has_multi_metric_state_machine == 1)
		reg_addr += CONTROL_43_54_SIZE;

	/* controls 55 56 */
	if (m_f54Query.has_0d_relaxation_control == 1)
		reg_addr += CONTROL_55_56_SIZE;

	/* control 57 */
	if (m_f54Query.has_0d_acquisition_control == 1) {
		m_f54Control.reg_57.address = reg_addr;
		reg_addr += CONTROL_57_SIZE;
	}

	/* control 58 */
	if (m_f54Query.has_0d_acquisition_control == 1)
		reg_addr += CONTROL_58_SIZE;

	/* control 59 */
	if (m_f54Query.has_h_blank == 1)
		reg_addr += CONTROL_59_SIZE;

	/* controls 60 61 62 */
	if ((m_f54Query.has_h_blank == 1) ||
			(m_f54Query.has_v_blank == 1) ||
			(m_f54Query.has_long_h_blank == 1))
		reg_addr += CONTROL_60_62_SIZE;

	/* control 63 */
	if ((m_f54Query.has_h_blank == 1) ||
			(m_f54Query.has_v_blank == 1) ||
			(m_f54Query.has_long_h_blank == 1) ||
			(m_f54Query.has_slew_metric == 1) ||
			(m_f54Query.has_slew_option == 1) ||
			(m_f54Query.has_noise_mitigation2 == 1))
		reg_addr += CONTROL_63_SIZE;

	/* controls 64 65 66 67 */
	if (m_f54Query.has_h_blank == 1)
		reg_addr += CONTROL_64_67_SIZE * 7;
	else if ((m_f54Query.has_v_blank == 1) ||
			(m_f54Query.has_long_h_blank == 1))
		reg_addr += CONTROL_64_67_SIZE;

	/* controls 68 69 70 71 72 73 */
	if ((m_f54Query.has_h_blank == 1) ||
			(m_f54Query.has_v_blank == 1) ||
			(m_f54Query.has_long_h_blank == 1))
		reg_addr += CONTROL_68_73_SIZE;

	/* control 74 */
	if (m_f54Query.has_slew_metric == 1)
		reg_addr += CONTROL_74_SIZE;

	/* control 75 */
	if (m_f54Query.has_enhanced_stretch == 1)
		reg_addr += CONTROL_75_SIZE * num_of_sensing_freqs;

	/* control 76 */
	if (m_f54Query.has_startup_fast_relaxation == 1)
		reg_addr += CONTROL_76_SIZE;

	/* controls 77 78 */
	if (m_f54Query.has_esd_control == 1)
		reg_addr += CONTROL_77_78_SIZE;

	/* controls 79 80 81 82 83 */
	if (m_f54Query.has_noise_mitigation2 == 1)
		reg_addr += CONTROL_79_83_SIZE;

	/* controls 84 85 */
	if (m_f54Query.has_energy_ratio_relaxation == 1)
		reg_addr += CONTROL_84_85_SIZE;

	/* control 86 */
	if ((m_f54Query.has_query13 == 1) && (m_f54Query_13.has_ctrl86 == 1))
		reg_addr += CONTROL_86_SIZE;

	/* control 87 */
	if ((m_f54Query.has_query13 == 1) && (m_f54Query_13.has_ctrl87 == 1))
		reg_addr += CONTROL_87_SIZE;

	/* control 88 */
	if (m_f54Query.has_ctrl88 == 1) {
		m_f54Control.reg_88.address = reg_addr;
		reg_addr += CONTROL_88_SIZE;
	}

	/* control 89 */
	if ((m_f54Query.has_query13 == 1) &&
			(m_f54Query_13.has_cidim == 1 ||
			m_f54Query_13.has_noise_mitigation_enhancement ||
			m_f54Query_13.has_rail_im))
		reg_addr += CONTROL_89_SIZE;

	/* control 90 */
	if ((m_f54Query.has_query15) && (m_f54Query_15.has_ctrl90))
		reg_addr += CONTROL_90_SIZE;

	/* control 91 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query21) &&
			(m_f54Query_21.has_ctrl91))
		reg_addr += CONTROL_91_SIZE;

	/* control 92 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query16) &&
			(m_f54Query_16.has_ctrl92))
		reg_addr += CONTROL_92_SIZE;

	/* control 93 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query16) &&
			(m_f54Query_16.has_ctrl93))
		reg_addr += CONTROL_93_SIZE;

	/* control 94 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query16) &&
			(m_f54Query_16.has_ctrl94_query18))
		reg_addr += CONTROL_94_SIZE;

	/* control 95 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query16) &&
			(m_f54Query_16.has_ctrl95_query19))
		reg_addr += CONTROL_95_SIZE;

	/* control 96 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query21) &&
			(m_f54Query_21.has_ctrl96))
		reg_addr += CONTROL_96_SIZE;

	/* control 97 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query21) &&
			(m_f54Query_21.has_ctrl97))
		reg_addr += CONTROL_97_SIZE;

	/* control 98 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query21) &&
			(m_f54Query_21.has_ctrl98))
		reg_addr += CONTROL_98_SIZE;

	/* control 99 */
	if (m_f54Query.touch_controller_family == 2)
		reg_addr += CONTROL_99_SIZE;

	/* control 100 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query16) &&
			(m_f54Query_16.has_ctrl100))
		reg_addr += CONTROL_100_SIZE;

	/* control 101 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query22) &&
			(m_f54Query_22.has_ctrl101))
		reg_addr += CONTROL_101_SIZE;


	/* control 102 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query22) &&
			(m_f54Query_22.has_query23) &&
			(m_f54Query_23.has_ctrl102))
		reg_addr += CONTROL_102_SIZE;

	/* control 103 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query22) &&
			(m_f54Query_22.has_ctrl103_query26))
		reg_addr += CONTROL_103_SIZE;

	/* control 104 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query22) &&
			(m_f54Query_22.has_ctrl104))
		reg_addr += CONTROL_104_SIZE;

	/* control 105 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query22) &&
			(m_f54Query_22.has_ctrl105))
		reg_addr += CONTROL_105_SIZE;

	/* control 106 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_ctrl106))
		reg_addr += CONTROL_106_SIZE;

	/* control 107 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_ctrl107))
		reg_addr += CONTROL_107_SIZE;

	/* control 108 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_ctrl108))
		reg_addr += CONTROL_108_SIZE;

	/* control 109 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_ctrl109))
		reg_addr += CONTROL_109_SIZE;

	/* control 110 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_ctrl110)) {
		m_f54Control.reg_110.address = reg_addr;
		reg_addr += CONTROL_110_SIZE;
	}

	/* control 111 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_ctrl111))
		reg_addr += CONTROL_111_SIZE;

	/* control 112 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_ctrl112))
		reg_addr += CONTROL_112_SIZE;

	/* control 113 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_ctrl113))
		reg_addr += CONTROL_113_SIZE;

	/* control 114 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_ctrl114))
		reg_addr += CONTROL_114_SIZE;

	/* control 115 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_ctrl115))
		reg_addr += CONTROL_115_SIZE;

	/* control 116 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_ctrl116))
		reg_addr += CONTROL_116_SIZE;

	/* control 117 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_ctrl117))
		reg_addr += CONTROL_117_SIZE;

	/* control 118 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_ctrl118))
		reg_addr += CONTROL_118_SIZE;

	/* control 119 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_ctrl119))
		reg_addr += CONTROL_119_SIZE;

	/* control 120 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_ctrl120))
		reg_addr += CONTROL_120_SIZE;

	/* control 121 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_ctrl121))
		reg_addr += CONTROL_121_SIZE;

	/* control 122 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_ctrl122_query31))
		reg_addr += CONTROL_122_SIZE;

	/* control 123 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_ctrl123))
		reg_addr += CONTROL_123_SIZE;

	/* control 124 reserved */

	/* control 125 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_ctrl125))
		reg_addr += CONTROL_125_SIZE;

	/* control 126 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_ctrl126))
		reg_addr += CONTROL_126_SIZE;

	/* control 127 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_ctrl127))
		reg_addr += CONTROL_127_SIZE;

	/* controls 128 129 130 131 reserved */

	/* control 132 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_ctrl132))
		reg_addr += CONTROL_132_SIZE;

	/* control 133 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_ctrl133))
		reg_addr += CONTROL_133_SIZE;

	/* control 134 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_ctrl134))
		reg_addr += CONTROL_134_SIZE;

	/* controls 135 136 reserved */

	/* control 137 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query35) &&
			(m_f54Query_35.has_ctrl137))
		reg_addr += CONTROL_137_SIZE;

	/* control 138 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query35) &&
			(m_f54Query_35.has_ctrl138))
		reg_addr += CONTROL_138_SIZE;

	/* control 139 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query35) &&
			(m_f54Query_35.has_ctrl139))
		reg_addr += CONTROL_139_SIZE;

	/* control 140 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query35) &&
			(m_f54Query_35.has_ctrl140))
		reg_addr += CONTROL_140_SIZE;

	/* control 141 reserved */

	/* control 142 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_ctrl142))
		reg_addr += CONTROL_142_SIZE;

	/* control 143 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_ctrl143))
		reg_addr += CONTROL_143_SIZE;

	/* control 144 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_ctrl144))
		reg_addr += CONTROL_144_SIZE;

	/* control 145 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_ctrl145))
		reg_addr += CONTROL_145_SIZE;

	/* control 146 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_ctrl146))
		reg_addr += CONTROL_146_SIZE;

	/* control 147 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_query38) &&
			(m_f54Query_38.has_ctrl147))
		reg_addr += CONTROL_147_SIZE;

	/* control 148 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_query38) &&
			(m_f54Query_38.has_ctrl148))
		reg_addr += CONTROL_148_SIZE;

	/* control 149 */
	if ((m_f54Query.has_query15) &&
			(m_f54Query_15.has_query25) &&
			(m_f54Query_25.has_query27) &&
			(m_f54Query_27.has_query29) &&
			(m_f54Query_29.has_query30) &&
			(m_f54Query_30.has_query32) &&
			(m_f54Query_32.has_query33) &&
			(m_f54Query_33.has_query36) &&
			(m_f54Query_36.has_query38) &&
			(m_f54Query_38.has_ctrl149)) {
		m_f54Control.reg_149.address = reg_addr;
		reg_addr += CONTROL_149_SIZE;
	}

	return TEST_SUCCESS;
}

int F54Test::ReadF55Queries()
{
	int retval;
	unsigned char ii;
	unsigned char rx_electrodes = m_f54Query.num_of_rx_electrodes;
	unsigned char tx_electrodes = m_f54Query.num_of_tx_electrodes;

	retval = m_device.Read(m_f55.GetQueryBase(),
			m_f55Query.data,
			sizeof(m_f55Query.data));
	if (retval < 0) {
		return retval;
	}

	if (!m_f55Query.has_sensor_assignment)
	{
		m_txAssigned = tx_electrodes;
		m_rxAssigned = rx_electrodes;
		m_txAssignment = NULL;
		m_rxAssignment = NULL;
		return TEST_SUCCESS;
	}

	if (m_txAssignment != NULL) delete [] m_txAssignment;
	if (m_rxAssignment != NULL) delete [] m_rxAssignment;
	m_txAssignment = new unsigned char[tx_electrodes];
	m_rxAssignment = new unsigned char[rx_electrodes];

	retval = m_device.Read(m_f55.GetControlBase() + SENSOR_TX_MAPPING_OFFSET,
			m_txAssignment,
			tx_electrodes);
	if (retval < 0) {
		goto exit;
	}

	retval = m_device.Read(m_f55.GetControlBase() + SENSOR_RX_MAPPING_OFFSET,
			m_rxAssignment,
			rx_electrodes);
	if (retval < 0) {
		goto exit;
	}

	m_txAssigned = 0;
	for (ii = 0; ii < tx_electrodes; ii++) {
		if (m_txAssignment[ii] != 0xff)
			m_txAssigned++;
	}

	m_rxAssigned = 0;
	for (ii = 0; ii < rx_electrodes; ii++) {
		if (m_rxAssignment[ii] != 0xff)
			m_rxAssigned++;
	}

	return TEST_SUCCESS;

exit:
	if (m_txAssignment != NULL)
	{
		delete [] m_txAssignment;
		m_txAssignment = NULL;
	}
	if (m_rxAssignment != NULL)
	{
		delete [] m_rxAssignment;
		m_rxAssignment = NULL;
	}

	return retval;
}

int F54Test::SetF54Interrupt()
{
	int retval;
	unsigned char mask = m_f54.GetInterruptMask();
	unsigned char zero = 0;
	unsigned int i;

	for (i = 0; i < m_device.GetNumInterruptRegs(); i++)
	{
		if (i == m_f54.GetInterruptRegNum())
		{
			retval = m_device.Write(m_f54.GetControlBase() + 1 + i, &mask, 1);
		}
		else
		{
			retval = m_device.Write(m_f54.GetControlBase() + 1 + i, &zero, 1);
		}

		if (retval < 0)
			return retval;
	}
	return TEST_SUCCESS;
}

int F54Test::DoF54Command(unsigned char command)
{
	int retval;

	retval = m_device.Write(m_f54.GetCommandBase(), &command, 1);
	if (retval < 0)
		return retval;

	retval = WaitForF54CommandCompletion();
	if (retval != TEST_SUCCESS)
		return retval;

	return TEST_SUCCESS;
}

int F54Test::WaitForF54CommandCompletion()
{
	int retval;
	unsigned char value;
	unsigned char timeout_count;

	timeout_count = 0;
	do {
		retval = m_device.Read(m_f54.GetCommandBase(),
				&value,
				sizeof(value));
		if (retval < 0)
			return retval;

		if (value == 0x00)
			break;

		Sleep(100);
		timeout_count++;
	} while (timeout_count < COMMAND_TIMEOUT_100MS);

	if (timeout_count == COMMAND_TIMEOUT_100MS) {
		return -ETIMEDOUT;
	}

	return TEST_SUCCESS;
}

int F54Test::ReadF54Report()
{
	int retval;
	unsigned char report_index[2];

	if (m_reportBufferSize < m_reportSize) {
		if (m_reportData != NULL)
			delete [] m_reportData;
		m_reportData = new unsigned char[m_reportSize];
		if (!m_reportData) {
			m_reportBufferSize = 0;
			retval = TEST_FAIL_MEMORY_ALLOCATION;
			goto exit;
		}
		m_reportBufferSize = m_reportSize;
	}

	report_index[0] = 0;
	report_index[1] = 0;

	retval = m_device.Write(m_f54.GetDataBase() + REPORT_INDEX_OFFSET,
				report_index,
				sizeof(report_index));

	if (retval < 0)
		goto exit;

	retval = m_device.Read(m_f54.GetDataBase() + REPORT_DATA_OFFSET,
				m_reportData,
				m_reportSize);
	if (retval < 0)
		goto exit;

	return TEST_SUCCESS;

exit:
	if (m_reportData != NULL)
	{
		delete [] m_reportData;
		m_reportData = NULL;
	}

	return retval;
}

int F54Test::ShowF54Report()
{
	unsigned int ii;
	unsigned int jj;
	unsigned int tx_num = m_txAssigned;
	unsigned int rx_num = m_rxAssigned;
	char *report_data_8;
	short *report_data_16;
	int *report_data_32;
	unsigned int *report_data_u32;
	char buf[256];

	switch (m_reportType) {
	case F54_8BIT_IMAGE:
		report_data_8 = (char *)m_reportData;
		for (ii = 0; ii < m_reportSize; ii++) {
			sprintf(buf, "%03d: %d\n",
					ii, *report_data_8);
			m_display.Output(buf);
			report_data_8++;
		}
		break;
	case F54_16BIT_IMAGE:
	case F54_RAW_16BIT_IMAGE:
	case F54_TRUE_BASELINE:
	case F54_FULL_RAW_CAP:
	case F54_FULL_RAW_CAP_NO_RX_COUPLING:
	case F54_SENSOR_SPEED:
		report_data_16 = (short *)m_reportData;
		sprintf(buf, "tx = %d\nrx = %d\n",
				tx_num, rx_num);
		m_display.Output(buf);

		for (ii = 0; ii < tx_num; ii++) {
			for (jj = 0; jj < (rx_num - 1); jj++) {
				sprintf(buf, "%-4d ",
						*report_data_16);
				report_data_16++;
				m_display.Output(buf);
			}
			sprintf(buf, "%-4d\n",
					*report_data_16);
			m_display.Output(buf);
			report_data_16++;
		}
		break;
	case F54_HIGH_RESISTANCE:
	case F54_FULL_RAW_CAP_MIN_MAX:
		report_data_16 = (short *)m_reportData;
		for (ii = 0; ii < m_reportSize; ii += 2) {
			sprintf(buf, "%03d: %d\n",
					ii / 2, *report_data_16);
			m_display.Output(buf);
			report_data_16++;
		}
		break;
	case F54_ABS_RAW_CAP:
		report_data_u32 = (unsigned int *)m_reportData;
		sprintf(buf, "rx ");
		m_display.Output(buf);

		for (ii = 0; ii < rx_num; ii++) {
			sprintf(buf, "     %2d", ii);
			m_display.Output(buf);
		}
		sprintf(buf, "\n");
		m_display.Output(buf);

		sprintf(buf, "   ");
		m_display.Output(buf);

		for (ii = 0; ii < rx_num; ii++) {
			sprintf(buf, "  %5u",
					*report_data_u32);
			report_data_u32++;
			m_display.Output(buf);
		}
		sprintf(buf, "\n");
		m_display.Output(buf);

		sprintf(buf, "tx ");
		m_display.Output(buf);

		for (ii = 0; ii < tx_num; ii++) {
			sprintf(buf, "     %2d", ii);
			m_display.Output(buf);
		}
		sprintf(buf, "\n");
		m_display.Output(buf);
		
		sprintf(buf, "   ");
		m_display.Output(buf);
		
		for (ii = 0; ii < tx_num; ii++) {
			sprintf(buf, "  %5u",
					*report_data_u32);
			report_data_u32++;
			m_display.Output(buf);
		}
		sprintf(buf, "\n");
		m_display.Output(buf);
		
		break;
	case F54_ABS_DELTA_CAP:
		report_data_32 = (int *)m_reportData;
		sprintf(buf, "rx ");
		m_display.Output(buf);
		
		for (ii = 0; ii < rx_num; ii++) {
			sprintf(buf, "     %2d", ii);
			m_display.Output(buf);
		}
		sprintf(buf, "\n");
		m_display.Output(buf);
		
		sprintf(buf, "   ");
		m_display.Output(buf);
		
		for (ii = 0; ii < rx_num; ii++) {
			sprintf(buf, "  %5d",
					*report_data_32);
			report_data_32++;
			m_display.Output(buf);
		}
		sprintf(buf, "\n");
		m_display.Output(buf);

		sprintf(buf, "tx ");
		m_display.Output(buf);
		
		for (ii = 0; ii < tx_num; ii++) {
			sprintf(buf, "     %2d", ii);
			m_display.Output(buf);
		}
		sprintf(buf, "\n");
		m_display.Output(buf);
		
		sprintf(buf, "   ");
		m_display.Output(buf);
		
		for (ii = 0; ii < tx_num; ii++) {
			sprintf(buf, "  %5d",
					*report_data_32);
			report_data_32++;
			m_display.Output(buf);
		}
		sprintf(buf, "\n");
		m_display.Output(buf);
		
		break;
	default:
		for (ii = 0; ii < m_reportSize; ii++) {
			sprintf(buf, "%03d: 0x%02x\n",
					ii, m_reportData[ii]);
			m_display.Output(buf);
		}
		break;
	}

	sprintf(buf, "\n");
	m_display.Output(buf);

	m_display.Reflesh();

	return TEST_SUCCESS;
}