implemented get

This commit is contained in:
john30
2014-12-06 13:02:16 +01:00
parent 38f0ddbe78
commit 73b74f1602
3 changed files with 266 additions and 161 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ ebusd_SOURCES = bushandler.cpp \
ebusd_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \
$(top_srcdir)/src/lib/ebus/libebus.a \
-lpthread
-lpthread -lrt
distclean-local:
-rm -f Makefile.in
+223 -134
View File
@@ -35,28 +35,31 @@ extern Logger& L;
extern Appl& A;
/**
* @brief Return the string corresponding to the @a BusState and send position.
* @brief Return the string corresponding to the @a BusState.
* @param state the @a BusState.
* @param sendPos >=0 while sending data, -1 while receiving data.
* @return the string corresponding to the @a BusState.
*/
const char* getStateCode(BusState state, int sendPos) {
const char* getStateCode(BusState state) {
switch (state)
{
case bs_skip: return "skip";
case bs_ready: return "ready";
case bs_command: return sendPos < 0 ? "receive command" : "send command";
case bs_commandAck: return sendPos < 0 ? "receive command ACK" : "send command ACK";
case bs_response: return sendPos < 0 ? "receive response" : "send response";
case bs_responseAck: return sendPos < 0 ? "receive response ACK" : "send response ACK";
//case bs_validTransfer: return sendPos < 0 ? "after complete receive" : "after complete send";
default: return "unknown state";
case bs_skip: return "skip";
case bs_ready: return "ready";
case bs_sendCmd: return "send command";
case bs_recvCmdAck: return "receive command ACK";
case bs_recvRes: return "receive response";
case bs_sendResAck: return "send response ACK";
case bs_recvCmd: return "receive command";
case bs_recvResAck: return "receive response ACK";
// case bs_sendRes: return "send response";
// case bs_sendCmdAck: return "send command ACK";
case bs_sendSyn: return "send SYN";
default: return "unknown";
}
}
BusRequest::BusRequest(SymbolString& master, SymbolString& slave)
: m_master(master), m_slave(slave), m_finished(false)
: m_master(master), m_slave(slave), m_finished(false), m_result(RESULT_SYN)
{
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
@@ -88,11 +91,12 @@ bool BusRequest::wait(int timeout)
return result == 0;
}
void BusRequest::notify(bool finished)
void BusRequest::notify(result_t result)
{
pthread_mutex_lock(&m_mutex);
m_finished = finished;
m_result = result;
m_finished = true;
pthread_mutex_unlock(&m_mutex);
}
@@ -103,29 +107,24 @@ result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave)
BusRequest* request = new BusRequest(master, slave);
m_requests.add(request);
bool result = request->wait(5);
if (result == false)
bool success = request->wait(5);
if (success == false)
m_requests.remove(request);
result_t result = request->m_result;
delete request;
return result == true ? RESULT_OK : RESULT_ERR_TIMEOUT;
return success == true ? result : RESULT_ERR_TIMEOUT;
}
void BusHandler::run()
{
result_t result = RESULT_OK;
do {
if (m_port->isOpen() == true) {
result = receiveSymbol();
if (result != RESULT_OK)
L.log(bus, error, " %s", getResultCode(result));
}
if (m_port->isOpen() == true)
handleSymbol();
else {
// TODO: define max reopen
sleep(10);
result = m_port->open();
result_t result = m_port->open();
if (result != RESULT_OK)
L.log(bus, error, "can't open %s", A.getOptVal<const char*>("device"));
@@ -135,46 +134,72 @@ void BusHandler::run()
} while (isRunning() == true);
}
result_t BusHandler::receiveSymbol()
#define RECV_TIMEOUT 4500
result_t BusHandler::handleSymbol()
{
long timeout;
ssize_t count;
unsigned char sentSymbol = SYN;
BusRequest* startRequest = NULL;
if (m_state == bs_skip)
timeout = 0;
else if (m_sendPos >= 0) {
timeout = SLAVE_RECV_TIMEOUT;
if (m_sendPos+1 < m_request->m_master.size()) {
m_sendPos++;
sentSymbol = m_request->m_master[m_sendPos];
if (m_port->send(&sentSymbol) != 1) {
sentSymbol = SYN; // try again later // TODO error: send failed, abort send
m_request->notify(false);
m_request = NULL;
m_sendPos = -1;
}
long timeout = SYN_TIMEOUT;
unsigned char sendSymbol = ESC;
bool sending = false;
// check if another symbol has to be sent and determine timeout for receive
switch (m_state)
{
case bs_skip:
timeout = 0; // endless
break;
case bs_ready:
m_request = m_requests.next(false);
if (m_request != NULL) { // initiate arbitration
sendSymbol = m_request->m_master[0];
sending = true;
}
break;
case bs_recvCmd:
case bs_recvCmdAck:
case bs_recvRes:
case bs_recvResAck:
timeout = SLAVE_RECV_TIMEOUT;
break;
case bs_sendCmd:
if (m_request != NULL) {
sendSymbol = m_request->m_master[m_nextSendPos];
sending = true;
}
break;
case bs_sendResAck:
if (m_request != NULL) {
sendSymbol = m_responseCrcValid ? ACK : NAK;
sending = true;
}
break;
case bs_sendSyn:
sendSymbol = SYN;
sending = true;
break;
}
else {
timeout = SYN_TIMEOUT;
if (m_state == bs_ready && m_request == NULL) {
startRequest = m_requests.next(false);
if (startRequest != NULL) {
// initiate arbitration
sentSymbol = startRequest->m_master[0];
if (m_port->send(&sentSymbol) != 1) {
sentSymbol = SYN; // try again later // TODO error: send failed
startRequest = NULL;
}
}
// send symbol if necessary
if (sending == true) {
if (m_port->send(&sendSymbol, 1) == 1)
timeout = RECV_TIMEOUT;
else {
sending = false;
timeout = 0;
setState(bs_skip, RESULT_ERR_SEND);
}
}
count = m_port->recv(timeout, 1);
// receive next symbol (optionally check reception of sent symbol)
ssize_t count = m_port->recv(timeout, 1);
if (count < 0)
return setState(bs_skip, RESULT_ERR_DEVICE);
return setState(bs_skip, count);
if (count == 0) {
if (m_state == bs_ready)
@@ -182,11 +207,9 @@ result_t BusHandler::receiveSymbol()
return setState(bs_skip, RESULT_ERR_TIMEOUT);
}
unsigned char symbol = m_port->byte();
if (symbol == SYN) {
m_repeat = false;
return setState(bs_ready, RESULT_OK);
}
unsigned char recvSymbol = m_port->byte();
if (recvSymbol == SYN)
return setState(bs_ready, RESULT_SYN);
unsigned char headerLen, crcPos;
result_t result;
@@ -197,128 +220,185 @@ result_t BusHandler::receiveSymbol()
return RESULT_OK;
case bs_ready:
if (symbol == ESC)
return setState(bs_skip, RESULT_ERR_ESC);
if (m_sendPos < 0 && sentSymbol != SYN) {
if (m_request != NULL && sending == true) {
// check arbitration
if (symbol == sentSymbol) { // arbitration successful
if (m_requests.remove(startRequest) == false) {
sentSymbol = SYN; // try again later // TODO error: send failed, abort send
} else {
m_request = startRequest;
m_sendPos = 0;
if (recvSymbol == sendSymbol) { // arbitration successful
if (m_requests.remove(m_request) == false) {
// request already timed out
m_request = NULL;
return setState(bs_sendSyn, RESULT_ERR_TIMEOUT);
}
} else { // arbitration lost
sentSymbol = SYN; // try again later // TODO error: lost arbitration
m_nextSendPos = 1;
m_repeat = false;
return setState(bs_sendCmd, RESULT_OK);
}
// arbitration lost
setState(m_state, RESULT_ERR_BUS_LOST); // try again later
}
result = m_command.push_back(symbol);
result = m_command.push_back(recvSymbol, false); // expect no escaping for master address
if (result < RESULT_OK)
return setState(bs_skip, result);
return setState(bs_command, RESULT_OK);
m_repeat = false;
return setState(bs_recvCmd, RESULT_OK);
case bs_command:
case bs_recvCmd:
headerLen = 4;
crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff;
result = m_command.push_back(symbol, true, m_command.size() < crcPos);
result = m_command.push_back(recvSymbol, true, m_command.size() < crcPos);
if (result < RESULT_OK)
return setState(bs_skip, result);
if (result == RESULT_OK && m_command.size() == crcPos + 1) { // CRC received
if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received
unsigned char dstAddress = m_command[1];
//if (isValidAddress(dstAddress) == false || isMaster(m_command[0]) == false)
// return setState(bs_skip, RESULT_ERR_INVALID_ADDR);
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC();
if (m_command[1] == BROADCAST) {
if (m_commandCrcValid) {
if (m_commandCrcValid) {
if (dstAddress == BROADCAST) {
transferCompleted(tt_broadcast);
return setState(bs_skip, RESULT_OK);
}
//if (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)
// return setState(bs_sendCmdAck, RESULT_OK);
return setState(bs_skip, RESULT_ERR_CRC);
return setState(bs_recvCmdAck, RESULT_OK);
}
/*if (m_command[1] == m_ownSlaveAddress || m_command[1] == m_ownMasterAddress) {
setState(bs_commandAck, RESULT_OK);
m_sendPos = 0;
symbol = m_commandCrcValid ? ACK : NAK;
if (m_port->send(&symbol) <= 0)
return setState(bs_skip, RESULT_ERR_SEND);
}*/
return setState(bs_commandAck, RESULT_OK);
if (dstAddress == BROADCAST)
return setState(bs_skip, RESULT_OK);
//if (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)
// return setState(bs_sendCmdAck, RESULT_ERR_CRC);
if (m_repeat == true)
return setState(bs_skip, RESULT_ERR_CRC);
return setState(bs_recvCmdAck, RESULT_ERR_CRC);
}
return RESULT_OK;
case bs_commandAck:
if (symbol == ESC)
return setState(bs_skip, RESULT_ERR_ESC);
/*if (m_sendPos >= 0) {
if (symbol == ACK && m_commandCrcValid == true)
return setState();
return setState()
}*/
if (symbol == ACK) {
case bs_recvCmdAck:
if (recvSymbol == ACK) {
if (m_commandCrcValid == false)
return setState(bs_skip, RESULT_ERR_ACK);
if (isMaster(m_command[1]) == true) {
if (m_request != NULL) {
if (isMaster(m_request->m_master[1]) == true) {
transferCompleted(tt_masterMaster);
return setState(bs_sendSyn, RESULT_OK);
}
} else if (isMaster(m_command[1]) == true) {
transferCompleted(tt_masterMaster);
return setState(bs_skip, RESULT_OK);
}
return setState(bs_response, RESULT_OK);
m_repeat = false;
return setState(bs_recvRes, RESULT_OK);
}
if (symbol == NAK) {
if (recvSymbol == NAK) {
if (m_repeat == false) {
m_repeat = true;
return setState(bs_ready, RESULT_ERR_NAK);
m_nextSendPos = 0;
m_command.clear();
if (m_request != NULL)
return setState(bs_sendCmd, RESULT_ERR_NAK);
return setState(bs_recvCmd, RESULT_ERR_NAK);
}
if (m_request != NULL)
return setState(bs_sendSyn, RESULT_ERR_NAK);
return setState(bs_skip, RESULT_ERR_NAK);
}
if (m_request != NULL)
return setState(bs_sendSyn, RESULT_ERR_ACK);
return setState(bs_skip, RESULT_ERR_ACK);
case bs_response:
case bs_recvRes:
headerLen = 0;
crcPos = m_response.size() > headerLen ? headerLen + 1 + m_response[headerLen] : 0xff;
result = m_response.push_back(symbol, true, m_response.size() < crcPos);
if (result < RESULT_OK)
return setState(bs_skip, result);
result = m_response.push_back(recvSymbol, true, m_response.size() < crcPos);
if (result < RESULT_OK) {
if (m_request != NULL)
return setState(bs_sendSyn, result);
if (result == RESULT_OK && m_response.size() == crcPos + 1) { // CRC received
return setState(bs_skip, result);
}
if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received
m_responseCrcValid = m_response[headerLen + 1 + m_response[headerLen]] == m_response.getCRC();
/*if (m_command[1] == m_ownSlaveAddress || m_command[1] == m_ownMasterAddress) {
setState(bs_responseAck, RESULT_OK);
m_sendPos = 0;
symbol = m_responseCrcValid ? ACK : NAK;
if (m_port->send(&symbol) <= 0)
return setState(bs_skip, RESULT_ERR_SEND);
}*/
return setState(bs_responseAck, RESULT_OK);
if (m_responseCrcValid) {
if (m_request != NULL)
return setState(bs_sendResAck, RESULT_OK);
return setState(bs_recvResAck, RESULT_OK);
}
if (m_repeat == true) {
if (m_request != NULL)
return setState(bs_sendSyn, RESULT_ERR_CRC);
return setState(bs_skip, RESULT_ERR_CRC);
}
if (m_request != NULL)
return setState(bs_sendResAck, RESULT_ERR_CRC);
return setState(bs_recvResAck, RESULT_ERR_CRC);
}
return RESULT_OK;
case bs_responseAck:
if (symbol == ESC)
return setState(bs_skip, RESULT_ERR_ESC);
/*if (m_sendPos >= 0) {
if (symbol == ACK && m_responseCrcValid == true)
return setState();
return setState()
}*/
if (symbol == ACK) {
case bs_recvResAck:
if (recvSymbol == ACK) {
if (m_responseCrcValid == false)
return setState(bs_skip, RESULT_ERR_ACK);
transferCompleted(tt_masterSlave);
return setState(bs_skip, RESULT_OK);
}
if (symbol == NAK) {
if (recvSymbol == NAK) {
if (m_repeat == false) {
m_repeat = true;
return setState(bs_response, RESULT_ERR_NAK);
m_response.clear();
return setState(bs_recvRes, RESULT_ERR_NAK);
}
return setState(bs_skip, RESULT_ERR_NAK);
}
return setState(bs_skip, RESULT_ERR_ACK);
case bs_sendCmd:
if (m_request != NULL && sending == true) {
if (recvSymbol == sendSymbol) {
// successfully sent
m_nextSendPos++;
if (m_nextSendPos >= m_request->m_master.size()) {
// master data completely sent
if (m_request->m_master[1] == BROADCAST)
return setState(bs_sendSyn, RESULT_OK);
m_commandCrcValid = true;
return setState(bs_recvCmdAck, RESULT_OK);
}
return RESULT_OK;
}
}
return setState(bs_sendSyn, RESULT_ERR_INVALID_ARG);
case bs_sendResAck:
if (m_request != NULL && sending == true) {
if (recvSymbol == sendSymbol) {
// successfully sent
return setState(bs_sendSyn, RESULT_OK);
}
}
return setState(bs_sendSyn, RESULT_ERR_INVALID_ARG);
case bs_sendSyn:
if (sending == true) {
if (recvSymbol == sendSymbol) {
// successfully sent
return setState(bs_skip, RESULT_OK);
}
}
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
}
return RESULT_OK;
@@ -330,18 +410,27 @@ result_t BusHandler::setState(BusState state, result_t result)
return result;
if (result < RESULT_OK || (result != RESULT_OK && state == bs_skip))
L.log(bus, error, " %s during %s, switching to %s", getResultCode(result), getStateCode(m_state, m_sendPos), getStateCode(state, m_sendPos));
L.log(bus, error, " %s during %s, switching to %s", getResultCode(result), getStateCode(m_state), getStateCode(state));
m_state = state;
if (m_request != NULL) {
if (state == bs_sendSyn) {
m_request->m_slave = m_response; // TODO nicer
m_request->notify(result);
m_request = NULL;
} else if (result != RESULT_OK) {
m_request->notify(result);
m_request = NULL;
}
}
if (state == bs_ready || state == bs_skip) {
m_command.clear();
m_commandCrcValid = false;
m_response.clear();
m_responseCrcValid = false;
m_sendPos = -1;
m_nextSendPos = 0;
}
if (state == bs_skip)
m_repeat = false;
return result;
}
@@ -367,7 +456,7 @@ void BusHandler::transferCompleted(TransferType type)
ostringstream output;
result_t result = msg->decode(m_command, m_response, output);
if (result != RESULT_OK)
L.log(bus, error, "unable to parse %s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), getResultCode(result));
L.log(bus, error, "unable to parse %s %s from %s / %s: %s", msg->getClass().c_str(), msg->getName().c_str(), m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result));
else
L.log(bus, trace, "%s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), output.str().c_str());
}
+42 -26
View File
@@ -36,18 +36,22 @@ using namespace std;
/** the maximum allowed time [us] for retrieval of a single symbol from an addressed slave. */
#define SLAVE_RECV_TIMEOUT 10000
/** the maximum allowed time [us] for retrieval of an AUTO-SYN symbol. */
/** the maximum allowed time [us] for retrieval of an AUTO-SYN symbol (should be generated in <45ms). */
#define SYN_TIMEOUT 50000
/** the possible bus states. */
enum BusState {
bs_skip, // skip all symbols until next @a SYN
bs_ready, // ready for next master (after @a SYN symbol, send/receive QQ)
bs_command, // receive/send command (ZZ, PBSB, master data)
bs_commandAck, // receive/send command ACK/NACK
bs_response, // receive/send response (slave data)
bs_responseAck, // receive/send response ACK/NACK
//bs_validTransfer,// completed a valid message transfer
bs_skip, // skip all symbols until next @a SYN
bs_ready, // ready for next master (after @a SYN symbol, send/receive QQ)
bs_recvCmd, // receive command (ZZ, PBSB, master data) [passive set]
bs_recvCmdAck, // receive command ACK/NACK [passive set + active set+get]
bs_recvRes, // receive response (slave data) [passive set + active get]
bs_recvResAck, // receive response ACK/NACK [passive set]
bs_sendCmd, // send command (ZZ, PBSB, master data) [active set+get]
bs_sendResAck, // send response ACK/NACK [active get]
// bs_sendRes, // send response (slave data) [passive get] // TODO implement
// bs_sendCmdAck, // send command ACK/NACK [passive get] // TODO implement
bs_sendSyn, // send SYN for completed transfer [active set+get]
};
/** the possible message transfer types. */
@@ -62,9 +66,9 @@ enum MessageDirection {
md_thisToAll, // message from us to all (broadcast)
md_thisToMaster, // message from us to another master
md_thisToSlave, // message from us to another slave
md_otherToAll, // message from a master (other than us) to all (broadcast): @a bs_ready, @a bs_recvCmd
md_otherToMaster, // message from a master (other than us) to another master (other than us): @a bs_ready, @a bs_recvCmd, @a bs_recvAck
md_otherToSlave, // message from a master (other than us) to another slave (other than us): @a bs_ready, @a bs_recvCmd, @a bs_recvAck, @a bs_recvResp, @a bs_recvAck
md_otherToAll, // message from a master (other than us) to all (broadcast)
md_otherToMaster, // message from a master (other than us) to another master (other than us)
md_otherToSlave, // message from a master (other than us) to another slave (other than us)
md_otherToThisMaster, // message from a master (other than us) to us (as master)
md_otherToThisSlave, // message from a master (other than us) to us (as slave)
md_undefined,
@@ -72,6 +76,9 @@ enum MessageDirection {
class BusHandler;
/**
* @brief Handles input from and output to the bus with respect to the ebus protocol.
*/
class BusRequest
{
friend class BusHandler;
@@ -79,6 +86,8 @@ public:
/**
* @brief Constructor.
* @param master the master data @a SymbolString to send.
* @param slave the slave data @a SymbolString received.
*/
BusRequest(SymbolString& master, SymbolString& slave);
@@ -96,16 +105,22 @@ public:
/**
* @brief Notify all waiting threads.
*/
void notify(bool finished);
void notify(result_t result);
private:
/** the master data @a SymbolString to send. */
SymbolString& m_master;
/** the slave data @a SymbolString received. */
SymbolString& m_slave;
/** true once the request is finished. */
bool m_finished;
/** the result of handling the request. */
result_t m_result;
/** a mutex for wait/notify. */
pthread_mutex_t m_mutex;
@@ -132,8 +147,9 @@ public:
BusHandler(Port* port, MessageMap* messages, unsigned char ownMasterAddress,
unsigned char ownSlaveAddress)
: m_port(port), m_messages(messages), m_ownMasterAddress(ownMasterAddress),
m_ownSlaveAddress(ownSlaveAddress), m_state(bs_skip), m_repeat(false),
m_sendPos(-1), m_commandCrcValid(false), m_responseCrcValid(false), m_request(NULL) {}
m_ownSlaveAddress(ownSlaveAddress), m_request(NULL), m_nextSendPos(0),
m_state(bs_skip), m_repeat(false),
m_commandCrcValid(false), m_responseCrcValid(false) {}
/**
* @brief Destructor.
@@ -155,10 +171,10 @@ public:
private:
/**
* @brief Receive another symbol from the bus.
* @brief Handle the next symbol on the bus.
* @return RESULT_OK on success, or an error code.
*/
result_t receiveSymbol();
result_t handleSymbol();
/**
* @brief Set a new @a BusState and add a log message if necessary.
@@ -186,18 +202,22 @@ private:
/** the own slave address to react on master-slave messages, or @a SYN to ignore. */
unsigned char m_ownSlaveAddress;
/** the queue of @a BusRequests that shall be handled. */
WQueue<BusRequest*> m_requests;
/** the currently handled BusRequest, or NULL. */
BusRequest* m_request;
/** the offset of the next symbol that needs to be sent from the command or response,
* (only relevant if m_request is set and state is bs_command or bs_response). */
unsigned char m_nextSendPos;
/** the current @a BusState. */
BusState m_state;
/** whether the current message part is being repeated. */
bool m_repeat;
/*
* the offset of the last sent symbol while sending command/response,
* or 0 while sending ACK/NACK, or -1 if not sending.
*/
int m_sendPos;
/** the received/sent command. */
SymbolString m_command;
@@ -210,10 +230,6 @@ private:
/** whether the response CRC is valid. */
bool m_responseCrcValid;
WQueue<BusRequest*> m_requests;
BusRequest* m_request;
};