//..............................................................................
//
// USB log packet declarations and representer
//

import "log.jnc"
import "io_UsbDb.jnc"

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

enum UsbRecordCode
{
	DeviceOpened,
	DeviceOpenError,
	DeviceClosed,
	KernelDriverDetached,
	InterfaceClaimed,
	InterfaceClaimError,
	InterfaceReleased,
	ReadingStarted,
	ReadingStopped,
	EndpointOpenError,
	ControlTransfer,
}

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

struct DeviceParams
{
	uint8_t m_bus;
	uint8_t m_address;
	uint16_t m_vendorId;
	uint16_t m_productId;
}

char const* formatDeviceString (DeviceParams const* params)
{
	char const* string = $"bus \e[34m%(1;03d):%(2;03d)\e[m ID \e[34m%(3;04x):%(4;04x)\e[m" (
		params.m_bus,
		params.m_address,
		params.m_vendorId,
		params.m_productId
		);

	io.UsbVendor const* vendor = g_usbDb.findVendor (params.m_vendorId);
	io.UsbProduct const* product = vendor ? vendor.findProduct (params.m_productId) : null;

	if (vendor)
	{
		string = $"$string $(vendor.m_name)";

		if (product)
			string = $"$string $(product.m_name)";
		else
			string = $"$string PID_$(params.m_productId; 04x)";
	}

	return string;
}

struct InterfaceParams
{
	uint8_t m_interfaceId;
	uint8_t m_altSettingId;
}

struct ControlTransferParams
{
	uint8_t m_type;
	uint8_t m_code;
	uint16_t m_value;
	uint16_t m_index;
}

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

bool representUsbLog (
	log.RepresenterTarget* target,
	uint_t recordCode,
	void const* p,
	size_t size,
	uint_t foldFlags
	)
{
	switch (recordCode)
	{
	case UsbRecordCode.DeviceOpened:
		DeviceParams const* params = (DeviceParams const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Connect;
		target.m_lineAttr.m_backColor = log.StdLogColor.Connect;
		target.addHyperText($"Device opened: $(formatDeviceString (params))");
		break;

	case UsbRecordCode.DeviceOpenError:
		std.Error const* error = (std.Error const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		target.m_lineAttr.m_backColor = log.StdLogColor.Error;
		target.addHyperText($"Cannot open device: $(error.m_description)");
		break;

	case UsbRecordCode.DeviceClosed:
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Disconnect;
		target.m_lineAttr.m_backColor = log.StdLogColor.Disconnect;
		target.addHyperText("Device closed");
		break;

	case UsbRecordCode.KernelDriverDetached:
		uint8_t ifaceId = *(uint8_t const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Warning;
		target.m_lineAttr.m_backColor = log.StdLogColor.Warning;
		target.addHyperText($"Kernel driver detached from interface ID \e[34m$ifaceId");
		break;

	case UsbRecordCode.InterfaceClaimed:
		InterfaceParams const* params = (InterfaceParams const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		target.m_lineAttr.m_backColor = log.StdLogColor.Info;
		target.addHyperText($"Interface claimed: ID \e[34m$(params.m_interfaceId):$(params.m_altSettingId)");
		break;

	case UsbRecordCode.InterfaceClaimError:
		std.Error const* error = (std.Error const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		target.m_lineAttr.m_backColor = log.StdLogColor.Error;
		target.addHyperText($"Cannot claim interface: $(error.m_description)");
		break;

	case UsbRecordCode.InterfaceReleased:
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		target.m_lineAttr.m_backColor = log.StdLogColor.Info;
		target.addHyperText($"Interface released");
		break;

	case UsbRecordCode.ReadingStarted:
		uint8_t endpointId = *(uint8_t const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		target.m_lineAttr.m_backColor = log.StdLogColor.Info;
		target.addHyperText($"Reading started from endpoint ID \e[34m$(endpointId; 02x)");
		break;

	case UsbRecordCode.ReadingStopped:
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Info;
		target.m_lineAttr.m_backColor = log.StdLogColor.Info;
		target.addHyperText($"Reading stopped");
		break;

	case UsbRecordCode.EndpointOpenError:
		std.Error const* error = (std.Error const*) p;
		target.m_lineAttr.m_iconIdx = log.StdLogIcon.Error;
		target.m_lineAttr.m_backColor = log.StdLogColor.Error;
		target.addHyperText($"Cannot open endpoint: $(error.m_description)");
		break;

	case UsbRecordCode.ControlTransfer:
		ControlTransferParams const* params = (ControlTransferParams const*) p;
		target.m_lineAttr.m_iconIdx = (params.m_type & 0x80) ? log.StdLogIcon.RxPacket : log.StdLogIcon.TxPacket;
		target.m_lineAttr.m_backColor = gui.StdColor.PastelGray;
		target.addHyperText(
			$"Type: $(params.m_type; 02x) "
			$"Code: $(params.m_code; 02x) "
			$"Value: $(params.m_value; 04x) "
			$"Index: $(params.m_index; 04x)"
			);
		break;

	default:
		return false;
	}

	return true;
}

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