X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fadapter%2FUSBCECAdapterMessage.h;h=2b122602d79b4b13e7716924f0096b57b3e03953;hb=a75e3a5a63546d6f7e670bc2a7a1931887a5d2a0;hp=4ff920a9060c8883b5461b4db289359ad463a256;hpb=fa4b80dfb92e15862041715cd3f1cbbf3f244f1e;p=deb_libcec.git diff --git a/src/lib/adapter/USBCECAdapterMessage.h b/src/lib/adapter/USBCECAdapterMessage.h index 4ff920a..2b12260 100644 --- a/src/lib/adapter/USBCECAdapterMessage.h +++ b/src/lib/adapter/USBCECAdapterMessage.h @@ -32,344 +32,179 @@ */ #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) : - event(false) - { - 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 = ToString(Message()); - - 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; - } - - static const char *ToString(cec_adapter_messagecode msgCode) - { - switch (msgCode) - { - case MSGCODE_NOTHING: - return "NOTHING"; - case MSGCODE_PING: - return "PING"; - case MSGCODE_TIMEOUT_ERROR: - return "TIMEOUT"; - case MSGCODE_HIGH_ERROR: - return "HIGH_ERROR"; - case MSGCODE_LOW_ERROR: - return "LOW_ERROR"; - case MSGCODE_FRAME_START: - return "FRAME_START"; - case MSGCODE_FRAME_DATA: - return "FRAME_DATA"; - case MSGCODE_RECEIVE_FAILED: - return "RECEIVE_FAILED"; - case MSGCODE_COMMAND_ACCEPTED: - return "COMMAND_ACCEPTED"; - case MSGCODE_COMMAND_REJECTED: - return "COMMAND_REJECTED"; - case MSGCODE_SET_ACK_MASK: - return "SET_ACK_MASK"; - case MSGCODE_TRANSMIT: - return "TRANSMIT"; - case MSGCODE_TRANSMIT_EOM: - return "TRANSMIT_EOM"; - case MSGCODE_TRANSMIT_IDLETIME: - return "TRANSMIT_IDLETIME"; - case MSGCODE_TRANSMIT_ACK_POLARITY: - return "TRANSMIT_ACK_POLARITY"; - case MSGCODE_TRANSMIT_LINE_TIMEOUT: - return "TRANSMIT_LINE_TIMEOUT"; - case MSGCODE_TRANSMIT_SUCCEEDED: - return "TRANSMIT_SUCCEEDED"; - case MSGCODE_TRANSMIT_FAILED_LINE: - return "TRANSMIT_FAILED_LINE"; - case MSGCODE_TRANSMIT_FAILED_ACK: - return "TRANSMIT_FAILED_ACK"; - case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA: - return "TRANSMIT_FAILED_TIMEOUT_DATA"; - case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE: - return "TRANSMIT_FAILED_TIMEOUT_LINE"; - case MSGCODE_FIRMWARE_VERSION: - return "FIRMWARE_VERSION"; - case MSGCODE_START_BOOTLOADER: - return "START_BOOTLOADER"; - case MSGCODE_FRAME_EOM: - return "FRAME_EOM"; - case MSGCODE_FRAME_ACK: - return "FRAME_ACK"; - case MSGCODE_SET_POWERSTATE: - return "SET_POWERSTATE"; - case MSGCODE_SET_CONTROLLED: - return "SET_CONTROLLED"; - case MSGCODE_GET_AUTO_ENABLED: - return "GET_AUTO_ENABLED"; - case MSGCODE_SET_AUTO_ENABLED: - return "SET_AUTO_ENABLED"; - case MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS: - return "GET_DEFAULT_LOGICAL_ADDRESS"; - case MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS: - return "SET_DEFAULT_LOGICAL_ADDRESS"; - case MSGCODE_GET_LOGICAL_ADDRESS_MASK: - return "GET_LOGICAL_ADDRESS_MASK"; - case MSGCODE_SET_LOGICAL_ADDRESS_MASK: - return "SET_LOGICAL_ADDRESS_MASK"; - case MSGCODE_GET_PHYSICAL_ADDRESS: - return "GET_PHYSICAL_ADDRESS"; - case MSGCODE_SET_PHYSICAL_ADDRESS: - return "SET_PHYSICAL_ADDRESS"; - case MSGCODE_GET_DEVICE_TYPE: - return "GET_DEVICE_TYPE"; - case MSGCODE_SET_DEVICE_TYPE: - return "SET_DEVICE_TYPE"; - case MSGCODE_GET_HDMI_VERSION: - return "GET_HDMI_VERSION"; - case MSGCODE_SET_HDMI_VERSION: - return "SET_HDMI_VERSION"; - case MSGCODE_GET_OSD_NAME: - return "GET_OSD_NAME"; - case MSGCODE_SET_OSD_NAME: - return "SET_OSD_NAME"; - case MSGCODE_WRITE_EEPROM: - return "WRITE_EEPROM"; - } - - return "unknown"; - } - - 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 Append(CCECAdapterMessage &data) - { - Append(data.packet); - } - - void Append(cec_datapacket &data) - { - for (uint8_t iPtr = 0; iPtr < data.size; iPtr++) - PushBack(data[iPtr]); - } - - 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::CEvent event; + /*! + * @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 iMaxTries The maximum number of tries. + * @param iLineTimeout The line timeout to use when sending this message the first time. + * @param iRetryLineTimeout The line timeout to use when retrying to send this message. + */ + CCECAdapterMessage(const cec_command &command, uint8_t iMaxTries = 1, uint8_t iLineTimeout = 3, uint8_t iRetryLineTimeout = 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 */ + uint8_t tries; /**< the amount of times this message has been sent */ + 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 */ + uint8_t retryTimeout; /**< the CEC line timeout to use when retrying to send this message */ + + private: + bool bNextByteIsEscaped; /**< true when the next byte that is added will be escaped, false otherwise */ }; }