allow initsend for enhanced as well, cleaner separation
This commit is contained in:
+35
-10
@@ -350,8 +350,32 @@ result_t BusHandler::readFromBus(Message* message, const string& inputStr, symbo
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BusHandler::notifyProtocolStatus(bool signal) {
|
||||
// ignored
|
||||
void BusHandler::notifyProtocolStatus(ProtocolState state) {
|
||||
if (state == ps_empty && m_pollInterval > 0) { // check for poll/scan
|
||||
time_t now;
|
||||
time(&now);
|
||||
if (m_lastPoll == 0 || difftime(now, m_lastPoll) > m_pollInterval) {
|
||||
Message* message = m_messages->getNextPoll();
|
||||
if (message != nullptr) {
|
||||
m_lastPoll = now;
|
||||
if (difftime(now, message->getLastUpdateTime()) > m_pollInterval) {
|
||||
// only poll this message if it was not updated already by other means within the interval
|
||||
auto request = new PollRequest(message);
|
||||
result_t ret = request->prepare(m_protocol->getOwnMasterAddress());
|
||||
if (ret != RESULT_OK) {
|
||||
logError(lf_bus, "prepare poll message: %s", getResultCode(ret));
|
||||
delete request;
|
||||
} else {
|
||||
ret = m_protocol->addRequest(request, false);
|
||||
if (ret != RESULT_OK) {
|
||||
logError(lf_bus, "push poll message: %s", getResultCode(ret));
|
||||
delete request;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result_t BusHandler::notifyProtocolAnswer(const MasterSymbolString& command, SlaveSymbolString* response) {
|
||||
@@ -494,7 +518,7 @@ result_t BusHandler::prepareScan(symbol_t slave, bool full, const string& levels
|
||||
if (scanMessage == nullptr) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
if (m_protocol->getDevice()->isReadOnly()) {
|
||||
if (m_protocol->isReadOnly()) {
|
||||
return RESULT_OK;
|
||||
}
|
||||
deque<Message*> messages;
|
||||
@@ -564,9 +588,8 @@ result_t BusHandler::startScan(bool full, const string& levels) {
|
||||
}
|
||||
m_scanResults.clear();
|
||||
m_runningScans++;
|
||||
m_protocol->addRequest(request, false);
|
||||
// request is deleted by ProtocolHandler after finish
|
||||
return RESULT_OK;
|
||||
return m_protocol->addRequest(request, false);
|
||||
}
|
||||
|
||||
void BusHandler::setScanResult(symbol_t dstAddress, size_t index, const string& str) {
|
||||
@@ -704,7 +727,7 @@ void BusHandler::formatUpdateInfo(ostringstream* output) const {
|
||||
}
|
||||
*output << ",\"c\":" << m_protocol->getMasterCount()
|
||||
<< ",\"m\":" << m_messages->size()
|
||||
<< ",\"ro\":" << (m_protocol->getDevice()->isReadOnly() ? 1 : 0)
|
||||
<< ",\"ro\":" << (m_protocol->isReadOnly() ? 1 : 0)
|
||||
<< ",\"an\":" << (m_protocol->isAnswering() ? 1 : 0)
|
||||
<< ",\"co\":" << (m_protocol->isAddressConflict(SYN) ? 1 : 0);
|
||||
if (m_grabMessages) {
|
||||
@@ -727,8 +750,7 @@ void BusHandler::formatUpdateInfo(ostringstream* output) const {
|
||||
}
|
||||
unsigned char address = 0;
|
||||
for (int index = 0; index < 256; index++, address++) {
|
||||
bool ownAddress = !m_protocol->getDevice()->isReadOnly()
|
||||
&& (address == m_protocol->getOwnMasterAddress() || address == m_protocol->getOwnSlaveAddress());
|
||||
bool ownAddress = !m_protocol->isOwnAddress(address);
|
||||
if (!isValidAddress(address, false) || ((m_seenAddresses[address]&SEEN) == 0 && !ownAddress)) {
|
||||
continue;
|
||||
}
|
||||
@@ -815,8 +837,11 @@ result_t BusHandler::scanAndWait(symbol_t dstAddress, bool loadScanConfig, bool
|
||||
m_scanResults[dstAddress].resize(1);
|
||||
}
|
||||
m_runningScans++;
|
||||
requestExecuted = m_protocol->addRequest(request, true);
|
||||
result = requestExecuted ? request->m_result : RESULT_ERR_TIMEOUT;
|
||||
result = m_protocol->addRequest(request, true);
|
||||
requestExecuted = result == RESULT_OK;
|
||||
if (requestExecuted) {
|
||||
result = request->m_result;
|
||||
}
|
||||
delete request;
|
||||
request = nullptr;
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ class BusHandler : public ProtocolListener {
|
||||
void setScanConfigLoaded(symbol_t address, const string& file);
|
||||
|
||||
// @copydoc
|
||||
void notifyProtocolStatus(bool signal) override;
|
||||
void notifyProtocolStatus(ProtocolState state) override;
|
||||
|
||||
// @copydoc
|
||||
result_t notifyProtocolAnswer(const MasterSymbolString& master, SlaveSymbolString* slave) override;
|
||||
|
||||
+9
-9
@@ -363,8 +363,7 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
}
|
||||
|
||||
// open the device
|
||||
Device *device = Device::create(s_opt.device, s_opt.extraLatency, !s_opt.noDeviceCheck, s_opt.readOnly,
|
||||
s_opt.initialSend);
|
||||
Device *device = Device::create(s_opt.device, s_opt.extraLatency, !s_opt.noDeviceCheck);
|
||||
if (device == nullptr) {
|
||||
logWrite(lf_main, ll_error, "unable to create device %s", s_opt.device); // force logging on exit
|
||||
cleanup();
|
||||
@@ -385,8 +384,14 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
signal(SIGINT, signalHandler);
|
||||
signal(SIGTERM, signalHandler);
|
||||
|
||||
// create the MainLoop
|
||||
s_requestQueue = new Queue<Request*>();
|
||||
s_mainLoop = new MainLoop(s_opt, device, s_messageMap, s_scanHelper, s_requestQueue);
|
||||
BusHandler* busHandler = s_mainLoop->getBusHandler();
|
||||
ProtocolHandler* protocol = busHandler->getProtocol();
|
||||
|
||||
ostringstream ostream;
|
||||
device->formatInfo(&ostream, false, false, true);
|
||||
protocol->formatInfo(&ostream, false, true);
|
||||
string deviceInfoStr = ostream.str();
|
||||
logNotice(lf_main, PACKAGE_STRING "." REVISION " started%s on device: %s",
|
||||
s_opt.scanConfig ? s_opt.initialScan == ESC ? " with auto scan"
|
||||
@@ -397,12 +402,7 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
// load configuration files
|
||||
s_scanHelper->loadConfigFiles(!s_opt.scanConfig);
|
||||
|
||||
s_requestQueue = new Queue<Request*>();
|
||||
|
||||
// create the MainLoop and start it
|
||||
s_mainLoop = new MainLoop(s_opt, device, s_messageMap, s_scanHelper, s_requestQueue);
|
||||
BusHandler* busHandler = s_mainLoop->getBusHandler();
|
||||
ProtocolHandler* protocol = busHandler->getProtocol();
|
||||
// start the MainLoop
|
||||
if (s_opt.injectMessages) {
|
||||
int scanAdrCount = 0;
|
||||
bool scanAddresses[256] = {};
|
||||
|
||||
@@ -152,6 +152,7 @@ MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messag
|
||||
}
|
||||
// create BusHandler
|
||||
ebus_protocol_config_t config = {
|
||||
.readOnly = opt.readOnly,
|
||||
.ownAddress = m_address,
|
||||
.answer = opt.answer,
|
||||
.busLostRetries = opt.acquireRetries,
|
||||
@@ -160,6 +161,7 @@ MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messag
|
||||
.slaveRecvTimeout = opt.receiveTimeout,
|
||||
.lockCount = opt.masterCount,
|
||||
.generateSyn = opt.generateSyn,
|
||||
.initialSend = opt.initialSend,
|
||||
};
|
||||
m_busHandler = new BusHandler(m_device, m_messages, scanHelper,
|
||||
config, opt.pollInterval);
|
||||
@@ -377,7 +379,7 @@ void MainLoop::run() {
|
||||
<< ",\"a\":\"other\""
|
||||
#endif
|
||||
<< ",\"u\":" << (now-start);
|
||||
m_device->formatInfo(&ostr, false, true, true);
|
||||
m_protocol->formatInfoJson(&ostr);
|
||||
if (m_reconnectCount) {
|
||||
ostr << ",\"rc\":" << m_reconnectCount;
|
||||
}
|
||||
@@ -1935,7 +1937,7 @@ result_t MainLoop::executeInfo(const vector<string>& args, const string& user, o
|
||||
*ostream << "update check: " << m_updateCheck << "\n";
|
||||
}
|
||||
*ostream << "device: ";
|
||||
m_device->formatInfo(ostream, verbose);
|
||||
m_protocol->formatInfo(ostream, verbose, false);
|
||||
*ostream << "\n";
|
||||
if (!user.empty()) {
|
||||
*ostream << "user: " << user << "\n";
|
||||
@@ -2226,7 +2228,7 @@ result_t MainLoop::executeGet(const vector<string>& args, bool* connected, ostri
|
||||
<< ",\n \"maxsymbollatency\": " << m_protocol->getMaxSymbolLatency();
|
||||
}
|
||||
}
|
||||
if (!m_device->isReadOnly()) {
|
||||
if (!m_protocol->isReadOnly()) {
|
||||
*ostream << ",\n \"qq\": " << static_cast<unsigned>(m_address);
|
||||
}
|
||||
*ostream << ",\n \"reconnects\": " << m_reconnectCount
|
||||
|
||||
+28
-39
@@ -88,11 +88,11 @@ namespace ebusd {
|
||||
#define DEBUG_RAW_TRAFFIC(format, args...)
|
||||
#endif
|
||||
|
||||
Device::Device(const char* name, bool readOnly, bool initialSend)
|
||||
: m_name(name), m_readOnly(readOnly), m_initialSend(initialSend), m_listener(nullptr) {
|
||||
Device::Device(const char* name)
|
||||
: m_name(name), m_listener(nullptr) {
|
||||
}
|
||||
|
||||
Device* Device::create(const char* name, unsigned int extraLatency, bool checkDevice, bool readOnly, bool initialSend) {
|
||||
Device* Device::create(const char* name, unsigned int extraLatency, bool checkDevice) {
|
||||
bool highSpeed = strncmp(name, "ens:", 4) == 0;
|
||||
bool enhanced = highSpeed || strncmp(name, "enh:", 4) == 0;
|
||||
if (enhanced) {
|
||||
@@ -128,23 +128,17 @@ Device* Device::create(const char* name, unsigned int extraLatency, bool checkDe
|
||||
*portpos = 0;
|
||||
char* hostOrIp = strdup(addrpos);
|
||||
free(in);
|
||||
return new NetworkDevice(name, hostOrIp, port, extraLatency, readOnly, initialSend, udp, enhanced);
|
||||
return new NetworkDevice(name, hostOrIp, port, extraLatency, udp, enhanced);
|
||||
}
|
||||
// support enh:/dev/<device>, ens:/dev/<device>, and /dev/<device>
|
||||
return new SerialDevice(name, checkDevice, extraLatency, readOnly, initialSend, enhanced, highSpeed);
|
||||
}
|
||||
|
||||
result_t Device::afterOpen() {
|
||||
if (m_initialSend && !send(ESC)) {
|
||||
return RESULT_ERR_SEND;
|
||||
}
|
||||
return RESULT_OK;
|
||||
return new SerialDevice(name, checkDevice, extraLatency, enhanced, highSpeed);
|
||||
}
|
||||
|
||||
|
||||
FileDevice::FileDevice(const char* name, bool checkDevice, unsigned int latency, bool readOnly, bool initialSend,
|
||||
|
||||
FileDevice::FileDevice(const char* name, bool checkDevice, unsigned int latency,
|
||||
bool enhancedProto)
|
||||
: Device(name, readOnly, initialSend),
|
||||
: Device(name),
|
||||
m_checkDevice(checkDevice),
|
||||
m_latency(HOST_LATENCY_MS+(enhancedProto?ENHANCED_LATENCY_MS:0)+latency),
|
||||
m_enhancedProto(enhancedProto), m_fd(-1), m_resetRequested(false),
|
||||
@@ -164,33 +158,24 @@ FileDevice::~FileDevice() {
|
||||
}
|
||||
}
|
||||
|
||||
void FileDevice::formatInfo(ostringstream* ostream, bool verbose, bool asJson, bool noWait) {
|
||||
if (asJson) {
|
||||
if (m_enhancedProto) {
|
||||
string ver = getEnhancedVersion();
|
||||
if (!ver.empty()) {
|
||||
*ostream << ",\"dv\":\"" << ver << "\"";
|
||||
}
|
||||
void FileDevice::formatInfo(ostringstream* ostream, bool verbose, bool prefix) {
|
||||
if (prefix) {
|
||||
*ostream << m_name;
|
||||
string info = getEnhancedProtoInfo();
|
||||
if (!info.empty()) {
|
||||
*ostream << ", " << info;
|
||||
}
|
||||
return;
|
||||
}
|
||||
*ostream << m_name;
|
||||
string info = getEnhancedProtoInfo();
|
||||
if (!info.empty()) {
|
||||
*ostream << ", " << info;
|
||||
}
|
||||
if (isReadOnly()) {
|
||||
*ostream << ", readonly";
|
||||
}
|
||||
if (noWait) {
|
||||
return;
|
||||
}
|
||||
if (!isValid()) {
|
||||
*ostream << ", invalid";
|
||||
}
|
||||
if (!m_enhancedProto) {
|
||||
return;
|
||||
}
|
||||
bool infoAdded = false;
|
||||
if (verbose) {
|
||||
info = getEnhancedInfos();
|
||||
string info = getEnhancedInfos();
|
||||
if (!info.empty()) {
|
||||
*ostream << ", " << info;
|
||||
infoAdded = true;
|
||||
@@ -204,6 +189,15 @@ void FileDevice::formatInfo(ostringstream* ostream, bool verbose, bool asJson, b
|
||||
}
|
||||
}
|
||||
|
||||
void FileDevice::formatInfoJson(ostringstream* ostream) {
|
||||
if (m_enhancedProto) {
|
||||
string ver = getEnhancedVersion();
|
||||
if (!ver.empty()) {
|
||||
*ostream << ",\"dv\":\"" << ver << "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result_t FileDevice::open() {
|
||||
close();
|
||||
return m_bufSize == 0 ? RESULT_ERR_DEVICE : RESULT_OK;
|
||||
@@ -220,8 +214,6 @@ result_t FileDevice::afterOpen() {
|
||||
m_listener->notifyStatus(false, "resetting");
|
||||
}
|
||||
m_resetRequested = true;
|
||||
} else if (m_initialSend && !write(ESC)) {
|
||||
return RESULT_ERR_SEND;
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
@@ -339,7 +331,7 @@ result_t FileDevice::send(symbol_t value) {
|
||||
if (!isValid()) {
|
||||
return RESULT_ERR_DEVICE;
|
||||
}
|
||||
if (m_readOnly || !write(value)) {
|
||||
if (!write(value)) {
|
||||
return RESULT_ERR_SEND;
|
||||
}
|
||||
if (m_listener != nullptr) {
|
||||
@@ -496,9 +488,6 @@ result_t FileDevice::startArbitration(symbol_t masterAddress) {
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (m_readOnly) {
|
||||
return RESULT_ERR_SEND;
|
||||
}
|
||||
m_arbitrationMaster = masterAddress;
|
||||
if (m_enhancedProto && masterAddress != SYN) {
|
||||
if (!write(masterAddress, true)) {
|
||||
|
||||
+23
-37
@@ -99,10 +99,8 @@ class Device {
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
* @param readOnly whether to allow read access to the device only.
|
||||
* @param initialSend whether to send an initial @a ESC symbol in @a open().
|
||||
*/
|
||||
Device(const char* name, bool readOnly, bool initialSend);
|
||||
explicit Device(const char* name);
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -115,13 +113,10 @@ class Device {
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
* @param extraLatency the extra bus transfer latency in milliseconds.
|
||||
* @param checkDevice whether to regularly check the device availability (only for serial devices).
|
||||
* @param readOnly whether to allow read access to the device only.
|
||||
* @param initialSend whether to send an initial @a ESC symbol in @a open().
|
||||
* @return the new @a Device, or nullptr on error.
|
||||
* Note: the caller needs to free the created instance.
|
||||
*/
|
||||
static Device* create(const char* name, unsigned int extraLatency = 0, bool checkDevice = true,
|
||||
bool readOnly = false, bool initialSend = false);
|
||||
static Device* create(const char* name, unsigned int extraLatency = 0, bool checkDevice = true);
|
||||
|
||||
/**
|
||||
* Get the device name.
|
||||
@@ -129,12 +124,6 @@ class Device {
|
||||
*/
|
||||
const char* getName() const { return m_name; }
|
||||
|
||||
/**
|
||||
* Return whether to allow read access to the device only.
|
||||
* @return whether to allow read access to the device only.
|
||||
*/
|
||||
bool isReadOnly() const { return m_readOnly; }
|
||||
|
||||
/**
|
||||
* Set the @a DeviceListener.
|
||||
* @param listener the @a DeviceListener.
|
||||
@@ -142,13 +131,18 @@ class Device {
|
||||
void setListener(DeviceListener* listener) { m_listener = listener; }
|
||||
|
||||
/**
|
||||
* Format device infos in plain text or JSON format.
|
||||
* Format device infos in plain text.
|
||||
* @param output the @a ostringstream to append the infos to.
|
||||
* @param verbose whether to add verbose infos.
|
||||
* @param asJson whether to format as JSON rather than plain text.
|
||||
* @param noWait true to not wait for any response asynchronously and return immediately.
|
||||
* @param prefix true for the synchronously retrievable prefix, false for the potentially asynchronous suffix.
|
||||
*/
|
||||
virtual void formatInfo(ostringstream* output, bool verbose, bool asJson = false, bool noWait = false) = 0;
|
||||
virtual void formatInfo(ostringstream* output, bool verbose, bool prefix) = 0;
|
||||
|
||||
/**
|
||||
* Format device infos in JSON format.
|
||||
* @param output the @a ostringstream to append the infos to.
|
||||
*/
|
||||
virtual void formatInfoJson(ostringstream* output) = 0;
|
||||
|
||||
/**
|
||||
* Open the file descriptor.
|
||||
@@ -160,7 +154,7 @@ class Device {
|
||||
* Has to be called by subclasses upon successful opening the device as last action in open().
|
||||
* @return the @a result_t code.
|
||||
*/
|
||||
virtual result_t afterOpen();
|
||||
virtual result_t afterOpen() { return RESULT_OK; }
|
||||
|
||||
/**
|
||||
* Close the file descriptor if opened.
|
||||
@@ -213,12 +207,6 @@ class Device {
|
||||
/** the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). */
|
||||
const char* m_name;
|
||||
|
||||
/** whether to allow read access to the device only. */
|
||||
const bool m_readOnly;
|
||||
|
||||
/** whether to send an initial @a ESC symbol in @a open(). */
|
||||
const bool m_initialSend;
|
||||
|
||||
/** the @a DeviceListener, or nullptr. */
|
||||
DeviceListener* m_listener;
|
||||
};
|
||||
@@ -234,11 +222,9 @@ class FileDevice : public Device {
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
* @param checkDevice whether to regularly check the device availability.
|
||||
* @param latency the bus transfer latency in milliseconds.
|
||||
* @param readOnly whether to allow read access to the device only.
|
||||
* @param initialSend whether to send an initial @a ESC symbol in @a open().
|
||||
* @param enhancedProto whether to use the ebusd enhanced protocol.
|
||||
*/
|
||||
FileDevice(const char* name, bool checkDevice, unsigned int latency, bool readOnly, bool initialSend,
|
||||
FileDevice(const char* name, bool checkDevice, unsigned int latency,
|
||||
bool enhancedProto = false);
|
||||
|
||||
public:
|
||||
@@ -248,7 +234,10 @@ class FileDevice : public Device {
|
||||
virtual ~FileDevice();
|
||||
|
||||
// @copydoc
|
||||
void formatInfo(ostringstream* output, bool verbose, bool asJson = false, bool noWait = false) override;
|
||||
void formatInfo(ostringstream* output, bool verbose, bool prefix) override;
|
||||
|
||||
// @copydoc
|
||||
void formatInfoJson(ostringstream* output) override;
|
||||
|
||||
// @copydoc
|
||||
result_t open() override;
|
||||
@@ -450,14 +439,12 @@ class SerialDevice : public FileDevice {
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
* @param checkDevice whether to regularly check the device availability.
|
||||
* @param extraLatency the extra bus transfer latency in milliseconds.
|
||||
* @param readOnly whether to allow read access to the device only.
|
||||
* @param initialSend whether to send an initial @a ESC symbol in @a open().
|
||||
* @param enhancedProto whether to use the ebusd enhanced protocol.
|
||||
* @param enhancedHighSpeed whether to use ebusd enhanced protocol in high speed mode.
|
||||
*/
|
||||
SerialDevice(const char* name, bool checkDevice, unsigned int extraLatency, bool readOnly, bool initialSend,
|
||||
SerialDevice(const char* name, bool checkDevice, unsigned int extraLatency,
|
||||
bool enhancedProto = false, bool enhancedHighSpeed = false)
|
||||
: FileDevice(name, checkDevice, extraLatency, readOnly, initialSend, enhancedProto),
|
||||
: FileDevice(name, checkDevice, extraLatency, enhancedProto),
|
||||
m_enhancedHighSpeed(enhancedHighSpeed) {
|
||||
}
|
||||
|
||||
@@ -498,14 +485,12 @@ class NetworkDevice : public FileDevice {
|
||||
* @param hostOrIp the host name or IP address of the device.
|
||||
* @param port the TCP or UDP port of the device.
|
||||
* @param extraLatency the extra bus transfer latency in milliseconds.
|
||||
* @param readOnly whether to allow read access to the device only.
|
||||
* @param initialSend whether to send an initial @a ESC symbol in @a open().
|
||||
* @param udp true for UDP, false to TCP.
|
||||
* @param enhancedProto whether to use the ebusd enhanced protocol.
|
||||
*/
|
||||
NetworkDevice(const char* name, const char* hostOrIp, uint16_t port, unsigned int extraLatency, bool readOnly,
|
||||
bool initialSend, bool udp, bool enhancedProto = false)
|
||||
: FileDevice(name, true, NETWORK_LATENCY_MS+extraLatency, readOnly, initialSend, enhancedProto),
|
||||
NetworkDevice(const char* name, const char* hostOrIp, uint16_t port, unsigned int extraLatency,
|
||||
bool udp, bool enhancedProto = false)
|
||||
: FileDevice(name, true, NETWORK_LATENCY_MS+extraLatency, enhancedProto),
|
||||
m_hostOrIp(hostOrIp), m_port(port), m_udp(udp) {}
|
||||
|
||||
/**
|
||||
@@ -514,6 +499,7 @@ class NetworkDevice : public FileDevice {
|
||||
~NetworkDevice() override {
|
||||
if (m_hostOrIp) {
|
||||
free((void*)m_hostOrIp);
|
||||
m_hostOrIp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,14 +43,35 @@ ProtocolHandler* ProtocolHandler::create(const ebus_protocol_config_t config,
|
||||
return new DirectProtocolHandler(config, device, listener);
|
||||
}
|
||||
|
||||
void ProtocolHandler::formatInfo(ostringstream* ostream, bool verbose, bool noWait) {
|
||||
m_device->formatInfo(ostream, verbose, true);
|
||||
if (isReadOnly()) {
|
||||
*ostream << ", readonly";
|
||||
}
|
||||
if (noWait) {
|
||||
return;
|
||||
}
|
||||
m_device->formatInfo(ostream, verbose, false);
|
||||
}
|
||||
|
||||
void ProtocolHandler::formatInfoJson(ostringstream* ostream) {
|
||||
m_device->formatInfoJson(ostream);
|
||||
}
|
||||
|
||||
void ProtocolHandler::clear() {
|
||||
memset(m_seenAddresses, 0, sizeof(m_seenAddresses));
|
||||
m_masterCount = 1;
|
||||
}
|
||||
|
||||
bool ProtocolHandler::addRequest(BusRequest* request, bool wait) {
|
||||
result_t ProtocolHandler::addRequest(BusRequest* request, bool wait) {
|
||||
if (m_config.readOnly) {
|
||||
return RESULT_ERR_DEVICE;
|
||||
}
|
||||
m_nextRequests.push(request);
|
||||
return !wait || m_finishedRequests.remove(request, true);
|
||||
if (!wait || m_finishedRequests.remove(request, true)) {
|
||||
return RESULT_OK;
|
||||
}
|
||||
return RESULT_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
result_t ProtocolHandler::sendAndWait(const MasterSymbolString& master, SlaveSymbolString* slave) {
|
||||
@@ -63,8 +84,11 @@ result_t ProtocolHandler::sendAndWait(const MasterSymbolString& master, SlaveSym
|
||||
logInfo(lf_bus, "send message: %s", master.getStr().c_str());
|
||||
|
||||
for (int sendRetries = m_config.failedSendRetries + 1; sendRetries > 0; sendRetries--) {
|
||||
bool success = addRequest(&request, true);
|
||||
result = success ? request.m_result : RESULT_ERR_TIMEOUT;
|
||||
result = addRequest(&request, true);
|
||||
bool success = result == RESULT_OK;
|
||||
if (success) {
|
||||
result = request.m_result;
|
||||
}
|
||||
if (result == RESULT_OK) {
|
||||
break;
|
||||
}
|
||||
@@ -103,7 +127,7 @@ bool ProtocolHandler::addSeenAddress(symbol_t address) {
|
||||
return false;
|
||||
}
|
||||
if (!isMaster(address)) {
|
||||
if (!m_device->isReadOnly() && address == m_ownSlaveAddress) {
|
||||
if (!m_config.readOnly && address == m_ownSlaveAddress) {
|
||||
if (!m_addressConflict) {
|
||||
m_addressConflict = true;
|
||||
logError(lf_bus, "own slave address %2.2x is used by another participant", address);
|
||||
@@ -122,7 +146,7 @@ bool ProtocolHandler::addSeenAddress(symbol_t address) {
|
||||
return false;
|
||||
}
|
||||
bool ret = false;
|
||||
if (!m_device->isReadOnly() && address == m_ownMasterAddress) {
|
||||
if (!m_config.readOnly && address == m_ownMasterAddress) {
|
||||
if (!m_addressConflict) {
|
||||
m_addressConflict = true;
|
||||
logError(lf_bus, "own master address %2.2x is used by another participant", address);
|
||||
|
||||
+37
-6
@@ -52,6 +52,8 @@ namespace ebusd {
|
||||
|
||||
/** settings for the eBUS protocol handler. */
|
||||
typedef struct ebus_protocol_config {
|
||||
/** whether to allow read access to the device only. */
|
||||
bool readOnly;
|
||||
/** the own master address. */
|
||||
symbol_t ownAddress;
|
||||
/** whether to answer queries for the own master/slave address. */
|
||||
@@ -68,9 +70,19 @@ typedef struct ebus_protocol_config {
|
||||
unsigned int lockCount;
|
||||
/** whether to enable AUTO-SYN symbol generation. */
|
||||
bool generateSyn;
|
||||
/** whether to send an initial escape symbol after connecting device. */
|
||||
bool initialSend;
|
||||
} ebus_protocol_config_t;
|
||||
|
||||
|
||||
/** the possible protocol states. */
|
||||
enum ProtocolState {
|
||||
ps_noSignal, //!< no signal on the bus
|
||||
ps_idle, //!< idle (after @a SYN symbol)
|
||||
ps_empty, //!< idle, no more lock remaining, and no other request queued
|
||||
};
|
||||
|
||||
|
||||
class ProtocolHandler;
|
||||
|
||||
/**
|
||||
@@ -185,9 +197,9 @@ class ProtocolListener {
|
||||
|
||||
/**
|
||||
* Called to notify a status update from the protocol.
|
||||
* @param signal true when signal is acquired, false otherwise.
|
||||
* @param state the current protocol state.
|
||||
*/
|
||||
virtual void notifyProtocolStatus(bool signal) = 0; // abstract
|
||||
virtual void notifyProtocolStatus(ProtocolState state) = 0; // abstract
|
||||
|
||||
/**
|
||||
* Called to notify a new valid seen address on the bus.
|
||||
@@ -234,7 +246,7 @@ class ProtocolHandler : public WaitThread {
|
||||
m_reconnect(false),
|
||||
m_ownMasterAddress(config.ownAddress), m_ownSlaveAddress(getSlaveAddress(config.ownAddress)),
|
||||
m_addressConflict(false),
|
||||
m_masterCount(device->isReadOnly()?0:1),
|
||||
m_masterCount(config.readOnly ? 0 : 1),
|
||||
m_symbolLatencyMin(-1), m_symbolLatencyMax(-1), m_arbitrationDelayMin(-1),
|
||||
m_arbitrationDelayMax(-1), m_lastReceive(0),
|
||||
m_symPerSec(0), m_maxSymPerSec(0) {
|
||||
@@ -266,6 +278,25 @@ class ProtocolHandler : public WaitThread {
|
||||
*/
|
||||
static ProtocolHandler* create(const ebus_protocol_config_t config, Device* device, ProtocolListener* listener);
|
||||
|
||||
/**
|
||||
* Format device/protocol infos in plain text.
|
||||
* @param output the @a ostringstream to append the infos to.
|
||||
* @param verbose whether to add verbose infos.
|
||||
* @param noWait true to not wait for any response asynchronously and return immediately.
|
||||
*/
|
||||
virtual void formatInfo(ostringstream* output, bool verbose, bool noWait);
|
||||
|
||||
/**
|
||||
* Format device/protocol infos in JSON format.
|
||||
* @param output the @a ostringstream to append the infos to.
|
||||
*/
|
||||
virtual void formatInfoJson(ostringstream* output);
|
||||
|
||||
/**
|
||||
* @return whether to allow read access to the device only.
|
||||
*/
|
||||
bool isReadOnly() const { return m_config.readOnly; }
|
||||
|
||||
/**
|
||||
* @return the own master address.
|
||||
*/
|
||||
@@ -286,7 +317,7 @@ class ProtocolHandler : public WaitThread {
|
||||
* @return @p true when the address is the own master or slave address (if not readonly).
|
||||
*/
|
||||
bool isOwnAddress(symbol_t address) const {
|
||||
return !m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress);
|
||||
return !m_config.readOnly && (address == m_ownMasterAddress || address == m_ownSlaveAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,9 +355,9 @@ class ProtocolHandler : public WaitThread {
|
||||
* Add a @a BusRequest to the internal queue and optionally wait for it to complete.
|
||||
* @param request the @a BusRequest to add.
|
||||
* @param wait true to wait for it to complete, false to return immediately.
|
||||
* @return true when it was not waited for or when it was completed.
|
||||
* @return the result code of adding the request (i.e. RESULT_OK when it was not waited for or when it was completed).
|
||||
*/
|
||||
virtual bool addRequest(BusRequest* request, bool wait);
|
||||
virtual result_t addRequest(BusRequest* request, bool wait);
|
||||
|
||||
/**
|
||||
* Send a message on the bus and wait for the answer.
|
||||
|
||||
@@ -91,6 +91,9 @@ void DirectProtocolHandler::run() {
|
||||
result_t result = m_device->open();
|
||||
if (result == RESULT_OK) {
|
||||
logNotice(lf_bus, "re-opened %s", m_device->getName());
|
||||
if (m_config.initialSend && !m_config.readOnly) {
|
||||
m_device->send(ESC);
|
||||
}
|
||||
} else {
|
||||
logError(lf_bus, "unable to open %s: %s", m_device->getName(), getResultCode(result));
|
||||
setState(bs_noSignal, result);
|
||||
@@ -131,6 +134,10 @@ result_t DirectProtocolHandler::handleSymbol() {
|
||||
}
|
||||
if (!m_device->isArbitrating() && m_currentRequest == nullptr && m_remainLockCount == 0) {
|
||||
BusRequest* startRequest = m_nextRequests.peek();
|
||||
if (startRequest == nullptr) {
|
||||
m_listener->notifyProtocolStatus(ps_empty);
|
||||
startRequest = m_nextRequests.peek();
|
||||
}
|
||||
if (startRequest != nullptr) { // initiate arbitration
|
||||
symbol_t master = startRequest->getMaster()[0];
|
||||
logDebug(lf_bus, "start request %2.2x", master);
|
||||
@@ -220,7 +227,7 @@ result_t DirectProtocolHandler::handleSymbol() {
|
||||
// send symbol if necessary
|
||||
result_t result;
|
||||
struct timespec sentTime, recvTime;
|
||||
if (sending) {
|
||||
if (sending && !m_config.readOnly) {
|
||||
if (m_state != bs_sendSyn && (sendSymbol == ESC || sendSymbol == SYN)) {
|
||||
if (m_escape) {
|
||||
sendSymbol = (symbol_t)(sendSymbol == ESC ? 0x00 : 0x01);
|
||||
@@ -254,7 +261,7 @@ result_t DirectProtocolHandler::handleSymbol() {
|
||||
clockGettime(&recvTime);
|
||||
}
|
||||
bool sentAutoSyn = false;
|
||||
if (!sending && result == RESULT_ERR_TIMEOUT && m_generateSynInterval > 0
|
||||
if (!sending && !m_config.readOnly && result == RESULT_ERR_TIMEOUT && m_generateSynInterval > 0
|
||||
&& timeout >= m_generateSynInterval && (m_state == bs_noSignal || m_state == bs_skip)) {
|
||||
// check if acting as AUTO-SYN generator is required
|
||||
result = m_device->send(SYN);
|
||||
@@ -671,7 +678,7 @@ result_t DirectProtocolHandler::setState(BusState state, result_t result, bool f
|
||||
|
||||
if (state == bs_noSignal) { // notify all requests
|
||||
if (m_state != bs_noSignal) {
|
||||
m_listener->notifyProtocolStatus(false);
|
||||
m_listener->notifyProtocolStatus(ps_idle);
|
||||
}
|
||||
m_response.clear(); // notify with empty response
|
||||
while ((m_currentRequest = m_nextRequests.pop()) != nullptr) {
|
||||
@@ -686,7 +693,7 @@ result_t DirectProtocolHandler::setState(BusState state, result_t result, bool f
|
||||
}
|
||||
}
|
||||
} else if (m_state == bs_noSignal) {
|
||||
m_listener->notifyProtocolStatus(true);
|
||||
m_listener->notifyProtocolStatus(ps_noSignal);
|
||||
}
|
||||
|
||||
m_escape = 0;
|
||||
|
||||
Reference in New Issue
Block a user