//..............................................................................
//
// Use this script to define your packet templates in Jancy language.
//
// If you are not familar with Jancy, no worries -- on the surface, you can
// think of it simply as a safe scripting dialect of C. Most C structs will
// compile just fine (you can use sub-structs, unions, arrays, bitfields, etc),
// and you also can make use of the native support of big-endian integers.
//
// Besides struct fields, you can also define *actions* -- special methods which
// will take existing packet and modify in a certain way. Good examples of what
// actions can be used for are: initializing the packet fields with some default
// valid values, calculating checksums, updating the length-field, etc
//
//..............................................................................

import "ui_Color.jnc"
import "crc16.jnc"

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

enum MyCommand: int8_t {
	Open,
	Close,
	Read,
	Write,
}

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

// static

pragma(Alignment, 1);

[
	packetTemplate,
	displayName = "My packet #1 (static)"
]
struct MyPacket {
	[ displayName = "Command" ]
	MyCommand m_field1;

	[ displayName = "16-bit integer" ]
	int16_t m_field2;

	[ displayName = "32-bit big-endian" ]
	bigendian int32_t m_field3;

	[ displayName = "Name" ]
	char m_name[8];

	[ displayName = "Length" ]
	uint16_t m_length;

	[ displayName = "CRC-16" ]
	uint16_t m_checksum;

	[ userAction = "Initialize" ]
	void initialize(string_t name) {
		m_field1 = MyCommand.Open;
		m_field2 = 2;
		m_field3 = 3;

		if (name.m_length >= sizeof(m_name))
			memcpy(m_name, name.m_p, sizeof(m_name));
		else {
			memset(m_name, 0, sizeof(m_name));
			memcpy(m_name, name.m_p, name.m_length);
		}
	}

	[
		userAction = "Update length",
		autorun = "Auto-update length"
	]
	void updateLength() {
		m_length = dynamic sizeof(this);
	}

	[
		userAction = "Update checksum",
		autorun = "Auto-update checksum"
	]
	void updateChecksum() {
		m_checksum = 0;
		m_checksum = crc16_ansi(this, dynamic sizeof(this));
	}
}

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

struct Hdr {
	[
		displayName = "Packet ID",
		formatSpec = "#%d"
	]
	bigendian uint16_t m_id;

	[ displayName = "Command" ]
	MyCommand m_command;
}

struct ReadWrite {
	[
		displayName = "Address",
		formatSpec = "0x%04X"
	]
	bigendian uint16_t m_address;

	[ displayName = "Length" ]
	uint8_t m_length;
}

[
	packetTemplate,
	displayName = "My packet #2 (dynamic)",
	fixedSize
]
void layoutMyPacket(jnc.DynamicLayout* layout) {
	dylayout (layout) {
		[
			backColor = ui.StdColor.PastelPurple,
			ungroup
		]
		dyfield Hdr hdr;

		switch (hdr.m_command) {
		case MyCommand.Open:
			[
				displayName = "Name",
				backColor = ui.StdColor.PastelYellow
			]
			dyfield char name[8];
			break;

		case MyCommand.Close: // no parameters
			break;

		case MyCommand.Read:
			[
				backColor = ui.StdColor.PastelBlue,
				ungroup
			]
			dyfield ReadWrite read;
			break;

		case MyCommand.Write:
			[
				backColor = ui.StdColor.PastelBlue,
				ungroup
			]
			dyfield ReadWrite write;

			[
				displayName = "Data",
				backColor = ui.StdColor.PastelYellow,
				binary
			]
			dyfield char data[write.m_length];
			break;
		}
	}
}

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