Skip to content

Commit

Permalink
fix connection state handling: each record sets its own, each item se…
Browse files Browse the repository at this point in the history
…ts the element tree
  • Loading branch information
dirk-zimoch committed Jul 9, 2024
1 parent 820371b commit 56cb080
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 51 deletions.
25 changes: 2 additions & 23 deletions devOpcuaSup/Item.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,9 @@
#include <epicsTypes.h>
#include <epicsTime.h>

namespace DevOpcua {
#include "devOpcua.h"

/**
* @brief Enum for the EPICS related state of an OPC UA item
*/
enum ConnectionStatus { down, initialRead, initialWrite, up };

inline const char *
connectionStatusString (const ConnectionStatus status) {
switch(status) {
case down: return "down";
case initialRead: return "initialRead";
case initialWrite: return "initialWrite";
case up: return "up";
}
return "Illegal Value";
}
namespace DevOpcua {

struct linkInfo;
class RecordConnector;
Expand Down Expand Up @@ -83,13 +69,6 @@ class Item
const epicsUInt32 len = 0,
epicsTimeStamp *ts = nullptr) = 0;

/**
* @brief Get the EPICS-related state of the item.
*
* @return connection state (EPICS-related)
*/
virtual ConnectionStatus state() const = 0;

/**
* @brief Set the EPICS-related state of the item.
*
Expand Down
5 changes: 3 additions & 2 deletions devOpcuaSup/RecordConnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class RecordConnector
return pdataelement->writeArray(val, len, num, prec);
}

ConnectionStatus state() const { return pitem->state(); }
void setState(ConnectionStatus state) { pitem->setState(state); }
ConnectionStatus state() const { return connState; }
void setState(ConnectionStatus state) { connState = state; }

void
getStatus(epicsUInt32 *code, char *text, const epicsUInt32 len, epicsTimeStamp *ts = nullptr)
Expand Down Expand Up @@ -145,6 +145,7 @@ class RecordConnector
std::shared_ptr<DataElement> pdataelement;
IOSCANPVT ioscanpvt;
ProcessReason reason;
ConnectionStatus connState = ConnectionStatus::down;

private:
dbCommon *prec;
Expand Down
18 changes: 16 additions & 2 deletions devOpcuaSup/UaSdk/DataElementUaSdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ DataElementUaSdk::setIncomingData(const UaVariant &value,
incomingData = value;

if (isLeaf()) {
if ((pitem->state() == ConnectionStatus::initialRead
if ((pconnector->state() == ConnectionStatus::initialRead
&& (reason == ProcessReason::readComplete || reason == ProcessReason::readFailure))
|| (pitem->state() == ConnectionStatus::up)) {
|| (pconnector->state() == ConnectionStatus::up)) {
Guard(pconnector->lock);
bool wasFirst = false;
// Make a copy of the value for this element and put it on the queue
Expand Down Expand Up @@ -249,6 +249,20 @@ DataElementUaSdk::setIncomingEvent (ProcessReason reason)
}
}

void
DataElementUaSdk::setState(const ConnectionStatus state)
{
if (isLeaf()) {
Guard(pconnector->lock);
pconnector->setState(state);
} else {
for (auto &it : elements) {
auto pelem = it.lock();
pelem->setState(state);
}
}
}

// Helper to update one data structure element from pointer to child
bool
DataElementUaSdk::updateDataInGenericValue (UaGenericStructureValue &value,
Expand Down
5 changes: 5 additions & 0 deletions devOpcuaSup/UaSdk/DataElementUaSdk.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ class DataElementUaSdk : public DataElement
*/
void setIncomingEvent(ProcessReason reason);

/**
* @brief Set the EPICS-related state of the element and all sub-elements.
*/
void setState(const ConnectionStatus state);

/**
* @brief Get the outgoing data value from the DataElement.
*
Expand Down
15 changes: 11 additions & 4 deletions devOpcuaSup/UaSdk/ItemUaSdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ ItemUaSdk::ItemUaSdk(const linkInfo &info)
, dataTreeDirty(false)
, lastStatus(OpcUa_BadServerNotConnected)
, lastReason(ProcessReason::connectionLoss)
, connState(ConnectionStatus::down)
{
if (linkinfo.subscription != "" && linkinfo.monitor) {
subscription = SubscriptionUaSdk::find(linkinfo.subscription);
Expand Down Expand Up @@ -100,7 +99,7 @@ ItemUaSdk::show (int level) const
else
std::cout << ";s=" << linkinfo.identifierString;
std::cout << " record=" << recConnector->getRecordName()
<< " state=" << connectionStatusString(connState)
<< " state=" << connectionStatusString(recConnector->state())
<< " status=" << UaStatus(lastStatus).toString().toUtf8()
<< " dataDirty=" << (dataTreeDirty ? "y" : "n")
<< " context=" << linkinfo.subscription << "@" << session->getName()
Expand Down Expand Up @@ -182,10 +181,10 @@ ItemUaSdk::setIncomingData(const OpcUa_DataValue &value, ProcessReason reason)
}

if (linkinfo.isItemRecord) {
if (state() == ConnectionStatus::initialRead
if (recConnector->state() == ConnectionStatus::initialRead
&& reason == ProcessReason::readComplete
&& recConnector->bini() == LinkOptionBini::write) {
setState(ConnectionStatus::initialWrite);
recConnector->setState(ConnectionStatus::initialWrite);
recConnector->requestRecordProcessing(ProcessReason::writeRequest);
} else {
recConnector->requestRecordProcessing(reason);
Expand Down Expand Up @@ -214,6 +213,14 @@ ItemUaSdk::setIncomingEvent(const ProcessReason reason)
recConnector->requestRecordProcessing(reason);
}

void
ItemUaSdk::setState(const ConnectionStatus state)
{
if (auto pd = dataTree.root().lock()) {
pd->setState(state);
}
}

void
ItemUaSdk::markAsDirty()
{
Expand Down
8 changes: 1 addition & 7 deletions devOpcuaSup/UaSdk/ItemUaSdk.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,12 @@ class ItemUaSdk : public Item
char *text = nullptr,
const epicsUInt32 len = 0,
epicsTimeStamp *ts = nullptr) override;
/**
* @brief Get the EPICS-related state of the item.
* See DevOpcua::Item::state
*/
virtual ConnectionStatus state() const override { return connState; }

/**
* @brief Set the EPICS-related state of the item.
* See DevOpcua::Item::setState
*/
virtual void setState(const ConnectionStatus state) override { connState = state; }
virtual void setState(const ConnectionStatus state) override;

/**
* @brief Return registered status.
Expand Down Expand Up @@ -231,7 +226,6 @@ class ItemUaSdk : public Item
bool dataTreeDirty; /**< true if any element has been modified */
UaStatusCode lastStatus; /**< status code of most recent service */
ProcessReason lastReason; /**< most recent processing reason */
ConnectionStatus connState; /**< Connection state of the item */
epicsTime tsClient; /**< client (local) time stamp */
epicsTime tsServer; /**< server time stamp */
epicsTime tsSource; /**< source time stamp */
Expand Down
1 change: 1 addition & 0 deletions devOpcuaSup/devOpcua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,7 @@ opcua_action_item(REC *prec)
}
pcon->getStatus(&prec->statcode, prec->stattext, MAX_STRING_SIZE + 1, &prec->time);
traceItemActionPrint(pdbc, pcon, ret, action, prec->statcode, prec->stattext);
manageStateAndBiniProcessing(pcon);
}
CATCH()
return ret;
Expand Down
16 changes: 16 additions & 0 deletions devOpcuaSup/devOpcua.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,22 @@ processReasonString (const ProcessReason type)
return "Illegal Value";
}

/**
* @brief Enum for the per-record connection state
*/
enum ConnectionStatus { down, initialRead, initialWrite, up };

inline const char *
connectionStatusString (const ConnectionStatus status) {
switch(status) {
case down: return "down";
case initialRead: return "initialRead";
case initialWrite: return "initialWrite";
case up: return "up";
}
return "Illegal Value";
}

template<typename R>
struct dset6 {
long N;
Expand Down
18 changes: 16 additions & 2 deletions devOpcuaSup/open62541/DataElementOpen62541.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,9 @@ DataElementOpen62541::setIncomingData (const UA_Variant &value,
UA_Variant_copy(&value, &incomingData);

if (isLeaf()) {
if ((pitem->state() == ConnectionStatus::initialRead
if ((pconnector->state() == ConnectionStatus::initialRead
&& (reason == ProcessReason::readComplete || reason == ProcessReason::readFailure))
|| (pitem->state() == ConnectionStatus::up)) {
|| (pconnector->state() == ConnectionStatus::up)) {

Guard(pconnector->lock);
bool wasFirst = false;
Expand Down Expand Up @@ -314,6 +314,20 @@ DataElementOpen62541::setIncomingEvent (ProcessReason reason)
}
}

void
DataElementOpen62541::setState(const ConnectionStatus state)
{
if (isLeaf()) {
Guard(pconnector->lock);
pconnector->setState(state);
} else {
for (auto &it : elements) {
auto pelem = it.lock();
pelem->setState(state);
}
}
}

// Helper to update one data structure element from pointer to child
bool
DataElementOpen62541::updateDataInStruct (void* container,
Expand Down
5 changes: 5 additions & 0 deletions devOpcuaSup/open62541/DataElementOpen62541.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,11 @@ class DataElementOpen62541 : public DataElement
*/
void setIncomingEvent(ProcessReason reason);

/**
* @brief Set the EPICS-related state of the element and all sub-elements.
*/
void setState(const ConnectionStatus state);

/**
* @brief Get the outgoing data value from the DataElement.
*
Expand Down
17 changes: 13 additions & 4 deletions devOpcuaSup/open62541/ItemOpen62541.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ ItemOpen62541::ItemOpen62541(const linkInfo &info)
, dataTreeDirty(false)
, lastStatus(UA_STATUSCODE_BADSERVERNOTCONNECTED)
, lastReason(ProcessReason::connectionLoss)
, connState(ConnectionStatus::down)
{
UA_NodeId_init(&nodeid);
if (linkinfo.subscription != "" && linkinfo.monitor) {
Expand Down Expand Up @@ -95,7 +94,7 @@ ItemOpen62541::show (int level) const
else
std::cout << ";s=" << linkinfo.identifierString;
std::cout << " record=" << recConnector->getRecordName()
<< " state=" << connectionStatusString(connState)
<< " state=" << connectionStatusString(recConnector->state())
<< " status=" << UA_StatusCode_name(lastStatus)
<< " dataDirty=" << (dataTreeDirty ? "y" : "n")
<< " context=" << linkinfo.subscription << "@" << session->getName()
Expand Down Expand Up @@ -181,10 +180,10 @@ ItemOpen62541::setIncomingData(const UA_DataValue &value, ProcessReason reason)
}

if (linkinfo.isItemRecord) {
if (state() == ConnectionStatus::initialRead
if (recConnector->state() == ConnectionStatus::initialRead
&& reason == ProcessReason::readComplete
&& recConnector->bini() == LinkOptionBini::write) {
setState(ConnectionStatus::initialWrite);
recConnector->setState(ConnectionStatus::initialWrite);
recConnector->requestRecordProcessing(ProcessReason::writeRequest);
} else {
recConnector->requestRecordProcessing(reason);
Expand Down Expand Up @@ -213,6 +212,16 @@ ItemOpen62541::setIncomingEvent(const ProcessReason reason)
recConnector->requestRecordProcessing(reason);
}

void
ItemOpen62541::setState(const ConnectionStatus state)
{
if (auto pd = dataTree.root().lock()) {
pd->setState(state);
}
if (linkinfo.isItemRecord)
recConnector->setState(state);
}

void
ItemOpen62541::markAsDirty()
{
Expand Down
8 changes: 1 addition & 7 deletions devOpcuaSup/open62541/ItemOpen62541.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,12 @@ class ItemOpen62541 : public Item
char *text = nullptr,
const epicsUInt32 len = 0,
epicsTimeStamp *ts = nullptr) override;
/**
* @brief Get the EPICS-related state of the item.
* See DevOpcua::Item::state
*/
virtual ConnectionStatus state() const override { return connState; }

/**
* @brief Set the EPICS-related state of the item.
* See DevOpcua::Item::setState
*/
virtual void setState(const ConnectionStatus state) override { connState = state; }
virtual void setState(const ConnectionStatus state) override;

/**
* @brief Return registered status.
Expand Down Expand Up @@ -226,7 +221,6 @@ class ItemOpen62541 : public Item
bool dataTreeDirty; /**< true if any element has been modified */
UA_StatusCode lastStatus; /**< status code of most recent service */
ProcessReason lastReason; /**< most recent processing reason */
ConnectionStatus connState; /**< Connection state of the item */
epicsTime tsClient; /**< client (local) time stamp */
epicsTime tsServer; /**< server time stamp */
epicsTime tsSource; /**< source time stamp */
Expand Down

0 comments on commit 56cb080

Please sign in to comment.