#ifndef SIGNATURE_H_
#define SIGNATURE_H_

// User signature is a 512 byte long reprogrammable region
// We use it to store serial number and configuration data

#include <asf.h>

#define USER_SIG_SIZE_BYTES		(512u)
#define USER_SIG_SIZE_WORDS		(USER_SIG_SIZE_BYTES/sizeof(uint32_t))

#define SIG_MAGIC				(0x5AADE15Fu) // No special significance, just a randomly generated number from 0 to 0xFFFF.FFFF

#define CRC8POLY				(0x07) // Polynomial generator for CRC

typedef enum en_user_sig_state{
	SIG_UNINITIALIZED,	// Ram buffer in unknown state, doesn't match Flash
	SIG_VALID,			// Ram and Flash match
	SIG_OVERWRITTEN		// Ram has been written with new values
} User_Signature_State;


// Signature tags.
// Signature fields are stored in Tag-Length-Value-CRC format.
// Tag is one byte, length is one byte, value is a variable number of bytes, 
// and CRC is one byte calculated over all the previous byte (including the initial tag).
//
// 
// Examples:
//
//	   |Tag--|Length--|Value (8 bytes)--------------------------------|CRC8|
//		0x01, 0x08,    0x48, 0x69, 0x54, 0x68, 0x65, 0x72, 0x65, 0x21, 0x9D
//			This is a 8-byte serial number: "HiThere!"

enum signature_tags{
	SigTag_Serial = 0x01, // Variable length, ASCII characters. Assigned to PCBA during factory test.
	SigTag_RGB_Color = 0x02, // 3 bytes, Red, Green, and Blue color
	SigTag_Fan_Speed = 0x03, // one byte, fan speed in percent
	SigTag_Prox_Disable = 0x04, // one byte, boolean
	SigTag_Linkbox_v1 = 0x05, // one byte, boolean
	SigTag_Prox_Cal = 0x06, // two bytes, u16 value of proximity sensor signal with nothing present
	SigTag_FATP_Mode = 0x07, // one byte, boolean
	SigTag_HMD_Serial = 0x08, // Variable length, ASCII characters. Serial number of whole headset assembly
	SigTag_Tracking_Serial = 0x09, // Variable length, ASCII characters. Serial number of the tracking flex in the HMD
	SigTag_Display_Brightness = 0x0A, // two bytes, u16 value of default display brightness. 0 to 0x03FF
	SigTag_Prox_Threshold = 0x0B, // two bytes, u16 value of prox sensor threshold
	SigTag_Prox_Hysteresis = 0x0C, // two bytes, u16 value of prox sensor threshold hysteresis (eg turns on at thresh+hyst, turns off at thresh-hyst)
	SigTag_EDID_Switch = 0x0D, // one byte: 0 = both 75Hz and 90Hz modes, 1 = 90Hz only, 2 = 75Hz only
	SigTag_Invalid = 0xFF // Any unprogrammed byte will be 0xFF. Can use this to denote the end of the valid tags	
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"
typedef struct __attribute__((packed)) st_user_sig_region{
	uint32_t magic_num;
	char serial_number[16]; // 16 alpha-numeric serial number
	int16_t user_name[64]; // UTF-16 user name, up to 64 characters (will have to be truncated after 64, sorry long name folks)
	RGB_Color_t default_color; // initial boot up color, and "off" (all zeros) can count as a color
	uint8_t default_fan_speed; // fan speed in percent
	bool prox_disabled;		// false: proximity sensor turns displays on and off
							// true: displays always on when there is video data, proximity sensor is ignored
	bool linkbox_is_v1;		// false: CC wire pulldown should be 1k (extra pulldowns ON) to assert HPD.
							// true: CC wire pulldown should be 5.1k to assert HPD. This was the case on Linkbox v1.
	uint8_t crc8;
	
} User_Signature_T;
#pragma GCC diagnostic pop

#define USER_SIG_STRUCT_SIZE sizeof(User_Signature_T)

ct_assert(USER_SIG_STRUCT_SIZE <= USER_SIG_SIZE_BYTES, user_sig_too_big);

uint8_t crc8(uint8_t initcrc, const uint8_t* input_data, uint32_t len);
const User_Signature_T* get_signature(void);
uint8_t update_signature_raw(uint8_t* buf, uint32_t offset, uint32_t len);
const uint32_t* get_signature_raw(void);
uint8_t save_signature(void);
uint8_t save_signature_raw(void);
bool check_signature(const User_Signature_T* sig);
bool sigv2_find_tag(uint8_t tag, uint8_t* retval);
bool sigv2_tag_exists(uint8_t tag);
uint8_t sigv2_tag_length(uint8_t tag);
uint16_t sigv2_build_signature(uint16_t sig_ptr, uint8_t tag, uint8_t length, uint8_t* data);
uint16_t sigv2_find_first_blank(void);
bool sigv2_add_new_tag(uint8_t tag, uint8_t length, uint8_t* data);
void sigv2_upgrade_from_sigv1(void);
#endif // SIGNATURE_H_
