#ifndef Commands_h
#define Commands_h

// Define command and response code layouts for the AardRemote protocol.

// NOTE: Change AARDREMOTE_CURRENT_VERSION (below) when making incompatible
// changes or extensions to this command set.

// Messages are always multiples of 2 bytes in length.

// The first word of the message holds the message kind and length
// in the 1st byte and the command code in the 2nd byte.

// The message length is indicated in the 1st byte of the message along
// with a flag indicating the kind of message.

// So, the first word (in LSB order) looks like:
//
//  7  6  5  4  3  2  1  0  7  6  5  4  3  2  1  0
// [kind][number of words ][8 bit function code   ]

// The message kind is encoded in the top 2 bits.
//
#define MSG_KIND(b) ((b) & 0xc0u)

// The message length (number of 16 bit words) is encoded in the
// low 6 bits. The encoded length *includes* the 1st word of the
// message, therefore 0 is not a valid length and is used to flag
// a variable length message which is always terminated by a 2
// byte value of all zero (0x0000). (So variable length messages
// really need to avoid having a 0x0000 as part of the data).
//
#define MSG_LEN(b) ((b) & 0x3fu)

// The 4 possible message kind values are:

// 0 is not a valid message
#define MK_INVALID 0

// 1 is a command from the host to the aardremote
#define MK_COMMAND 0x40u

// 2 is a reply from the aardremote to the host
#define MK_REPLY 0x80u

// 3 is a message from the aardremote to the host generated "spontaneously"
// not in response to a command (something like "Hey! Some IR data appeared")
#define MK_ASYNC 0xc0u

// The command or function code is the 8 bit value in the 2nd byte.
// 0x00 is invalid and never used as a command. 0xff is used to
// mean extended command (should we ever need more than 254 commands).
//
// When a successful command expects a reply, that reply always contains the
// same command code. If the reply is of length 1, the simple echoing of the
// command code indicates success. If the command requested data, the length
// will be greater than 1 and the returned data will be in the extra words.
//
// If the command failed, the reply will always used the command code
// MKR_NACK to indicate failure and may have additional error information
// in any data words sent in the reply.
//
// The async data codes are independent of the command and reply codes.

// **************************************************** Command and Reply codes

// MKCR_INVALID is never used.
//
#define MKCR_INVALID    0x00

// MKR_NACK - only used in a reply, never sent as a command. Indicates
// an error occurred and error information may be returned in data words
// (most errors are length 2 and the data word is an error code).
//
#define MKR_NACK        0x01

// MKCR_QVERSION, response should have version number of microcode in
// 2nd word (version should always be changed when command set changes).
//
#define MKCR_QVERSION   0x02
#define AARDREMOTE_CURRENT_VERSION 9

// MKCR_RECEIVER, 2nd word of message should be 0 to turn off IR receiver
// or non-0 to turn on IR receiver. Response should be simple ACK/NACK response.
//
#define MKCR_RECEIVER   0x03

// MKCR_QRECEIVER - query current receive state, 2nd word in response is
// 0 for off, non-0 for on.
//
#define MKCR_QRECEIVER  0x04

// MKCR_FREQUENCY, 2nd word of message should contain the IR send frequency
// to use in units of kHz (i.e. 38 would mean 38kHz). Response should be
// simple ACK/NACK
//
#define MKCR_FREQUENCY  0x05

// MKCR_QFREQUENCY - query current send frequency, 2nd word of response
// contains the current setting.
//
#define MKCR_QFREQUENCY 0x06

// MKCR_QMICROS - query current micros() value in controller, response
// should have the 4 byte value in 2nd and 3rd words.
//
#define MKCR_QMICROS    0x07

// MKCR_SENDRAW - send raw format IR MARK/SPACE pulses, length indicates how
// many pulses are in the message, or it may be variable length and
// terminated by a 0x0000 word. The response to this message has an
// additional data word that says how many of the pulses it was able to push
// on the output queue. If the queue fills up, the response may indicate
// fewer pulses were queued than were sent. It is up to the caller to
// resend the dropped data. (Which needs to happen pretty quick before
// the queue drains completely). See RawIR.h for format of pulse data.
//
#define MKCR_SENDRAW    0x08

// MKCR_WAITAVAIL - wait till the output queue is no longer full, then
// return an ACK (this means it is possible to push more data on queue, not
// that all the data on the queue has been sent, use MKCR_WAITSEND for that).
//
#define MKCR_WAITAVAIL  0x09

// MKCR_WAITSEND - wait for any sending to finish. If there is data in the
// queue still being sent, wait for it all to be sent, then reply with
// ACK. If there is no send active, reply right away.
//
#define MKCR_WAITSEND   0x0A

// MKCR_QUEUESIZE - report the size of the queue used to push IR pulses
// on for sending. Reply returns the size in the 2nd word.
//
#define MKCR_QUEUESIZE  0x0B

// MKCR_RESET - set the low bit of byte 0 in the eeprom to 1 to tell the
// custom bootloader to enter the loader on the next watchdog reset, then
// turn on the watchdog and trigger a reset. (We expect the host to
// start a new microcode upload after sending us this command).
//
#define MKCR_RESET      0x0C

// MKCR_EXTENDED - reserved for extending command set beyond 254 commands.
// Format to be determined when we actually need to do that (but presumably
// the next word would be a 16 bit command code).
//
#define MKCR_EXTENDED   0xff

// *********************************************************** Async Data Codes

// MKAS_INVALID is never used.
//
#define MKAS_INVALID    0x00

// MKAS_RESET - this gets sent with no associated data when the
// microcode starts up so anyone waiting for it to start will know
// it is ready.
//
#define MKAS_RESET      0xfb

// MKAS_BILGE - used to send back a character that appears to be unexpected
// bilge (doesn't look like a command but arrives when I'm expecting a
// command).
//
#define MKAS_BILGE      0xfc

// MKAS_GLOBERR - a global error was detected since the last one (or since
// startup). The 2nd word contains the global error flags (which are flushed
// after this report is made).
//
#define MKAS_GLOBERR    0xfd

// MKAS_RAWIR - the message contains raw IR codes received by the
// aardremote.  Length will depend on how many codes are available in the
// circular buffer.  (Can be sent in variable length message format
// terminated by 0x0000). See RawIR.h for the format of the data.
//
#define MKAS_RAWIR      0xfe

// MKAS_EXTENDED - reserved for extending async codes beyond 254 if we
// ever need that many (hard to imagine).
//
#define MKAS_EXTENDED   0xff

#endif // Commands_h
