allow initsend for enhanced as well, cleaner separation

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