+++ /dev/null
-#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 <license@pulse-eight.com>
- * http://www.pulse-eight.com/
- * http://www.pulse-eight.net/
- */
-
-#include <cectypes.h>
-#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<uint8_t> m_inBuffer;
- PLATFORM::SyncedBuffer<CCECAdapterMessage *> m_outBuffer;
- PLATFORM::CMutex m_mutex;
- PLATFORM::CCondition m_rcvCondition;
- PLATFORM::CCondition m_startCondition;
- uint8_t m_iLineTimeout;
- };
-};
#include "CECProcessor.h"
-#include "AdapterCommunication.h"
+#include "adapter/AdapterMessage.h"
#include "devices/CECBusDevice.h"
#include "devices/CECAudioSystem.h"
#include "devices/CECPlaybackDevice.h"
{
ReplaceHandlers();
command.Clear();
- msg.clear();
+ msg.Clear();
{
CLockObject lock(m_mutex);
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;
}
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);
{
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;
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())
{
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());
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)
{
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:
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");
#include <string>
#include <cectypes.h>
-#include "AdapterCommunication.h"
+#include "adapter/AdapterCommunication.h"
#include "platform/os.h"
class CSerialPort;
#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"
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 \
#include "AdapterCommunication.h"
+#include "AdapterMessage.h"
#include "CECProcessor.h"
#include "platform/serialport/serialport.h"
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),
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;
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);
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;
{
CLockObject lock(m_mutex);
- msg.clear();
+ msg.Clear();
uint64_t iNow = GetTimeMs();
uint64_t iTarget = iNow + iTimeout;
bool bGotFullMessage(false);
}
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;
}
}
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)
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))
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))
{
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");
{
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);
+}
--- /dev/null
+#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 <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include <cectypes.h>
+#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<uint8_t> m_inBuffer;
+ PLATFORM::SyncedBuffer<CCECAdapterMessage *> m_outBuffer;
+ PLATFORM::CMutex m_mutex;
+ PLATFORM::CCondition m_rcvCondition;
+ uint8_t m_iLineTimeout;
+ };
+};
--- /dev/null
+#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 <license@pulse-eight.com>
+ * 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;
+ };
+}