*/
#include "../platform/util/StdString.h"
+#include "../platform/util/buffer.h"
+#include "../platform/threads/mutex.h"
+#include "../../../include/cectypes.h"
namespace CEC
{
+ typedef enum cec_adapter_message_state
+ {
+ ADAPTER_MESSAGE_STATE_UNKNOWN = 0, /**< the initial state */
+ ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT, /**< waiting in the send queue of the adapter, or timed out */
+ ADAPTER_MESSAGE_STATE_SENT, /**< sent and waiting on an ACK */
+ ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED, /**< sent, but failed to ACK */
+ ADAPTER_MESSAGE_STATE_SENT_ACKED, /**< sent, and ACK received */
+ ADAPTER_MESSAGE_STATE_INCOMING, /**< received from another device */
+ ADAPTER_MESSAGE_STATE_ERROR /**< an error occured */
+ } cec_adapter_message_state;
+
class CCECAdapterMessage
{
public:
- CCECAdapterMessage(void)
- {
- Clear();
- }
-
- CCECAdapterMessage(const cec_command &command)
- {
- Clear();
-
- //set ack polarity to high when transmitting to the broadcast address
- //set ack polarity low when transmitting to any other address
- PushBack(MSGSTART);
- PushEscaped(MSGCODE_TRANSMIT_ACK_POLARITY);
- if (command.destination == CECDEVICE_BROADCAST)
- PushEscaped(CEC_TRUE);
- else
- PushEscaped(CEC_FALSE);
- PushBack(MSGEND);
-
- // add source and destination
- PushBack(MSGSTART);
- PushEscaped(command.opcode_set == 0 ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT);
- PushBack(((uint8_t)command.initiator << 4) + (uint8_t)command.destination);
- PushBack(MSGEND);
-
- // add opcode
- if (command.opcode_set == 1)
- {
- PushBack(MSGSTART);
- PushEscaped(command.parameters.IsEmpty() ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT);
- PushBack((uint8_t) command.opcode);
- PushBack(MSGEND);
-
- // add parameters
- for (int8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
- {
- PushBack(MSGSTART);
-
- if (iPtr == command.parameters.size - 1)
- PushEscaped( MSGCODE_TRANSMIT_EOM);
- else
- PushEscaped(MSGCODE_TRANSMIT);
-
- PushEscaped(command.parameters[iPtr]);
-
- PushBack(MSGEND);
- }
- }
-
- // set timeout
- transmit_timeout = command.transmit_timeout;
- //TODO
- }
-
- CCECAdapterMessage &operator=(const CCECAdapterMessage &msg)
- {
- packet = msg.packet;
- state = msg.state;
- return *this;
- }
-
- CStdString ToString(void) const
- {
- CStdString strMsg;
- if (Size() == 0)
- {
- strMsg = "empty message";
- }
- else
- {
- strMsg = MessageCodeAsString();
-
- switch (Message())
- {
- case MSGCODE_TIMEOUT_ERROR:
- case MSGCODE_HIGH_ERROR:
- case MSGCODE_LOW_ERROR:
- {
- uint32_t iLine = (Size() >= 3) ? (At(1) << 8) | At(2) : 0;
- uint32_t iTime = (Size() >= 7) ? (At(3) << 24) | (At(4) << 16) | (At(5) << 8) | At(6) : 0;
- strMsg.AppendFormat(" line:%u", iLine);
- strMsg.AppendFormat(" time:%u", iTime);
- }
- break;
- case MSGCODE_FRAME_START:
- if (Size() >= 2)
- strMsg.AppendFormat(" initiator:%1x destination:%1x ack:%s %s", Initiator(), Destination(), IsACK() ? "high" : "low", IsEOM() ? "eom" : "");
- break;
- case MSGCODE_FRAME_DATA:
- if (Size() >= 2)
- strMsg.AppendFormat(" %02x %s", At(1), IsEOM() ? "eom" : "");
- break;
- default:
- break;
- }
- }
-
- return strMsg;
- }
-
- CStdString MessageCodeAsString(void) const
- {
- CStdString strMsg;
- switch (Message())
- {
- case MSGCODE_NOTHING:
- strMsg = "NOTHING";
- break;
- case MSGCODE_PING:
- strMsg = "PING";
- break;
- case MSGCODE_TIMEOUT_ERROR:
- strMsg = "TIMEOUT";
- break;
- case MSGCODE_HIGH_ERROR:
- strMsg = "HIGH_ERROR";
- break;
- case MSGCODE_LOW_ERROR:
- strMsg = "LOW_ERROR";
- break;
- case MSGCODE_FRAME_START:
- strMsg = "FRAME_START";
- break;
- case MSGCODE_FRAME_DATA:
- strMsg = "FRAME_DATA";
- break;
- case MSGCODE_RECEIVE_FAILED:
- strMsg = "RECEIVE_FAILED";
- break;
- case MSGCODE_COMMAND_ACCEPTED:
- strMsg = "COMMAND_ACCEPTED";
- break;
- case MSGCODE_COMMAND_REJECTED:
- strMsg = "COMMAND_REJECTED";
- break;
- case MSGCODE_SET_ACK_MASK:
- strMsg = "SET_ACK_MASK";
- break;
- case MSGCODE_TRANSMIT:
- strMsg = "TRANSMIT";
- break;
- case MSGCODE_TRANSMIT_EOM:
- strMsg = "TRANSMIT_EOM";
- break;
- case MSGCODE_TRANSMIT_IDLETIME:
- strMsg = "TRANSMIT_IDLETIME";
- break;
- case MSGCODE_TRANSMIT_ACK_POLARITY:
- strMsg = "TRANSMIT_ACK_POLARITY";
- break;
- case MSGCODE_TRANSMIT_LINE_TIMEOUT:
- strMsg = "TRANSMIT_LINE_TIMEOUT";
- break;
- case MSGCODE_TRANSMIT_SUCCEEDED:
- strMsg = "TRANSMIT_SUCCEEDED";
- break;
- case MSGCODE_TRANSMIT_FAILED_LINE:
- strMsg = "TRANSMIT_FAILED_LINE";
- break;
- case MSGCODE_TRANSMIT_FAILED_ACK:
- strMsg = "TRANSMIT_FAILED_ACK";
- break;
- case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
- strMsg = "TRANSMIT_FAILED_TIMEOUT_DATA";
- break;
- case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
- strMsg = "TRANSMIT_FAILED_TIMEOUT_LINE";
- break;
- case MSGCODE_FIRMWARE_VERSION:
- strMsg = "FIRMWARE_VERSION";
- break;
- case MSGCODE_START_BOOTLOADER:
- strMsg = "START_BOOTLOADER";
- break;
- case MSGCODE_FRAME_EOM:
- strMsg = "FRAME_EOM";
- break;
- case MSGCODE_FRAME_ACK:
- strMsg = "FRAME_ACK";
- break;
- }
-
- return strMsg;
- }
-
- uint8_t operator[](uint8_t pos) const
- {
- return packet[pos];
- }
-
- uint8_t At(uint8_t pos) const
- {
- return packet[pos];
- }
-
- uint8_t Size(void) const
- {
- return packet.size;
- }
-
- bool IsEmpty(void) const
- {
- return packet.IsEmpty();
- }
-
- void Clear(void)
- {
- state = ADAPTER_MESSAGE_STATE_UNKNOWN;
- transmit_timeout = CEC_DEFAULT_TRANSMIT_TIMEOUT;
- packet.Clear();
- maxTries = CEC_DEFAULT_TRANSMIT_RETRIES + 1;
- tries = 0;
- reply = MSGCODE_NOTHING;
- isTransmission = true;
- expectControllerAck = true;
- lineTimeout = 3;
- retryTimeout = 3;
- }
-
- void Shift(uint8_t iShiftBy)
- {
- packet.Shift(iShiftBy);
- }
-
- void PushBack(uint8_t add)
- {
- packet.PushBack(add);
- }
-
- void PushEscaped(uint8_t byte)
- {
- if (byte >= MSGESC)
- {
- PushBack(MSGESC);
- PushBack(byte - ESCOFFSET);
- }
- else
- {
- PushBack(byte);
- }
- }
-
- cec_adapter_messagecode Message(void) const
- {
- return packet.size >= 1 ?
- (cec_adapter_messagecode) (packet.At(0) & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK)) :
- MSGCODE_NOTHING;
- }
-
- bool IsEOM(void) const
- {
- return packet.size >= 1 ?
- (packet.At(0) & MSGCODE_FRAME_EOM) != 0 :
- false;
- }
-
- bool IsACK(void) const
- {
- return packet.size >= 1 ?
- (packet.At(0) & MSGCODE_FRAME_ACK) != 0 :
- false;
- }
-
- bool IsError(void) const
- {
- cec_adapter_messagecode code = Message();
- return (code == MSGCODE_HIGH_ERROR ||
- code == MSGCODE_LOW_ERROR ||
- code == MSGCODE_RECEIVE_FAILED ||
- code == MSGCODE_COMMAND_REJECTED ||
- code == MSGCODE_TRANSMIT_LINE_TIMEOUT ||
- code == MSGCODE_TRANSMIT_FAILED_LINE ||
- code == MSGCODE_TRANSMIT_FAILED_ACK ||
- code == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
- code == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE);
- }
-
- bool NeedsRetry(void) const
- {
- return reply == MSGCODE_NOTHING ||
- reply == MSGCODE_RECEIVE_FAILED ||
- reply == MSGCODE_TIMEOUT_ERROR ||
- reply == MSGCODE_TRANSMIT_FAILED_LINE ||
- reply == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
- reply == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE ||
- reply == MSGCODE_TRANSMIT_LINE_TIMEOUT;
- }
-
- cec_logical_address Initiator(void) const
- {
- return packet.size >= 2 ?
- (cec_logical_address) (packet.At(1) >> 4) :
- CECDEVICE_UNKNOWN;
- }
-
- cec_logical_address Destination(void) const
- {
- return packet.size >= 2 ?
- (cec_logical_address) (packet.At(1) & 0xF) :
- CECDEVICE_UNKNOWN;
- }
-
- uint8_t maxTries;
- uint8_t tries;
- cec_adapter_messagecode reply;
- cec_datapacket packet;
- cec_adapter_message_state state;
- int32_t transmit_timeout;
- bool isTransmission;
- bool expectControllerAck;
- uint8_t lineTimeout;
- uint8_t retryTimeout;
- PLATFORM::CMutex mutex;
- PLATFORM::CCondition condition;
+ /*!
+ * @brief Create an empty message.
+ */
+ CCECAdapterMessage(void);
+
+ /*!
+ * @brief Create a message with a command that is to be transmitted over the CEC line.
+ * @param command The command to transmit.
+ * @param iLineTimeout The line timeout to use when sending this message.
+ */
+ CCECAdapterMessage(const cec_command &command, uint8_t iLineTimeout = 3);
+
+ /*!
+ * @return the message as human readable string.
+ */
+ CStdString ToString(void) const;
+
+ /*!
+ * @brief Translate the messagecode into a human readable string.
+ * @param msgCode The messagecode to translate.
+ * @return The messagecode as string.
+ */
+ static const char *ToString(cec_adapter_messagecode msgCode);
+
+ /*!
+ * @brief Get the byte at the given position.
+ * @param pos The position to get.
+ * @return The requested byte, or 0 when it's out of range.
+ */
+ uint8_t At(uint8_t pos) const;
+ uint8_t operator[](uint8_t pos) const;
+
+ /*!
+ * @return The size of the packet in bytes.
+ */
+ uint8_t Size(void) const;
+
+ /*!
+ * @return True when empty, false otherwise.
+ */
+ bool IsEmpty(void) const;
+
+ /*!
+ * @brief Clear this message and reset everything to the initial values.
+ */
+ void Clear(void);
+
+ /*!
+ * @brief Shift the message by the given number of bytes.
+ * @param iShiftBy The number of bytes to shift.
+ */
+ void Shift(uint8_t iShiftBy);
+
+ /*!
+ * @brief Append the given message to this message.
+ * @param data The message to append.
+ */
+ void Append(CCECAdapterMessage &data);
+
+ /*!
+ * @brief Append the given datapacket to this message.
+ * @param data The packet to add.
+ */
+ void Append(cec_datapacket &data);
+
+ /*!
+ * @brief Adds a byte to this message. Does not escape the byte.
+ * @param byte The byte to add.
+ */
+ void PushBack(uint8_t byte);
+
+ /*!
+ * @brief Adds a byte to this message and escapes the byte if needed.
+ * @param byte The byte to add.
+ */
+ void PushEscaped(uint8_t byte);
+
+ /*!
+ * @brief Adds a byte to this message.
+ * @param byte The byte to add.
+ * @return True when a full message was received, false otherwise.
+ */
+ bool PushReceivedByte(uint8_t byte);
+
+ /*!
+ * @return The messagecode inside this adapter message, or MSGCODE_NOTHING if there is none.
+ */
+ cec_adapter_messagecode Message(void) const;
+
+ /*!
+ * @return True when this message is a transmission, false otherwise.
+ */
+ bool IsTranmission(void) const;
+
+ /*!
+ * @return True when the EOM bit is set, false otherwise.
+ */
+ bool IsEOM(void) const;
+
+ /*!
+ * @return True when the ACK bit is set, false otherwise.
+ */
+ bool IsACK(void) const;
+
+ /*!
+ * @return True when this message has been replied with an error code, false otherwise.
+ */
+ bool IsError(void) const;
+
+ /*!
+ * @return True when this message has been replied with an error code and needs to be retried, false otherwise.
+ */
+ bool NeedsRetry(void) const;
+
+ /*!
+ * @return The logical address of the initiator, or CECDEVICE_UNKNOWN if unknown.
+ */
+ cec_logical_address Initiator(void) const;
+
+ /*!
+ * @return The logical address of the destination, or CECDEVICE_UNKNOWN if unknown.
+ */
+ cec_logical_address Destination(void) const;
+
+ /*!
+ * @return True when this message contains a start message, false otherwise.
+ */
+ bool HasStartMessage(void) const;
+
+ /*!
+ * @brief Push this adapter message to the end of the given cec_command.
+ * @param command The command to push this message to.
+ * @return True when a full CEC message was received, false otherwise.
+ */
+ bool PushToCecCommand(cec_command &command) const;
+
+ /*!
+ * @return The response messagecode.
+ */
+ cec_adapter_messagecode Reply(void) const;
+
+ uint8_t maxTries; /**< the maximum number of times to try to send this message */
+ cec_datapacket response; /**< the response to this message */
+ cec_datapacket packet; /**< the actual data */
+ cec_adapter_message_state state; /**< the current state of this message */
+ int32_t transmit_timeout; /**< the timeout to use when sending this message */
+ uint8_t lineTimeout; /**< the default CEC line timeout to use when sending this message */
+
+ private:
+ bool bNextByteIsEscaped; /**< true when the next byte that is added will be escaped, false otherwise */
};
}