From ef7696f555d4051a4412346939f3da4c649fb128 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Tue, 24 Jan 2012 11:20:27 +0100 Subject: [PATCH] cec: moved all adapter related code to src/lib/adapter, camelcased CAdapterMessage methods, removed unneeded m_startCondition in CAdapterCommunication (this is handled by CThread now), cosmetics. win32 needs to be synced after this --- src/lib/AdapterCommunication.h | 131 ------- src/lib/CECProcessor.cpp | 60 +-- src/lib/CECProcessor.h | 2 +- src/lib/LibCEC.cpp | 4 +- src/lib/Makefile.am | 10 +- .../{ => adapter}/AdapterCommunication.cpp | 356 ++++-------------- src/lib/adapter/AdapterCommunication.h | 80 ++++ src/lib/{ => adapter}/AdapterDetection.cpp | 0 src/lib/{ => adapter}/AdapterDetection.h | 0 src/lib/adapter/AdapterMessage.h | 355 +++++++++++++++++ 10 files changed, 546 insertions(+), 452 deletions(-) delete mode 100644 src/lib/AdapterCommunication.h rename src/lib/{ => adapter}/AdapterCommunication.cpp (54%) create mode 100644 src/lib/adapter/AdapterCommunication.h rename src/lib/{ => adapter}/AdapterDetection.cpp (100%) rename src/lib/{ => adapter}/AdapterDetection.h (100%) create mode 100644 src/lib/adapter/AdapterMessage.h diff --git a/src/lib/AdapterCommunication.h b/src/lib/AdapterCommunication.h deleted file mode 100644 index 97cd18d..0000000 --- a/src/lib/AdapterCommunication.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once -/* - * This file is part of the libCEC(R) library. - * - * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved. - * libCEC(R) is an original work, containing original code. - * - * libCEC(R) is a trademark of Pulse-Eight Limited. - * - * This program is dual-licensed; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * - * Alternatively, you can license this library under a commercial license, - * please contact Pulse-Eight Licensing for more information. - * - * For more information contact: - * Pulse-Eight Licensing - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ - -#include -#include "platform/os.h" - -namespace PLATFORM -{ - class CSerialPort; -} - -namespace CEC -{ - typedef enum cec_adapter_message_state - { - ADAPTER_MESSAGE_STATE_UNKNOWN = 0, - ADAPTER_MESSAGE_STATE_WAITING, - ADAPTER_MESSAGE_STATE_SENT, - ADAPTER_MESSAGE_STATE_RECEIVED, - ADAPTER_MESSAGE_STATE_ERROR - } cec_adapter_message_state; - - - class CCECAdapterMessage - { - public: - CCECAdapterMessage(void) { clear(); } - CCECAdapterMessage(const cec_command &command); - CCECAdapterMessage &operator =(const CCECAdapterMessage &msg); - CStdString ToString(void) const; - CStdString MessageCodeAsString(void) const; - - bool empty(void) const { return packet.IsEmpty(); } - 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; } - void clear(void) { state = ADAPTER_MESSAGE_STATE_UNKNOWN; transmit_timeout = 0; packet.Clear(); maxTries = CEC_DEFAULT_TRANSMIT_RETRIES + 1; tries = 0; reply = MSGCODE_NOTHING; } - void shift(uint8_t iShiftBy) { packet.Shift(iShiftBy); } - void push_back(uint8_t add) { packet.PushBack(add); } - 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 eom(void) const { return packet.size >= 1 ? (packet.At(0) & MSGCODE_FRAME_EOM) != 0 : false; } - bool ack(void) const { return packet.size >= 1 ? (packet.At(0) & MSGCODE_FRAME_ACK) != 0 : false; } - 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; }; - bool is_error(void) const; - void push_escaped(uint8_t byte); - bool needs_retry(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; } - - uint8_t maxTries; - uint8_t tries; - cec_adapter_messagecode reply; - cec_datapacket packet; - cec_adapter_message_state state; - int32_t transmit_timeout; - PLATFORM::CMutex mutex; - PLATFORM::CCondition condition; - }; - - class CCECProcessor; - - class CAdapterCommunication : private PLATFORM::CThread - { - public: - CAdapterCommunication(CCECProcessor *processor); - virtual ~CAdapterCommunication(); - - bool Open(const char *strPort, uint16_t iBaudRate = 38400, uint32_t iTimeoutMs = 10000); - bool Read(CCECAdapterMessage &msg, uint32_t iTimeout = 1000); - bool Write(CCECAdapterMessage *data); - bool PingAdapter(void); - void Close(void); - bool IsOpen(void); - std::string GetError(void) const; - - void *Process(void); - - bool SetLineTimeout(uint8_t iTimeout); - bool StartBootloader(void); - - private: - void SendMessageToAdapter(CCECAdapterMessage *msg); - void WriteNextCommand(void); - void AddData(uint8_t *data, uint8_t iLen); - bool ReadFromDevice(uint32_t iTimeout); - - PLATFORM::CSerialPort * m_port; - CCECProcessor * m_processor; - PLATFORM::SyncedBuffer m_inBuffer; - PLATFORM::SyncedBuffer m_outBuffer; - PLATFORM::CMutex m_mutex; - PLATFORM::CCondition m_rcvCondition; - PLATFORM::CCondition m_startCondition; - uint8_t m_iLineTimeout; - }; -}; diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index efc4f2f..dd47c0d 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -32,7 +32,7 @@ #include "CECProcessor.h" -#include "AdapterCommunication.h" +#include "adapter/AdapterMessage.h" #include "devices/CECBusDevice.h" #include "devices/CECAudioSystem.h" #include "devices/CECPlaybackDevice.h" @@ -396,7 +396,7 @@ void *CCECProcessor::Process(void) { ReplaceHandlers(); command.Clear(); - msg.clear(); + msg.Clear(); { CLockObject lock(m_mutex); @@ -848,9 +848,9 @@ bool CCECProcessor::Transmit(const cec_command &data) bReturn = Transmit(output); /* set to "not present" on failed ack */ - if (output->is_error() && output->reply == MSGCODE_TRANSMIT_FAILED_ACK && - output->destination() != CECDEVICE_BROADCAST) - m_busDevices[output->destination()]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT); + if (output->IsError() && output->reply == MSGCODE_TRANSMIT_FAILED_ACK && + output->Destination() != CECDEVICE_BROADCAST) + m_busDevices[output->Destination()]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT); delete output; return bReturn; @@ -890,7 +890,7 @@ bool CCECProcessor::Transmit(CCECAdapterMessage *output) } else bReturn = true; - }while (output->transmit_timeout > 0 && output->needs_retry() && ++output->tries < output->maxTries); + }while (output->transmit_timeout > 0 && output->NeedsRetry() && ++output->tries < output->maxTries); } m_communication->SetLineTimeout(m_iStandardLineTimeout); @@ -915,7 +915,7 @@ bool CCECProcessor::WaitForTransmitSucceeded(CCECAdapterMessage *message) { bool bError(false); bool bTransmitSucceeded(false); - uint8_t iPacketsLeft(message->size() / 4); + uint8_t iPacketsLeft(message->Size() / 4); int64_t iNow = GetTimeMs(); int64_t iTargetTime = iNow + message->transmit_timeout; @@ -930,16 +930,16 @@ bool CCECProcessor::WaitForTransmitSucceeded(CCECAdapterMessage *message) continue; } - if (msg.message() == MSGCODE_FRAME_START && msg.ack()) + if (msg.Message() == MSGCODE_FRAME_START && msg.IsACK()) { - m_busDevices[msg.initiator()]->GetHandler()->HandlePoll(msg.initiator(), msg.destination()); - m_lastInitiator = msg.initiator(); + m_busDevices[msg.Initiator()]->GetHandler()->HandlePoll(msg.Initiator(), msg.Destination()); + m_lastInitiator = msg.Initiator(); iNow = GetTimeMs(); continue; } - bError = msg.is_error(); - if (msg.message() == MSGCODE_RECEIVE_FAILED && + bError = msg.IsError(); + if (msg.Message() == MSGCODE_RECEIVE_FAILED && m_lastInitiator != CECDEVICE_UNKNOWN && !m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed()) { @@ -949,12 +949,12 @@ bool CCECProcessor::WaitForTransmitSucceeded(CCECAdapterMessage *message) if (bError) { - message->reply = msg.message(); + message->reply = msg.Message(); m_controller->AddLog(CEC_LOG_DEBUG, msg.ToString()); } else { - switch(msg.message()) + switch(msg.Message()) { case MSGCODE_COMMAND_ACCEPTED: m_controller->AddLog(CEC_LOG_DEBUG, msg.ToString()); @@ -982,22 +982,22 @@ bool CCECProcessor::WaitForTransmitSucceeded(CCECAdapterMessage *message) bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg) { bool bEom(false); - bool bIsError(msg.is_error()); + bool bIsError(msg.IsError()); - if (msg.empty()) + if (msg.IsEmpty()) return bEom; - switch(msg.message()) + switch(msg.Message()) { case MSGCODE_FRAME_START: { m_currentframe.Clear(); - if (msg.size() >= 2) + if (msg.Size() >= 2) { - m_currentframe.initiator = msg.initiator(); - m_currentframe.destination = msg.destination(); - m_currentframe.ack = msg.ack(); - m_currentframe.eom = msg.eom(); + m_currentframe.initiator = msg.Initiator(); + m_currentframe.destination = msg.Destination(); + m_currentframe.ack = msg.IsACK(); + m_currentframe.eom = msg.IsEOM(); } if (m_currentframe.ack == 0x1) { @@ -1014,12 +1014,12 @@ bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg) break; case MSGCODE_FRAME_DATA: { - if (msg.size() >= 2) + if (msg.Size() >= 2) { m_currentframe.PushBack(msg[1]); - m_currentframe.eom = msg.eom(); + m_currentframe.eom = msg.IsEOM(); } - bEom = msg.eom(); + bEom = msg.IsEOM(); } break; default: @@ -1111,11 +1111,11 @@ bool CCECProcessor::SetAckMask(uint16_t iMask) CCECAdapterMessage *output = new CCECAdapterMessage; - output->push_back(MSGSTART); - output->push_escaped(MSGCODE_SET_ACK_MASK); - output->push_escaped(iMask >> 8); - output->push_escaped((uint8_t)iMask); - output->push_back(MSGEND); + output->PushBack(MSGSTART); + output->PushEscaped(MSGCODE_SET_ACK_MASK); + output->PushEscaped(iMask >> 8); + output->PushEscaped((uint8_t)iMask); + output->PushBack(MSGEND); if ((bReturn = Transmit(output)) == false) m_controller->AddLog(CEC_LOG_ERROR, "could not set the ackmask"); diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index e4f0a6b..55286f8 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -33,7 +33,7 @@ #include #include -#include "AdapterCommunication.h" +#include "adapter/AdapterCommunication.h" #include "platform/os.h" class CSerialPort; diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index 29cc3f4..db141f3 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -32,8 +32,8 @@ #include "LibCEC.h" -#include "AdapterCommunication.h" -#include "AdapterDetection.h" +#include "adapter/AdapterCommunication.h" +#include "adapter/AdapterDetection.h" #include "CECProcessor.h" #include "devices/CECBusDevice.h" #include "platform/timeutils.h" diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 9ccd4c7..cd20766 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -8,15 +8,15 @@ library_include_HEADERS = ../../include/cec.h \ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libcec.pc -libcec_la_SOURCES = AdapterCommunication.cpp \ - AdapterDetection.cpp \ - CECProcessor.cpp \ +libcec_la_SOURCES = CECProcessor.cpp \ LibCEC.cpp \ LibCECC.cpp \ - devices/CECAudioSystem.cpp \ + adapter/AdapterCommunication.cpp \ + adapter/AdapterDetection.cpp \ + devices/CECAudioSystem.cpp \ devices/CECBusDevice.cpp \ devices/CECPlaybackDevice.cpp \ - devices/CECRecordingDevice.cpp \ + devices/CECRecordingDevice.cpp \ devices/CECTuner.cpp \ devices/CECTV.cpp \ implementations/ANCommandHandler.cpp \ diff --git a/src/lib/AdapterCommunication.cpp b/src/lib/adapter/AdapterCommunication.cpp similarity index 54% rename from src/lib/AdapterCommunication.cpp rename to src/lib/adapter/AdapterCommunication.cpp index faa15aa..4a136ab 100644 --- a/src/lib/AdapterCommunication.cpp +++ b/src/lib/adapter/AdapterCommunication.cpp @@ -32,6 +32,7 @@ #include "AdapterCommunication.h" +#include "AdapterMessage.h" #include "CECProcessor.h" #include "platform/serialport/serialport.h" @@ -39,210 +40,6 @@ using namespace std; using namespace CEC; using namespace PLATFORM; -CCECAdapterMessage::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 - push_back(MSGSTART); - push_escaped(MSGCODE_TRANSMIT_ACK_POLARITY); - if (command.destination == CECDEVICE_BROADCAST) - push_escaped(CEC_TRUE); - else - push_escaped(CEC_FALSE); - push_back(MSGEND); - - // add source and destination - push_back(MSGSTART); - push_escaped(command.opcode_set == 0 ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT); - push_back(((uint8_t)command.initiator << 4) + (uint8_t)command.destination); - push_back(MSGEND); - - // add opcode - if (command.opcode_set == 1) - { - push_back(MSGSTART); - push_escaped(command.parameters.IsEmpty() ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT); - push_back((uint8_t) command.opcode); - push_back(MSGEND); - - // add parameters - for (int8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) - { - push_back(MSGSTART); - - if (iPtr == command.parameters.size - 1) - push_escaped( MSGCODE_TRANSMIT_EOM); - else - push_escaped(MSGCODE_TRANSMIT); - - push_escaped(command.parameters[iPtr]); - - push_back(MSGEND); - } - } - - // set timeout - transmit_timeout = command.transmit_timeout; -} - -CCECAdapterMessage &CCECAdapterMessage::operator =(const CCECAdapterMessage &msg) -{ - packet = msg.packet; - state = msg.state; - return *this; -} - -CStdString CCECAdapterMessage::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; -} - -CStdString CCECAdapterMessage::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(), ack() ? "high" : "low", eom() ? "eom" : ""); - break; - case MSGCODE_FRAME_DATA: - if (size() >= 2) - strMsg.AppendFormat(" %02x %s", at(1), eom() ? "eom" : ""); - break; - default: - break; - } - } - - return strMsg; -} - -bool CCECAdapterMessage::is_error(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); -} - -void CCECAdapterMessage::push_escaped(uint8_t byte) -{ - if (byte >= MSGESC) - { - push_back(MSGESC); - push_back(byte - ESCOFFSET); - } - else - push_back(byte); -} - CAdapterCommunication::CAdapterCommunication(CCECProcessor *processor) : m_port(NULL), m_processor(processor), @@ -307,13 +104,12 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38 if (CreateThread()) { - m_startCondition.Wait(m_mutex); m_processor->AddLog(CEC_LOG_DEBUG, "communication thread started"); return true; } else { - m_processor->AddLog(CEC_LOG_DEBUG, "could not create a communication thread"); + m_processor->AddLog(CEC_LOG_ERROR, "could not create a communication thread"); } return false; @@ -322,18 +118,12 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38 void CAdapterCommunication::Close(void) { CLockObject lock(m_mutex); - m_startCondition.Broadcast(); m_rcvCondition.Broadcast(); StopThread(); } void *CAdapterCommunication::Process(void) { - { - CLockObject lock(m_mutex); - m_startCondition.Signal(); - } - while (!IsStopped()) { ReadFromDevice(50); @@ -341,68 +131,13 @@ void *CAdapterCommunication::Process(void) WriteNextCommand(); } - CCECAdapterMessage *msg; + CCECAdapterMessage *msg(NULL); if (m_outBuffer.Pop(msg)) msg->condition.Broadcast(); return NULL; } -bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout) -{ - int32_t iBytesRead; - uint8_t buff[1024]; - if (!m_port) - return false; - - iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout); - if (iBytesRead < 0 || iBytesRead > 256) - { - CStdString strError; - strError.Format("error reading from serial port: %s", m_port->GetError().c_str()); - m_processor->AddLog(CEC_LOG_ERROR, strError); - return false; - } - else if (iBytesRead > 0) - AddData(buff, (uint8_t) iBytesRead); - - return iBytesRead > 0; -} - -void CAdapterCommunication::AddData(uint8_t *data, uint8_t iLen) -{ - CLockObject lock(m_mutex); - for (uint8_t iPtr = 0; iPtr < iLen; iPtr++) - m_inBuffer.Push(data[iPtr]); - - m_rcvCondition.Signal(); -} - -void CAdapterCommunication::WriteNextCommand(void) -{ - CCECAdapterMessage *msg; - if (m_outBuffer.Pop(msg)) - SendMessageToAdapter(msg); -} - -void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg) -{ - CLockObject lock(msg->mutex); - if (m_port->Write(msg->packet.data, msg->size()) != (int32_t) msg->size()) - { - CStdString strError; - strError.Format("error writing to serial port: %s", m_port->GetError().c_str()); - m_processor->AddLog(CEC_LOG_ERROR, strError); - msg->state = ADAPTER_MESSAGE_STATE_ERROR; - } - else - { - m_processor->AddLog(CEC_LOG_DEBUG, "command sent"); - msg->state = ADAPTER_MESSAGE_STATE_SENT; - } - msg->condition.Signal(); -} - bool CAdapterCommunication::Write(CCECAdapterMessage *data) { data->state = ADAPTER_MESSAGE_STATE_WAITING; @@ -414,7 +149,7 @@ bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout) { CLockObject lock(m_mutex); - msg.clear(); + msg.Clear(); uint64_t iNow = GetTimeMs(); uint64_t iTarget = iNow + iTimeout; bool bGotFullMessage(false); @@ -438,9 +173,9 @@ bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout) } else if (buf == MSGSTART) //we found a msgstart before msgend, this is not right, remove { - if (msg.size() > 0) + if (msg.Size() > 0) m_processor->AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents"); - msg.clear(); + msg.Clear(); bGotStart = true; } @@ -450,13 +185,13 @@ bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout) } else if (bNextIsEscaped) { - msg.push_back(buf + (uint8_t)ESCOFFSET); + msg.PushBack(buf + (uint8_t)ESCOFFSET); bNextIsEscaped = false; } else if (buf == MSGESC) bNextIsEscaped = true; else - msg.push_back(buf); + msg.PushBack(buf); } if (bGotFullMessage) @@ -479,9 +214,9 @@ bool CAdapterCommunication::StartBootloader(void) m_processor->AddLog(CEC_LOG_DEBUG, "starting the bootloader"); CCECAdapterMessage *output = new CCECAdapterMessage; - output->push_back(MSGSTART); - output->push_escaped(MSGCODE_START_BOOTLOADER); - output->push_back(MSGEND); + output->PushBack(MSGSTART); + output->PushEscaped(MSGCODE_START_BOOTLOADER); + output->PushBack(MSGEND); CLockObject lock(output->mutex); if (Write(output)) @@ -501,9 +236,9 @@ bool CAdapterCommunication::PingAdapter(void) m_processor->AddLog(CEC_LOG_DEBUG, "sending ping"); CCECAdapterMessage *output = new CCECAdapterMessage; - output->push_back(MSGSTART); - output->push_escaped(MSGCODE_PING); - output->push_back(MSGEND); + output->PushBack(MSGSTART); + output->PushEscaped(MSGCODE_PING); + output->PushBack(MSGEND); CLockObject lock(output->mutex); if (Write(output)) @@ -522,10 +257,10 @@ bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout) { CCECAdapterMessage *output = new CCECAdapterMessage; - output->push_back(MSGSTART); - output->push_escaped(MSGCODE_TRANSMIT_IDLETIME); - output->push_escaped(iTimeout); - output->push_back(MSGEND); + output->PushBack(MSGSTART); + output->PushEscaped(MSGCODE_TRANSMIT_IDLETIME); + output->PushEscaped(iTimeout); + output->PushBack(MSGEND); if ((bReturn = Write(output)) == false) m_processor->AddLog(CEC_LOG_ERROR, "could not set the idletime"); @@ -539,3 +274,58 @@ bool CAdapterCommunication::IsOpen(void) { return !IsStopped() && m_port->IsOpen() && IsRunning(); } + +void CAdapterCommunication::AddData(uint8_t *data, uint8_t iLen) +{ + CLockObject lock(m_mutex); + for (uint8_t iPtr = 0; iPtr < iLen; iPtr++) + m_inBuffer.Push(data[iPtr]); + + m_rcvCondition.Signal(); +} + +bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout) +{ + int32_t iBytesRead; + uint8_t buff[1024]; + if (!m_port) + return false; + + iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout); + if (iBytesRead < 0 || iBytesRead > 256) + { + CStdString strError; + strError.Format("error reading from serial port: %s", m_port->GetError().c_str()); + m_processor->AddLog(CEC_LOG_ERROR, strError); + return false; + } + else if (iBytesRead > 0) + AddData(buff, (uint8_t) iBytesRead); + + return iBytesRead > 0; +} + +void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg) +{ + CLockObject lock(msg->mutex); + if (m_port->Write(msg->packet.data, msg->Size()) != (int32_t) msg->Size()) + { + CStdString strError; + strError.Format("error writing to serial port: %s", m_port->GetError().c_str()); + m_processor->AddLog(CEC_LOG_ERROR, strError); + msg->state = ADAPTER_MESSAGE_STATE_ERROR; + } + else + { + m_processor->AddLog(CEC_LOG_DEBUG, "command sent"); + msg->state = ADAPTER_MESSAGE_STATE_SENT; + } + msg->condition.Signal(); +} + +void CAdapterCommunication::WriteNextCommand(void) +{ + CCECAdapterMessage *msg(NULL); + if (m_outBuffer.Pop(msg)) + SendMessageToAdapter(msg); +} diff --git a/src/lib/adapter/AdapterCommunication.h b/src/lib/adapter/AdapterCommunication.h new file mode 100644 index 0000000..4367e40 --- /dev/null +++ b/src/lib/adapter/AdapterCommunication.h @@ -0,0 +1,80 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include +#include "platform/os.h" + +namespace PLATFORM +{ + class CSerialPort; +} + +namespace CEC +{ + class CCECProcessor; + class CCECAdapterMessage; + + class CAdapterCommunication : private PLATFORM::CThread + { + public: + CAdapterCommunication(CCECProcessor *processor); + virtual ~CAdapterCommunication(); + + bool Open(const char *strPort, uint16_t iBaudRate = 38400, uint32_t iTimeoutMs = 10000); + bool Read(CCECAdapterMessage &msg, uint32_t iTimeout = 1000); + bool Write(CCECAdapterMessage *data); + bool PingAdapter(void); + void Close(void); + bool IsOpen(void); + std::string GetError(void) const; + + void *Process(void); + + bool SetLineTimeout(uint8_t iTimeout); + bool StartBootloader(void); + + private: + void SendMessageToAdapter(CCECAdapterMessage *msg); + void WriteNextCommand(void); + void AddData(uint8_t *data, uint8_t iLen); + bool ReadFromDevice(uint32_t iTimeout); + + PLATFORM::CSerialPort * m_port; + CCECProcessor * m_processor; + PLATFORM::SyncedBuffer m_inBuffer; + PLATFORM::SyncedBuffer m_outBuffer; + PLATFORM::CMutex m_mutex; + PLATFORM::CCondition m_rcvCondition; + uint8_t m_iLineTimeout; + }; +}; diff --git a/src/lib/AdapterDetection.cpp b/src/lib/adapter/AdapterDetection.cpp similarity index 100% rename from src/lib/AdapterDetection.cpp rename to src/lib/adapter/AdapterDetection.cpp diff --git a/src/lib/AdapterDetection.h b/src/lib/adapter/AdapterDetection.h similarity index 100% rename from src/lib/AdapterDetection.h rename to src/lib/adapter/AdapterDetection.h diff --git a/src/lib/adapter/AdapterMessage.h b/src/lib/adapter/AdapterMessage.h new file mode 100644 index 0000000..4fadbed --- /dev/null +++ b/src/lib/adapter/AdapterMessage.h @@ -0,0 +1,355 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +namespace CEC +{ + typedef enum cec_adapter_message_state + { + ADAPTER_MESSAGE_STATE_UNKNOWN = 0, + ADAPTER_MESSAGE_STATE_WAITING, + ADAPTER_MESSAGE_STATE_SENT, + ADAPTER_MESSAGE_STATE_RECEIVED, + ADAPTER_MESSAGE_STATE_ERROR + } 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; + } + + 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 = 0; + packet.Clear(); + maxTries = CEC_DEFAULT_TRANSMIT_RETRIES + 1; + tries = 0; + reply = MSGCODE_NOTHING; + } + + 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; + PLATFORM::CMutex mutex; + PLATFORM::CCondition condition; + }; +} -- 2.34.1