//..............................................................................
//
// I2C/SPI Tap log representer
//

import "log_Representation.jnc"
import "io_RpdFile.jnc"

//..............................................................................

bool representI2cSpiTapLog(
	log.Representation* representation,
	uint64_t recordCode,
	void const* p,
	size_t size,
	uint_t foldFlags
) {
	switch (recordCode) {
	case I2cSpiTapLogRecordCode.DeviceOpened:
		string_t name = (char const*)p;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Opened tap device \e[34m$name\e[m");
		break;

	case I2cSpiTapLogRecordCode.InterfaceClaimed:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Interface \e[34m#0\e[m claimed");
		break;

	case I2cSpiTapLogRecordCode.InEndpointOpened:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"In endpoint \e[34m#86\e[m opened");
		break;

	case I2cSpiTapLogRecordCode.OutEndpointOpened:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Out endpoint \e[34m#2\e[m opened");
		break;

	case I2cSpiTapLogRecordCode.CaptureStarted:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Connect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Connect;
		representation.addHyperText($"Capture started");
		break;

	case I2cSpiTapLogRecordCode.CaptureStopped:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Disconnect;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Disconnect;
		representation.addHyperText("Capture stopped");
		break;

	case I2cSpiTapLogRecordCode.CaptureError:
		std.Error const* error = (std.Error const*)p;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Error;
		representation.addHyperText($"Cannot open sniffer: $(error.m_description)");
		break;

	case I2cSpiTapLogRecordCode.UnexpectedCode:
		uint_t code = ((uint_t const*)p)[0];
		uint_t state = ((uint_t const*)p)[1];
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Error;
		representation.addHyperText($"Unexpected code from sniffer (code: $code, decoder state: $state)");
		break;

	case I2cSpiTapLogRecordCode.IncompleteByte:
		uint_t bitCount = *(uint_t const*)p;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Warning;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Warning;
		representation.addHyperText($"Incomplete byte received ($(bitCount) bit(s))");
		break;

	case I2cSpiTapLogRecordCode.FpgaBufferOverflow:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Warning;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Warning;
		representation.addHyperText("Hardware buffer overflow");
		break;

	case I2cSpiTapLogRecordCode.CypressBufferCleared:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText($"Hardware buffer cleared");
		break;

	case I2cSpiTapLogRecordCode.I2cStart:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Play;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText(I2cSpiTapLogPartCode.I2cStartBegin, "I2C start");
		break;

	case I2cSpiTapLogRecordCode.I2cFinalizeStart7Bit:
		uint16_t hdr = *(const uint16_t*)p;
		bool isRead = hdr & 0x01;
		bool isAck = hdr & 0x0100;

		representation.addHyperText(
			I2cSpiTapLogPartCode.I2cStartEnd,
			$"\x15I2C start (%1, I2C 7-bit address: \e[%2m0x%(3; 02x)\e[m)" (
				isRead ? "read" : "write",
				isAck ? "34" : "34;9",
				(hdr & 0xfe) >> 1
			)
		);

		representation.m_lineAttr.m_iconIdx = isRead ? log.StdLogIcon.Rx : log.StdLogIcon.Tx;
		representation.m_lineAttr.m_backColor = ui.ColorFlags.Undefined;
		representation.m_lineAttr.m_textColor = ui.StdColor.Red;
		representation.m_lineAttr.m_fontFlags = isAck ? 0 : ui.FontFlags.Strikeout;
		representation.addBin(isRead ? log.StdRecordCode.Rx : log.StdRecordCode.Tx, p, 1);
		break;

	case I2cSpiTapLogRecordCode.I2cFinalizeStart10Bit:
		uint32_t hdr = *(const uint32_t*)p;
		bool isRead = hdr & 0x01;
		bool isAck1 = hdr & 0x00010000;
		bool isAck2 = hdr & 0x00020000;

		representation.addHyperText(
			I2cSpiTapLogPartCode.I2cStartEnd,
			$"\x15I2C start (%1, I2C 10-bit address: \e[%2m0x%(3; 03x)\e[m)" (
				isRead ? "read" : "write",
				isAck1 && isAck2 ? "34" : "34;9",
				((hdr & 0x06) << 7) | ((hdr & 0xff00) >> 8)
			)
		);

		representation.m_lineAttr.m_iconIdx = isRead ? log.StdLogIcon.Rx : log.StdLogIcon.Tx;
		representation.m_lineAttr.m_backColor = ui.ColorFlags.Undefined;
		representation.m_lineAttr.m_textColor = ui.StdColor.Red;

		uint64_t binRecordCode = isRead ? log.StdRecordCode.Rx : log.StdRecordCode.Tx;
		ui.FontFlags fontFlags1 = isAck1 ? 0 : ui.FontFlags.Strikeout;
		ui.FontFlags fontFlags2 = isAck2 ? 0 : ui.FontFlags.Strikeout;

		if (fontFlags1 == fontFlags2) {
			representation.m_lineAttr.m_fontFlags = fontFlags1;
			representation.addBin(binRecordCode, p, 2);
		} else {
			representation.m_lineAttr.m_fontFlags = fontFlags1;
			representation.addBin(binRecordCode, p, 1);
			representation.m_lineAttr.m_fontFlags = fontFlags2;
			representation.addBin(binRecordCode, p + 1, 1);
		}

		break;

	case I2cSpiTapLogRecordCode.I2cStop:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Stop;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText("I2C stop");
		break;

	case I2cSpiTapLogRecordCode.I2cStopOutOfTransaction:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Warning;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Warning;
		representation.addHyperText("I2C \e[31mstop\e[m out-of-transaction");
		break;

	case I2cSpiTapLogRecordCode.I2cTxNack:
		representation.m_lineAttr.m_flags = log.LineAttrFlags.TileIcon;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Tx;
		representation.m_lineAttr.m_textColor = log.StdLogColor.Tx;
		representation.m_lineAttr.m_fontFlags = ui.FontFlags.Strikeout;
		representation.addBin(log.StdRecordCode.Tx, p, size);
		break;

	case I2cSpiTapLogRecordCode.I2cRxNack:
		representation.m_lineAttr.m_flags = log.LineAttrFlags.TileIcon;
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Rx;
		representation.m_lineAttr.m_textColor = log.StdLogColor.Rx;
		representation.m_lineAttr.m_fontFlags = ui.FontFlags.Strikeout;
		representation.addBin(log.StdRecordCode.Rx, p, size);
		break;

	case I2cSpiTapLogRecordCode.SpiStart:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Play;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText("SPI SS \e[32mlow\e[m");
		break;

	case I2cSpiTapLogRecordCode.SpiStop:
		representation.m_lineAttr.m_iconIdx = log.StdLogIcon.Stop;
		representation.m_lineAttr.m_backColor = log.StdLogColor.Info;
		representation.addHyperText("SPI SS \e[31mhigh\e[m");
		break;

	default:
		return false;
	}

	return true;
}

//..............................................................................
