replaced by BusHandler
This commit is contained in:
@@ -1,700 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd 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 ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "busloop.h"
|
||||
#include "logger.h"
|
||||
#include "appl.h"
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern Logger& L;
|
||||
extern Appl& A;
|
||||
|
||||
BusMessage::BusMessage(const string command, const bool poll, const bool scan)
|
||||
: m_poll(poll), m_scan(scan), m_command(command), m_result(), m_resultCode(RESULT_OK)
|
||||
{
|
||||
unsigned char dstAddress = m_command[1];
|
||||
|
||||
if (dstAddress == BROADCAST)
|
||||
m_type = broadcast;
|
||||
else if (isMaster(dstAddress) == true)
|
||||
m_type = masterMaster;
|
||||
else
|
||||
m_type = masterSlave;
|
||||
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_cond_init(&m_cond, NULL);
|
||||
}
|
||||
|
||||
const string BusMessage::getMessageStr()
|
||||
{
|
||||
string result;
|
||||
|
||||
if (m_resultCode >= 0) {
|
||||
if (m_type == masterSlave) {
|
||||
result = m_command.getDataStr();
|
||||
result += "00";
|
||||
result += m_result.getDataStr();
|
||||
result += "00";
|
||||
}
|
||||
else
|
||||
result = "success";
|
||||
}
|
||||
else
|
||||
result = "error: "+string(getResultCodeCStr());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
BusLoop::BusLoop(Commands* commands)
|
||||
: m_commands(commands), m_running(true), m_lockCounter(0),
|
||||
m_priorRetry(false), m_scan(false), m_scanFull(false), m_scanIndex(0)
|
||||
{
|
||||
m_port = new Port(A.getOptVal<const char*>("device"), A.getOptVal<bool>("nodevicecheck"));
|
||||
m_port->open();
|
||||
|
||||
if (m_port->isOpen() == false)
|
||||
L.log(bus, error, "can't open %s", A.getOptVal<const char*>("device"));
|
||||
|
||||
m_dumpFile = A.getOptVal<const char*>("dumpfile");
|
||||
m_dumpSize = A.getOptVal<long>("dumpsize");
|
||||
m_dumping = A.getOptVal<bool>("dump");
|
||||
|
||||
m_logRawData = A.getOptVal<bool>("lograwdata");
|
||||
|
||||
m_pollInterval = A.getOptVal<int>("pollinterval");
|
||||
|
||||
m_recvTimeout = A.getOptVal<long>("recvtimeout");
|
||||
|
||||
m_sendRetries = A.getOptVal<int>("sendretries");
|
||||
|
||||
m_lockRetries = A.getOptVal<int>("lockretries");
|
||||
|
||||
m_acquireTime = A.getOptVal<long>("acquiretime");
|
||||
}
|
||||
|
||||
BusLoop::~BusLoop()
|
||||
{
|
||||
if (m_port->isOpen() == true)
|
||||
m_port->close();
|
||||
|
||||
delete m_port;
|
||||
}
|
||||
|
||||
void* BusLoop::run()
|
||||
{
|
||||
int sendRetries = 0;
|
||||
int lockRetries = 0;
|
||||
|
||||
// polling
|
||||
time_t pollStart, pollEnd;
|
||||
time(&pollStart);
|
||||
double pollDelta;
|
||||
|
||||
for (;;) {
|
||||
if (m_port->isOpen() == true) {
|
||||
ssize_t numBytes;
|
||||
|
||||
// add poll or scan command
|
||||
if (m_commands->sizePollDB() > 0 || m_scan == true) {
|
||||
// check polling delta
|
||||
time(&pollEnd);
|
||||
pollDelta = difftime(pollEnd, pollStart);
|
||||
|
||||
// add new polling command to send
|
||||
if (pollDelta >= m_pollInterval) {
|
||||
if (m_scan == true)
|
||||
addScanMessage();
|
||||
else
|
||||
addPollMessage();
|
||||
|
||||
time(&pollStart);
|
||||
}
|
||||
}
|
||||
|
||||
// read device - no timeout needed (AUTO-SYN)
|
||||
numBytes = m_port->recv(0);
|
||||
|
||||
if (numBytes < 0) {
|
||||
L.log(bus, error, " ERR_DEVICE: generic device error");
|
||||
continue;
|
||||
}
|
||||
|
||||
// cycle bytes
|
||||
collectCycData(numBytes);
|
||||
|
||||
// send command
|
||||
if (m_sstr.size() == 0 && m_lockCounter == 0 && m_busQueue.size() > 0) {
|
||||
// acquire Bus
|
||||
int busResult = acquireBus();
|
||||
|
||||
// send bus command
|
||||
if (busResult == RESULT_BUS_ACQUIRED) {
|
||||
BusMessage* message = sendCommand();
|
||||
L.log(bus, trace, " %s", message->getMessageStr().c_str());
|
||||
|
||||
if (message->isErrorResult() == true) {
|
||||
if (sendRetries < m_sendRetries) {
|
||||
sendRetries++;
|
||||
L.log(bus, trace, " send retry %d", sendRetries);
|
||||
message->setResult(string(), RESULT_OK);
|
||||
}
|
||||
else {
|
||||
sendRetries = 0;
|
||||
L.log(bus, event, " send retry failed", sendRetries);
|
||||
|
||||
if (message->isPoll() == true)
|
||||
delete m_busQueue.remove();
|
||||
else
|
||||
message->sendSignal();
|
||||
}
|
||||
}
|
||||
else {
|
||||
sendRetries = 0;
|
||||
|
||||
if (message->isPoll() == true) {
|
||||
if (message->isScan() == true)
|
||||
m_commands->storeScanData(message->getMessageStr().c_str());
|
||||
else
|
||||
m_commands->storePollData(message->getMessageStr().c_str()); // TODO use getResult()
|
||||
delete message;
|
||||
}
|
||||
else
|
||||
message->sendSignal();
|
||||
}
|
||||
|
||||
lockRetries = 0;
|
||||
m_lockCounter = A.getOptVal<int>("lockcounter");
|
||||
}
|
||||
else if (busResult == RESULT_ERR_BUS_LOST) {
|
||||
L.log(bus, trace, " acquire bus failed");
|
||||
|
||||
if (lockRetries >= m_lockRetries) {
|
||||
lockRetries = 0;
|
||||
L.log(bus, event, " lock bus failed");
|
||||
|
||||
BusMessage* message = m_busQueue.remove();
|
||||
if (message->isPoll() == true)
|
||||
delete message;
|
||||
else
|
||||
message->sendSignal();
|
||||
}
|
||||
else {
|
||||
lockRetries++;
|
||||
L.log(bus, trace, " lock retry %d", lockRetries);
|
||||
}
|
||||
|
||||
m_lockCounter = A.getOptVal<int>("lockcounter");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
// TODO: define max reopen
|
||||
sleep(10);
|
||||
m_port->open();
|
||||
|
||||
if (m_port->isOpen() == false)
|
||||
L.log(bus, error, "can't open %s", A.getOptVal<const char*>("device"));
|
||||
|
||||
}
|
||||
|
||||
if (m_running == false) {
|
||||
if (m_port->isOpen() == true)
|
||||
m_port->close();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int BusLoop::writeDumpFile(const char* byte)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ofstream fs(m_dumpFile.c_str(), ios::out | ios::binary | ios::app);
|
||||
|
||||
if (fs == 0)
|
||||
return -1;
|
||||
|
||||
fs.write(byte, 1);
|
||||
|
||||
if (fs.tellp() >= m_dumpSize * 1024) {
|
||||
string oldfile;
|
||||
oldfile += m_dumpFile;
|
||||
oldfile += ".old";
|
||||
ret = rename(m_dumpFile.c_str(), oldfile.c_str());
|
||||
}
|
||||
|
||||
fs.close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char BusLoop::fetchByte()
|
||||
{
|
||||
unsigned char byte;
|
||||
|
||||
// fetch byte
|
||||
byte = m_port->byte();
|
||||
|
||||
if (m_dumping == true)
|
||||
writeDumpFile((const char*) &byte);
|
||||
|
||||
if (m_logRawData == true)
|
||||
L.log(bus, event, "%02x", byte);
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
void BusLoop::collectCycData(const int numRecv)
|
||||
{
|
||||
// cycle bytes
|
||||
for (int i = 0; i < numRecv; i++) {
|
||||
|
||||
// fetch byte
|
||||
unsigned char byte = fetchByte();
|
||||
|
||||
if (byte == SYN) {
|
||||
|
||||
// analyse cycle data
|
||||
if (m_sstr.size() > 0) {
|
||||
|
||||
analyseCycData();
|
||||
|
||||
if (m_sstr.size() == 1 && m_lockCounter == 0 && m_priorRetry == false)
|
||||
m_lockCounter++;
|
||||
|
||||
else if (m_lockCounter > 0)
|
||||
m_lockCounter--;
|
||||
|
||||
m_sstr.clear();
|
||||
}
|
||||
|
||||
else if (m_lockCounter > 0)
|
||||
m_lockCounter--;
|
||||
|
||||
}
|
||||
|
||||
// collect cycle data
|
||||
else
|
||||
m_sstr.push_back(byte, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
void BusLoop::analyseCycData()
|
||||
{
|
||||
static bool skipfirst = false;
|
||||
|
||||
if (skipfirst == true) {
|
||||
L.log(cyc, trace, "%s", m_sstr.getDataStr().c_str());
|
||||
|
||||
int index = m_commands->storeCycData(m_sstr.getDataStr());
|
||||
|
||||
if (index == -1) {
|
||||
L.log(cyc, debug, " command not found");
|
||||
}
|
||||
else if (index == -2) {
|
||||
L.log(cyc, debug, " no commands defined");
|
||||
}
|
||||
else if (index == -3) {
|
||||
L.log(cyc, debug, " search skipped - string too short");
|
||||
}
|
||||
else {
|
||||
string tmp;
|
||||
tmp += (*m_commands)[index][1];
|
||||
tmp += " ";
|
||||
tmp += (*m_commands)[index][2];
|
||||
L.log(cyc, event, " cycle [%4d] %s", index, tmp.c_str());
|
||||
}
|
||||
|
||||
// collect Slave address
|
||||
if (index != -3)
|
||||
collectSlave();
|
||||
}
|
||||
else
|
||||
skipfirst = true;
|
||||
}
|
||||
|
||||
void BusLoop::collectSlave()
|
||||
{
|
||||
vector<unsigned char>::iterator it;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
bool found = false;
|
||||
unsigned char mm = m_sstr[i];
|
||||
|
||||
if (i == 0) {
|
||||
if (mm == 0xFF)
|
||||
mm = 0x04;
|
||||
else
|
||||
mm += 0x05;
|
||||
}
|
||||
|
||||
for (it = m_slave.begin(); it != m_slave.end(); it++)
|
||||
if ((*it) == mm)
|
||||
found = true;
|
||||
|
||||
if (found == false && isMaster(mm) == false && mm != BROADCAST) {
|
||||
m_slave.push_back(mm);
|
||||
L.log(bus, event, " new slave: %d %02x", m_slave.size(), m_slave.back());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BusLoop::acquireBus()
|
||||
{
|
||||
unsigned char recvByte, sendByte;
|
||||
ssize_t numRecv, numSend;
|
||||
|
||||
sendByte = m_busQueue.next()->getCommand()[0];
|
||||
|
||||
// send QQ
|
||||
numSend = m_port->send(&sendByte);
|
||||
if (numSend <= 0) {
|
||||
L.log(bus, error, " ERR_SEND: send error");
|
||||
return RESULT_ERR_SEND;
|
||||
}
|
||||
|
||||
// wait ~4200 usec for receive
|
||||
usleep(m_acquireTime);
|
||||
|
||||
// receive 1 byte - must be QQ
|
||||
numRecv = m_port->recv(0);
|
||||
|
||||
if (numRecv < 0) {
|
||||
L.log(bus, error, " ERR_DEVICE: generic device error");
|
||||
return RESULT_ERR_DEVICE;
|
||||
}
|
||||
|
||||
if (numRecv == 1) {
|
||||
// fetch byte
|
||||
recvByte = fetchByte();
|
||||
|
||||
// compare sent and received byte
|
||||
if (sendByte == recvByte) {
|
||||
L.log(bus, trace, " bus acquired");
|
||||
return RESULT_BUS_ACQUIRED;
|
||||
}
|
||||
|
||||
// collect cycle data
|
||||
if (recvByte != SYN)
|
||||
m_sstr.push_back(recvByte, true, false);
|
||||
|
||||
// compare prior nibble for retry
|
||||
if ((sendByte & 0x0F) == (recvByte & 0x0F)) {
|
||||
m_priorRetry = true;
|
||||
L.log(bus, trace, " bus prior retry");
|
||||
return RESULT_BUS_PRIOR_RETRY;
|
||||
}
|
||||
|
||||
L.log(bus, error, " ERR_BUS_LOST: lost bus arbitration");
|
||||
return RESULT_ERR_BUS_LOST;
|
||||
}
|
||||
|
||||
// cycle bytes
|
||||
collectCycData(numRecv);
|
||||
|
||||
L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes");
|
||||
return RESULT_ERR_EXTRA_DATA;
|
||||
}
|
||||
|
||||
BusMessage* BusLoop::sendCommand()
|
||||
{
|
||||
unsigned char recvByte;
|
||||
string result;
|
||||
SymbolString slaveData;
|
||||
int retval = RESULT_OK;
|
||||
|
||||
BusMessage* message = m_busQueue.next();
|
||||
|
||||
// send ZZ PB SB NN Dx CRC
|
||||
SymbolString command = message->getCommand();
|
||||
for (size_t i = 1; i < command.size(); i++) {
|
||||
retval = sendByte(command[i]);
|
||||
if (retval < 0)
|
||||
goto on_exit;
|
||||
}
|
||||
|
||||
// BC -> send SYN
|
||||
if (message->getType() == broadcast) {
|
||||
sendByte(SYN);
|
||||
goto on_exit;
|
||||
}
|
||||
|
||||
// receive ACK
|
||||
retval = recvSlaveAck(recvByte);
|
||||
if (retval < 0)
|
||||
goto on_exit;
|
||||
|
||||
// is slave ACK negative?
|
||||
if (recvByte == NAK) {
|
||||
|
||||
// send QQ ZZ PB SB NN Dx CRC again
|
||||
for (size_t i = 0; i < command.size(); i++) {
|
||||
retval = sendByte(command[i]);
|
||||
if (retval < 0)
|
||||
goto on_exit;
|
||||
}
|
||||
|
||||
// receive ACK
|
||||
retval = recvSlaveAck(recvByte);
|
||||
if (retval < 0)
|
||||
goto on_exit;
|
||||
|
||||
// is slave ACK negative?
|
||||
if (recvByte == NAK) {
|
||||
sendByte(SYN);
|
||||
L.log(bus, error, " ERR_NAK: NAK received");
|
||||
retval = RESULT_ERR_NAK;
|
||||
goto on_exit;
|
||||
}
|
||||
}
|
||||
|
||||
// MM -> send SYN
|
||||
if (message->getType() == masterMaster) {
|
||||
sendByte(SYN);
|
||||
goto on_exit;
|
||||
}
|
||||
|
||||
// receive NN, Dx, CRC
|
||||
retval = recvSlaveData(slaveData);
|
||||
|
||||
// are calculated and received CRC equal?
|
||||
if (retval == RESULT_ERR_CRC) {
|
||||
|
||||
// send NAK
|
||||
retval = sendByte(NAK);
|
||||
if (retval < 0)
|
||||
goto on_exit;
|
||||
|
||||
// receive NN, Dx, CRC
|
||||
slaveData.clear();
|
||||
retval = recvSlaveData(slaveData);
|
||||
|
||||
// are calculated and received CRC equal?
|
||||
if (retval == RESULT_ERR_CRC) {
|
||||
|
||||
// send NAK
|
||||
retval = sendByte(NAK);
|
||||
if (retval >= 0)
|
||||
retval = RESULT_ERR_CRC;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval < 0)
|
||||
goto on_exit;
|
||||
|
||||
// send ACK
|
||||
retval = sendByte(ACK);
|
||||
if (retval == -1) {
|
||||
L.log(bus, error, " ERR_ACK: ACK error");
|
||||
retval = RESULT_ERR_ACK;
|
||||
goto on_exit;
|
||||
}
|
||||
|
||||
// MS -> send SYN
|
||||
sendByte(SYN);
|
||||
|
||||
on_exit:
|
||||
|
||||
// empty receive buffer
|
||||
while (m_port->size() != 0)
|
||||
recvByte = fetchByte();
|
||||
|
||||
message->setResult(slaveData, retval);
|
||||
|
||||
if (retval == RESULT_OK)
|
||||
return m_busQueue.remove();
|
||||
else
|
||||
return message;
|
||||
|
||||
}
|
||||
|
||||
int BusLoop::sendByte(const unsigned char sendByte)
|
||||
{
|
||||
unsigned char recvByte;
|
||||
ssize_t numRecv, numSend;
|
||||
|
||||
numSend = m_port->send(&sendByte);
|
||||
|
||||
// receive 1 byte - must be equal
|
||||
numRecv = m_port->recv(RECV_TIMEOUT);
|
||||
|
||||
if (numSend != numRecv) {
|
||||
L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes");
|
||||
return RESULT_ERR_EXTRA_DATA;
|
||||
}
|
||||
|
||||
recvByte = fetchByte();
|
||||
|
||||
if (sendByte != recvByte) {
|
||||
L.log(bus, error, " ERR_SEND: send error");
|
||||
return RESULT_ERR_SEND;
|
||||
}
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
int BusLoop::recvSlaveAck(unsigned char& recvByte)
|
||||
{
|
||||
ssize_t numRecv;
|
||||
|
||||
// receive ACK
|
||||
numRecv = m_port->recv(m_recvTimeout);
|
||||
|
||||
if (numRecv > 1) {
|
||||
L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes");
|
||||
return RESULT_ERR_EXTRA_DATA;
|
||||
}
|
||||
else if (numRecv < 0) {
|
||||
L.log(bus, error, " ERR_TIMEOUT: read timeout");
|
||||
return RESULT_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
recvByte = fetchByte();
|
||||
|
||||
// is received byte SYN?
|
||||
if (recvByte == SYN) {
|
||||
L.log(bus, error, " ERR_SYN: SYN received");
|
||||
return RESULT_ERR_SYN;
|
||||
}
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
int BusLoop::recvSlaveData(SymbolString& result)
|
||||
{
|
||||
unsigned char recvByte, calcCrc = 0;
|
||||
ssize_t numRecv;
|
||||
size_t NN = 0;
|
||||
bool updateCrc = true;
|
||||
int retval = 0;
|
||||
|
||||
for (size_t i = 0, needed = 1; i < needed; i++) {
|
||||
numRecv = m_port->recv(RECV_TIMEOUT);
|
||||
if (numRecv < 0) {
|
||||
L.log(bus, error, " ERR_TIMEOUT: read timeout");
|
||||
return RESULT_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
recvByte = fetchByte();
|
||||
retval = result.push_back(recvByte, true, updateCrc);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
if (retval == RESULT_IN_ESC)
|
||||
needed++;
|
||||
else if (result.size() == 1) { // NN received
|
||||
NN = result[0];
|
||||
needed += NN;
|
||||
}
|
||||
else if (NN > 0 && result.size() == 1+NN) {// all data received
|
||||
updateCrc = false;
|
||||
calcCrc = result.getCRC();
|
||||
needed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == RESULT_IN_ESC) {
|
||||
L.log(bus, error, " ERR_ESC: invalid escape sequence received");
|
||||
return RESULT_ERR_ESC;
|
||||
}
|
||||
|
||||
if (updateCrc == true || calcCrc != result[result.size()-1]) {
|
||||
L.log(bus, error, " ERR_CRC: CRC error");
|
||||
return RESULT_ERR_CRC;
|
||||
}
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void BusLoop::addPollMessage()
|
||||
{
|
||||
int index = m_commands->nextPollCommand();
|
||||
if (index < 0) {
|
||||
L.log(bus, error, "polling index out of range");
|
||||
}
|
||||
else {
|
||||
// TODO: implement as methode from class commands?
|
||||
string tmp;
|
||||
tmp += (*m_commands)[index][1];
|
||||
tmp += " ";
|
||||
tmp += (*m_commands)[index][2];
|
||||
L.log(bus, event, " polling [%4d] %s", index, tmp.c_str());
|
||||
|
||||
string busCommand(A.getOptVal<const char*>("address"));
|
||||
busCommand += m_commands->getBusCommand(index);
|
||||
transform(busCommand.begin(), busCommand.end(), busCommand.begin(), ::tolower);
|
||||
|
||||
BusMessage* message = new BusMessage(busCommand, true, false);
|
||||
L.log(bus, trace, " msg: %s", busCommand.c_str());
|
||||
|
||||
addMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
void BusLoop::addScanMessage()
|
||||
{
|
||||
string busCommand(A.getOptVal<const char*>("address"));
|
||||
stringstream sstr;
|
||||
|
||||
if (m_scanFull == true) {
|
||||
for (; m_scanIndex <= 0xFF; m_scanIndex++) {
|
||||
if (isMaster(m_scanIndex) == false && m_scanIndex != SYN
|
||||
&& m_scanIndex != ESC && m_scanIndex != BROADCAST) {
|
||||
sstr << nouppercase << setw(2) << setfill('0')
|
||||
<< hex << m_scanIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
sstr << nouppercase << setw(2) << setfill('0')
|
||||
<< hex << static_cast<unsigned>(m_slave[m_scanIndex]);
|
||||
|
||||
if (m_scanIndex+1 >= m_slave.size())
|
||||
m_scan = false;
|
||||
}
|
||||
|
||||
if (m_scanIndex > 0xFF)
|
||||
m_scan = false;
|
||||
else {
|
||||
m_scanIndex++;
|
||||
|
||||
busCommand += sstr.str();
|
||||
busCommand += "070400";
|
||||
transform(busCommand.begin(), busCommand.end(), busCommand.begin(), ::tolower);
|
||||
|
||||
L.log(bus, event, " scanning address %s", sstr.str().c_str());
|
||||
|
||||
|
||||
BusMessage* message = new BusMessage(busCommand, true, true);
|
||||
L.log(bus, trace, " msg: %s", busCommand.c_str());
|
||||
|
||||
addMessage(message);
|
||||
}
|
||||
}
|
||||
@@ -1,370 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* This file is part of ebusd.
|
||||
*
|
||||
* ebusd is free software: 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ebusd 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 ebusd. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef BUSLOOP_H_
|
||||
#define BUSLOOP_H_
|
||||
|
||||
#include "commands.h"
|
||||
#include "port.h"
|
||||
#include "wqueue.h"
|
||||
#include "thread.h"
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/** \file busloop.h */
|
||||
|
||||
/** the maximum time [us] allowed for retrieving a byte from an addressed slave */
|
||||
#define RECV_TIMEOUT 10000
|
||||
|
||||
/** possible bus command types */
|
||||
enum BusCommandType {
|
||||
invalid, /*!< invalid command type */
|
||||
broadcast, /*!< broadcast */
|
||||
masterMaster, /*!< master - master */
|
||||
masterSlave /*!< master - slave */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief class for data/message transfer between baseloop and busloop.
|
||||
*/
|
||||
class BusMessage
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief construct a new bus message instance and determine command type.
|
||||
* @param command the command data to write on bus.
|
||||
* @param poll true if message type is polling.
|
||||
* @param scan true if message type is scanning.
|
||||
*/
|
||||
BusMessage(const string command, const bool poll, const bool scan);
|
||||
|
||||
/**
|
||||
* @brief destructor.
|
||||
*/
|
||||
~BusMessage()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_cond_destroy(&m_cond);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the bus command type.
|
||||
* @return the bus command type.
|
||||
*/
|
||||
BusCommandType getType() const { return m_type; }
|
||||
|
||||
/**
|
||||
* @brief get the command string.
|
||||
* @return the command string.
|
||||
*/
|
||||
SymbolString getCommand() const { return m_command; }
|
||||
|
||||
/**
|
||||
* @brief get the result string.
|
||||
* @return the result string.
|
||||
*/
|
||||
SymbolString getResult() const { return m_result; }
|
||||
|
||||
/**
|
||||
* @brief set the result string and result code.
|
||||
* @param result the result string.
|
||||
* @param resultCode the result code.
|
||||
*/
|
||||
void setResult(const SymbolString result, const int resultCode)
|
||||
{ m_result = result; m_resultCode = resultCode; }
|
||||
|
||||
/**
|
||||
* @brief return status of result code.
|
||||
* @return true if result code is negativ.
|
||||
*/
|
||||
bool isErrorResult() const { return m_resultCode < 0; }
|
||||
|
||||
/**
|
||||
* @brief return output string of result code.
|
||||
* @return the output string of result code.
|
||||
*/
|
||||
const char* getResultCodeCStr() const { return getResultCode(m_resultCode); }
|
||||
|
||||
/**
|
||||
* @brief return the message string or error result string.
|
||||
* @return the message string or error result string.
|
||||
*/
|
||||
const string getMessageStr();
|
||||
|
||||
/**
|
||||
* @brief return polling flag of message type.
|
||||
* @return true if message type is polling.
|
||||
*/
|
||||
bool isPoll() const { return m_poll; }
|
||||
|
||||
/**
|
||||
* @brief return scanning flag of message type.
|
||||
* @return true if message type is scanning.
|
||||
*/
|
||||
bool isScan() const { return m_scan; }
|
||||
|
||||
/**
|
||||
* @brief wait on notification.
|
||||
*/
|
||||
void waitSignal() { pthread_cond_wait(&m_cond, &m_mutex); } // TODO timeout
|
||||
|
||||
/**
|
||||
* @brief send notification.
|
||||
*/
|
||||
void sendSignal() { pthread_cond_signal(&m_cond); }
|
||||
|
||||
private:
|
||||
/** the bus command type */
|
||||
BusCommandType m_type;
|
||||
|
||||
/** true if message is of type polling */
|
||||
bool m_poll;
|
||||
|
||||
/** true if message is of type scanning */
|
||||
bool m_scan;
|
||||
|
||||
/** the command string (master data) */
|
||||
SymbolString m_command;
|
||||
|
||||
/** the result string (slave data) */
|
||||
SymbolString m_result;
|
||||
|
||||
/** the result code of result string */
|
||||
int m_resultCode;
|
||||
|
||||
/** mutex variable for exclusive lock */
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
/** condition variable for exclusive lock */
|
||||
pthread_cond_t m_cond;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief class busloop which handle all bus activities.
|
||||
*/
|
||||
class BusLoop : public Thread
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief create a busloop instance and set the commands instance.
|
||||
* @param commands the commands instance.
|
||||
*/
|
||||
BusLoop(Commands* commands);
|
||||
|
||||
/**
|
||||
* @brief destructor.
|
||||
*/
|
||||
~BusLoop();
|
||||
|
||||
/**
|
||||
* @brief endless loop for busloop instance.
|
||||
* @return void pointer.
|
||||
*/
|
||||
void* run();
|
||||
|
||||
/**
|
||||
* @brief shut down busloop.
|
||||
*/
|
||||
void stop() { m_running = false; }
|
||||
|
||||
/**
|
||||
* @brief add a new bus message to internal message queue.
|
||||
* @param message the bus message.
|
||||
*/
|
||||
void addMessage(BusMessage* message) { m_busQueue.add(message); }
|
||||
|
||||
/**
|
||||
* @brief switch to new commands instance.
|
||||
* @param commands reference of new loaded commands instance.
|
||||
*/
|
||||
void reload(Commands* commands) { m_commands = commands; }
|
||||
|
||||
/**
|
||||
* @brief scanning ebus do determine bus members.
|
||||
* @param full if true a scan of all slave addresses will be done.
|
||||
*/
|
||||
void scan(const bool full=false) { m_scan = true; m_scanFull = full; m_scanIndex = 0; }
|
||||
|
||||
/**
|
||||
* @brief toggle (on/off) logging of raw data to logging system.
|
||||
*/
|
||||
void raw() { m_logRawData == true ? m_logRawData = false : m_logRawData = true ; }
|
||||
|
||||
/**
|
||||
* @brief set the name of dump file.
|
||||
* @param dumpFile the file name of dump file.
|
||||
*/
|
||||
void setDumpFile(const string& dumpFile) { m_dumpFile = dumpFile; }
|
||||
|
||||
/**
|
||||
* @brief set the max size of dump file.
|
||||
* @param dumpSize the max. size of the dump file, before switching.
|
||||
*/
|
||||
void setDumpSize(const long dumpSize) { m_dumpSize = dumpSize; }
|
||||
|
||||
/**
|
||||
* @brief toggle (on/off) dumping of raw bytes to a dump file.
|
||||
*/
|
||||
void dump() { m_dumping == true ? m_dumping = false : m_dumping = true ; }
|
||||
|
||||
private:
|
||||
/** the commands instance */
|
||||
Commands* m_commands;
|
||||
|
||||
/** the port instance which control the ebus device */
|
||||
Port* m_port;
|
||||
|
||||
/** the name of dump file*/
|
||||
string m_dumpFile;
|
||||
|
||||
/** max. size of dump file */
|
||||
long m_dumpSize;
|
||||
|
||||
/** true if dumping of raw bytes to file is enabled */
|
||||
bool m_dumping;
|
||||
|
||||
/** true if logging of raw bytes is enabled */
|
||||
bool m_logRawData;
|
||||
|
||||
/** true if this instance is running */
|
||||
bool m_running;
|
||||
|
||||
/** bus access is not allowed if counter is greater than 0 */
|
||||
int m_lockCounter;
|
||||
|
||||
/** if true, we lost bus acquire but same priority class.
|
||||
* after next SYN sign we are allowed to try again to aquire bus.
|
||||
*/
|
||||
bool m_priorRetry;
|
||||
|
||||
/** queue for bus messages */
|
||||
WQueue<BusMessage*> m_busQueue;
|
||||
|
||||
/** string for cycle bus data */
|
||||
SymbolString m_sstr;
|
||||
|
||||
/** number of send retries for one bus command */
|
||||
int m_sendRetries;
|
||||
|
||||
/** number of lock retries (acquire bus) for one bus command */
|
||||
int m_lockRetries;
|
||||
|
||||
/** time for receiving answer from slave [us] */
|
||||
long m_recvTimeout;
|
||||
|
||||
/** waiting time for bus acquire [us] */
|
||||
long m_acquireTime;
|
||||
|
||||
/** time between to polling commands [s] */
|
||||
double m_pollInterval;
|
||||
|
||||
/** vector with collected slave addresses */
|
||||
vector<unsigned char> m_slave;
|
||||
|
||||
/** true if bus scanning for collected slave addresses is active */
|
||||
bool m_scan;
|
||||
|
||||
/** true if bus scanning for all slave addresses is active */
|
||||
bool m_scanFull;
|
||||
|
||||
/** internal index do get next scan command */
|
||||
size_t m_scanIndex;
|
||||
|
||||
/**
|
||||
* @brief write byte to dump file.
|
||||
* @param byte to write
|
||||
* @return -1 if dump file cannot opened or renaming of dump file failed.
|
||||
*/
|
||||
int writeDumpFile(const char* byte);
|
||||
|
||||
/**
|
||||
* @brief fetch next byte of device input buffer (dumping and raw logging).
|
||||
* @return next byte of device.
|
||||
*/
|
||||
unsigned char fetchByte();
|
||||
|
||||
/**
|
||||
* @brief collect cycle bytes. the analysis of collected bytes will be triggered after next SYN sign.
|
||||
* @param numRecv the number of bytes to analyze.
|
||||
*/
|
||||
void collectCycData(const int numRecv);
|
||||
|
||||
/**
|
||||
* @brief the analyzing of collected bytes. collecting of slave address will be triggered.
|
||||
*/
|
||||
void analyseCycData();
|
||||
|
||||
/**
|
||||
* @brief determine and collect slave addresses.
|
||||
*/
|
||||
void collectSlave();
|
||||
|
||||
/**
|
||||
* @brief try to acquire bus for sending purpose.
|
||||
* @return result code of bus acquiring.
|
||||
*/
|
||||
int acquireBus();
|
||||
|
||||
/**
|
||||
* @brief handle sending of a bus command.
|
||||
* @return a reference to sent bus message.
|
||||
*/
|
||||
BusMessage* sendCommand();
|
||||
|
||||
/**
|
||||
* @brief send 1 byte to bus device.
|
||||
* @param sendByte the byte to send.
|
||||
* @return result code of byte sending.
|
||||
*/
|
||||
int sendByte(const unsigned char sendByte);
|
||||
|
||||
/**
|
||||
* @brief receive ACK from slave.
|
||||
* @param reference for receive byte.
|
||||
* @return result code of receiving byte.
|
||||
*/
|
||||
int recvSlaveAck(unsigned char& recvByte);
|
||||
|
||||
/**
|
||||
* @brief receive slave data block.
|
||||
* @param reference for result string.
|
||||
* @return result code of receiving slave data.
|
||||
*/
|
||||
int recvSlaveData(SymbolString& result);
|
||||
|
||||
/**
|
||||
* @brief add a polling bus message to internal message queue.
|
||||
* @param message the bus message.
|
||||
*/
|
||||
void addPollMessage();
|
||||
|
||||
/**
|
||||
* @brief add a scanning bus message to internal message queue.
|
||||
* @param message the bus message.
|
||||
*/
|
||||
void addScanMessage();
|
||||
|
||||
};
|
||||
|
||||
#endif // BUSLOOP_H_
|
||||
Reference in New Issue
Block a user