/* GPC (C) 2017-2018 Stephane Charette <stephanecharette@gmail.com>
 * $Id: BinaryProtocol.hpp 2489 2018-03-19 05:57:30Z stephane $
 */

#pragma once

#include "GPC.hpp"


/** The IncJet devices can communicate using several different methods.
 * The document "IJM017B OnBoardRIP Software Integration Guide" describes
 * a method called "binary protocol".
 *
 * The message format is described in section 4.2, "Binary Protocol Command
 * Structure":
 *
 * Offset		| Field		| Description
 * -------------|-----------|------------
 * 0x00			| STX		| Start of transmission.  Should be @p 0x02.
 * 0x01-0x04	| NumBytes	| Number of bytes following this parameter, beginning with Checksum field and ending with the ETX.
 * 0x05			| Checksum	| Unused.
 * 0x06			| SeqNum	| Message sequence number.  Possibly unused?
 * 0x07			| MsgID		| Message ID.
 * 0x08-...		| TBuff		| Message data goes here.
 * ... + 1		| ETX		| End of transmission.  Should be @p 0x03.
 *
 * @note Don't get confused with section 4.3 of the document, which describes
 * the "simple ASCII" protocol versus the binary protocol from section 4.2!
 *
 * The @p SeqNum field is not described in the document.  Start with 1 and keep increasing it.
 *
 * The @p MsgID field is the "code" in section 6, starting on page 18.  Not all codes are
 * described in the document, some had to be reverse engineered.  See @ref BinaryProtocol::ECode.
 */
class BinaryProtocol final
{
	public:

		/// These are the 1-byte @p "MsgID" values described in section 6.0 of the document.
		enum class ECode
		{
			kInvalid		= 0xff,
			kPowerUpMsg		= 0x01,
			kAcknowledgeMsg	= 0x09,
			kKeepAlive		= 0x30,
			kReportIOStates	= 0x65,
			kIOStates		= 0x66,
			kDoneWithFiles	= 0x70,	// -- no idea what 0x70 does, but it seems to be sent from the host to the imager after changing files
			kSendIjsFile	= 0x72,
			kSendIjbFile	= 0x7d,
			kRequestStatus	= 0x8d,
			kImagerStatus	= 0x8e
		};

		/// Constructor.
		BinaryProtocol(void);

		/// Destructor.
		~BinaryProtocol(void);

		/// Parse the data in the vector.
		BinaryProtocol(const VBytes &v, const size_t number_of_bytes);

		/// Parse the data in the vector.
		BinaryProtocol &parse(const VBytes &v, const size_t number_of_bytes);

		/// Extract just the message data bytes from the content.  Will return an empty vector if there are no data bytes.
		VBytes message_data(void) const;

		/// Describe in English text the message contained within @ref content.
		std::string describe(void) const;

		/// Create a new sequence of bytes to send out to the imager device.
		BinaryProtocol &create(const ECode new_code);

		/// Append the vector to the existing @ref content buffer.  Automatically updates the "NumBytes" value.
		BinaryProtocol &append(const VBytes &file_contents);

		/// SeqNum, 5th byte into the data vector.
		uint8_t sequence_number;

		/// The message ID extracted from the parsed content, 7th byte into the data vector.
		ECode code;

		/// A full copy of the bytes that were parsed.
		VBytes content;
};
