From 7d4d72eae1b5f9bbb1c1f8e1ce192bd861d3190d Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Thu, 11 Oct 2012 14:16:44 +0200 Subject: [PATCH] new NTTable definition, eget pv formatting --- testApp/remote/eget.cpp | 358 +++++++++++----------------------- testApp/remote/pvget.cpp | 2 +- testApp/remote/pvput.cpp | 2 - testApp/remote/testServer.cpp | 32 ++- 4 files changed, 133 insertions(+), 261 deletions(-) diff --git a/testApp/remote/eget.cpp b/testApp/remote/eget.cpp index 5ea97a0..e048a4b 100644 --- a/testApp/remote/eget.cpp +++ b/testApp/remote/eget.cpp @@ -19,149 +19,13 @@ #include #include +#include "pvutils.cpp" + using namespace std; using namespace std::tr1; using namespace epics::pvData; using namespace epics::pvAccess; -class RequesterImpl : public Requester, - public std::tr1::enable_shared_from_this -{ -public: - - virtual String getRequesterName() - { - return "RequesterImpl"; - }; - - virtual void message(String const & message,MessageType messageType) - { - std::cout << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; - } -}; - - -/// terse mode functions - -void convertStructure(StringBuilder buffer,PVStructure *data,int notFirst); -void convertArray(StringBuilder buffer,PVScalarArray * pv,int notFirst); -void convertStructureArray(StringBuilder buffer,PVStructureArray * pvdata,int notFirst); - - - - - - - - -void convertToString(StringBuilder buffer,PVField * pv,int notFirst) -{ - Type type = pv->getField()->getType(); - if(type==structure) { - convertStructure(buffer,static_cast(pv),notFirst); - return; - } - if(type==scalarArray) { - convertArray(buffer,static_cast(pv),notFirst); - *buffer += "\t"; - return; - } - if(type==structureArray) { - convertStructureArray( - buffer,static_cast(pv),notFirst); - *buffer += "\t"; - return; - } - - // scalar stringification - std::stringstream sstream; - sstream << std::boolalpha << *pv; - *buffer += sstream.str(); - *buffer += "\t"; -} - -void convertStructure(StringBuilder buffer,PVStructure *data,int notFirst) -{ - PVFieldPtrArray fieldsData = data->getPVFields(); - int length = data->getStructure()->getNumberFields(); - for(int i=0; igetLength(); - if(length<=0) { - return; - } - StructureArrayData data = StructureArrayData(); - pvdata->get(0, length, data); - for (int i = 0; i < length; i++) { - PVStructurePtr pvStructure = data.data[i]; - if (pvStructure == 0) { - *buffer += "null"; - } else { - convertToString(buffer,pvStructure.get(),notFirst+1); - } - } -} - - - - - - - - - - - -/* Converts a hex character to its integer value */ -char from_hex(char ch) { - return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; -} - -/* Converts an integer value to its hex character*/ -char to_hex(char code) { - static char hex[] = "0123456789abcdef"; - return hex[code & 15]; -} - -/* Returns a url-encoded version of str */ -/* IMPORTANT: be sure to free() the returned string after use */ -char *url_encode(char *str) { - char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf; - bool firstEquals = true; - while (*pstr) { - if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') - *pbuf++ = *pstr; - else if (*pstr == ' ') - *pbuf++ = '+'; - else if (*pstr == '=' && firstEquals) - { - firstEquals = false; - *pbuf++ = '='; - } - else - *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); - pstr++; - } - *pbuf = '\0'; - return buf; -} - - void formatNTAny(std::ostream& o, PVStructurePtr const & pvStruct) { @@ -187,6 +51,17 @@ void formatNTScalar(std::ostream& o, PVStructurePtr const & pvStruct) o << *value; } +std::ostream& formatScalarArray(std::ostream& o, PVScalarArrayPtr const & pvScalarArray) +{ + size_t len = pvScalarArray->getLength(); + if (len == 0) + o << "(empty)" << std::endl; // TODO is this OK? + else + for (size_t i = 0; i < len; i++) + (pvScalarArray.get())->dumpValue(o, i) << std::endl; + return o; +} + void formatNTScalarArray(std::ostream& o, PVStructurePtr const & pvStruct) { PVScalarArrayPtr value = dynamic_pointer_cast(pvStruct->getSubField("value")); @@ -196,7 +71,8 @@ void formatNTScalarArray(std::ostream& o, PVStructurePtr const & pvStruct) return; } - o << *value; + //o << *value; + formatScalarArray(o, value); } void formatNTTable(std::ostream& o, PVStructurePtr const & pvStruct) @@ -208,24 +84,31 @@ void formatNTTable(std::ostream& o, PVStructurePtr const & pvStruct) return; } - size_t numColumns = labels->getLength(); - if ((pvStruct->getPVFields().size()-1) < numColumns) + PVStructurePtr value = pvStruct->getStructureField("value"); + if (value.get() == 0) { - std::cerr << "malformed NTTable, not enough of columns - " << numColumns << " column(s) expected" << std::endl; - return; + std::cerr << "no 'value' structure in NTTable" << std::endl; + return; } - + // next numColumns fields are columns size_t maxValues = 0; vector columnData; - PVFieldPtrArray fields = pvStruct->getPVFields(); + PVFieldPtrArray fields = value->getPVFields(); + size_t numColumns = fields.size(); + + if (labels->getLength() != numColumns) + { + std::cerr << "malformed NTTable, length of 'labels' array does not equal to a number of 'value' structure subfields" << std::endl; + return; + } + for (size_t i = 0; i < numColumns; i++) { - // TODO we relay on field ordering here (labels, ) - PVScalarArrayPtr array = dynamic_pointer_cast(fields[i+1]); + PVScalarArrayPtr array = dynamic_pointer_cast(fields[i]); if (array.get() == 0) { - std::cerr << "malformed NTTable, " << (i+1+1) << ". field is not scalar_t[]" << std::endl; + std::cerr << "malformed NTTable, " << (i+1) << ". field is not scalar_t[]" << std::endl; return; } size_t arrayLength = array->getLength(); @@ -350,7 +233,7 @@ void initializeNTFormatterLUT() ntFormatterLUT["scalarArray_t"] = formatNTScalarArray; } -void toNTString(std::ostream& o, PVFieldPtr const & pv) +void formatNT(std::ostream& o, PVFieldPtr const & pv) { static bool lutInitialized = false; if (!lutInitialized) @@ -374,9 +257,7 @@ void toNTString(std::ostream& o, PVFieldPtr const & pv) else { std::cerr << "unsupported normative type" << std::endl; - String buffer; - pv->toString(&buffer); - o << buffer; + o << *(pv.get()) << std::endl; } return; @@ -384,9 +265,7 @@ void toNTString(std::ostream& o, PVFieldPtr const & pv) } // no ID, just dump - String buffer; - pv->toString(&buffer); - o << buffer; + o << *(pv.get()) << std::endl; } @@ -405,6 +284,7 @@ string request(DEFAULT_REQUEST); enum PrintMode { ValueOnlyMode, StructureMode, TerseMode }; PrintMode mode = ValueOnlyMode; +char fieldSeparator = ' '; void usage (void) { @@ -418,6 +298,7 @@ void usage (void) " -q: Pure pvAccess RPC based service (send NTURI.query as request argument)\n" " -t: Terse mode - print only value, without field names\n" " -d: Enable debug output\n" + " -F : Use as an alternate output field separator\n" " -c: Wait for clean shutdown and report used instance count (for expert users)" "\n\nexamples:\n\n" "#! Get the value of the PV corr:li32:53:bdes\n" @@ -446,14 +327,14 @@ class ChannelGetRequesterImpl : public ChannelGetRequester public: - ChannelGetRequesterImpl(String channelName) : m_channelName(channelName) {}; + ChannelGetRequesterImpl(String channelName) : m_channelName(channelName) {} virtual String getRequesterName() { return "ChannelGetRequesterImpl"; - }; + } - virtual void message(String const & message,MessageType messageType) + virtual void message(String const & message, MessageType messageType) { std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } @@ -505,7 +386,59 @@ class ChannelGetRequesterImpl : public ChannelGetRequester if (mode == ValueOnlyMode) { - PVFieldPtr pvField = m_pvStructure->getSubField("value"); + PVField::shared_pointer value = m_pvStructure->getSubField("value"); + if (value.get() == 0) + { + std::cerr << "no 'value' field" << std::endl; + return; + } + + Type valueType = value->getField()->getType(); + if (valueType == scalar) + std::cout << *(value.get()) << std::endl; + else if (valueType == scalarArray) + { + // TODO decide on formatting (with or without std::endl) + formatScalarArray(std::cout, dynamic_pointer_cast(value)) << std::endl; + } + else + { + // switch to structure mode + std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; + } + } + else if (mode == TerseMode) + terseStructure(std::cout, m_pvStructure) << std::endl; + else + std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; + } + // this is OK since calle holds also owns it + m_channelGet.reset(); + } + + m_event.signal(); + + } + else + { + std::cerr << "[" << m_channelName << "] failed to get: " << status.toString() << std::endl; + { + Lock lock(m_pointerMutex); + // this is OK since caller holds also owns it + m_channelGet.reset(); + } + } + + } + + bool waitUntilGet(double timeOut) + { + return m_event.wait(timeOut); + } +}; + +/* +PVFieldPtr pvField = m_pvStructure->getSubField("value"); if (pvField.get()) { PVScalarArrayPtr pvScalarArray = std::tr1::dynamic_pointer_cast(pvField); @@ -544,30 +477,7 @@ class ChannelGetRequesterImpl : public ChannelGetRequester std::cout << str << std::endl; } } - // this is OK since calle holds also owns it - m_channelGet.reset(); - } - - m_event.signal(); - - } - else - { - std::cerr << "[" << m_channelName << "] failed to get: " << status.toString() << std::endl; - { - Lock lock(m_pointerMutex); - // this is OK since calle holds also owns it - m_channelGet.reset(); - } - } - - } - - bool waitUntilGet(double timeOut) - { - return m_event.wait(timeOut); - } -}; +*/ class ChannelRPCRequesterImpl : public ChannelRPCRequester { @@ -580,14 +490,14 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester public: - ChannelRPCRequesterImpl(String channelName) : m_channelName(channelName) {}; + ChannelRPCRequesterImpl(String channelName) : m_channelName(channelName) {} virtual String getRequesterName() { return "ChannelRPCRequesterImpl"; - }; + } - virtual void message(String const & message,MessageType messageType) + virtual void message(String const & message, MessageType messageType) { std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; } @@ -630,7 +540,7 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester { Lock lock(m_pointerMutex); - toNTString(std::cout, pvResponse); + formatNT(std::cout, pvResponse); std::cout << std::endl; // this is OK since calle holds also owns it @@ -645,7 +555,7 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester std::cerr << "[" << m_channelName << "] failed to RPC: " << status.toString() << std::endl; { Lock lock(m_pointerMutex); - // this is OK since calle holds also owns it + // this is OK since caller holds also owns it m_channelRPC.reset(); } } @@ -671,59 +581,6 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester } }; -class ChannelRequesterImpl : public ChannelRequester -{ -private: - Event m_event; - -public: - - virtual String getRequesterName() - { - return "ChannelRequesterImpl"; - }; - - virtual void message(String const & message,MessageType messageType) - { - std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; - } - - virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel) - { - if (status.isSuccess()) - { - // show warning - if (!status.isOK()) - { - std::cerr << "[" << channel->getChannelName() << "] channel create: " << status.toString() << std::endl; - } - } - else - { - std::cerr << "[" << channel->getChannelName() << "] failed to create a channel: " << status.toString() << std::endl; - } - } - - virtual void channelStateChange(Channel::shared_pointer const & /*channel*/, Channel::ConnectionState connectionState) - { - if (connectionState == Channel::CONNECTED) - { - m_event.signal(); - } - /* - else if (connectionState != Channel::DESTROYED) - { - std::cout << "[" << channel->getChannelName() << "] channel state change: " << Channel::ConnectionStateNames[connectionState] << std::endl; - } - */ - } - - bool waitUntilConnected(double timeOut) - { - return m_event.wait(timeOut); - } -}; - /*+************************************************************************** * * Function: main @@ -746,8 +603,6 @@ int main (int argc, char *argv[]) bool debug = false; bool cleanupAndReport = false; - Requester::shared_pointer requester(new RequesterImpl()); - bool serviceRequest = false; bool onlyQuery = false; string service; @@ -756,7 +611,7 @@ int main (int argc, char *argv[]) setvbuf(stdout,NULL,_IOLBF,BUFSIZ); /* Set stdout to line buffering */ - while ((opt = getopt(argc, argv, ":hr:s:a:w:qtdc")) != -1) { + while ((opt = getopt(argc, argv, ":hr:s:a:w:qtdcF:")) != -1) { switch (opt) { case 'h': /* Print usage */ usage(); @@ -807,6 +662,9 @@ int main (int argc, char *argv[]) case 'c': /* Clean-up and report used instance count */ cleanupAndReport = true; break; + case 'F': /* Store this for output formatting */ + fieldSeparator = (char) *optarg; + break; case '?': fprintf(stderr, "Unrecognized option: '-%c'. ('eget -h' for help.)\n", @@ -838,8 +696,12 @@ int main (int argc, char *argv[]) SET_LOG_LEVEL(debug ? logLevelDebug : logLevelError); + std::cout << std::boolalpha; + terseSeparator(fieldSeparator); + bool allOK = true; + Requester::shared_pointer requester(new RequesterImpl("eget")); // PVs mode if (!serviceRequest) @@ -848,8 +710,8 @@ int main (int argc, char *argv[]) for (int n = 0; optind < argc; n++, optind++) pvs.push_back(argv[optind]); /* Copy PV names from command line */ - PVStructure::shared_pointer pvRequest; - pvRequest = getCreateRequest()->createRequest(request,requester); + PVStructure::shared_pointer pvRequest = + getCreateRequest()->createRequest(request, requester); if(pvRequest.get()==0) { fprintf(stderr, "failed to parse request string\n"); return 1; @@ -907,8 +769,8 @@ int main (int argc, char *argv[]) */ // simply empty - PVStructure::shared_pointer pvRequest; - pvRequest = getCreateRequest()->createRequest(request,requester); + PVStructure::shared_pointer pvRequest = + getCreateRequest()->createRequest(request, requester); if(pvRequest.get()==NULL) { fprintf(stderr, "failed to parse request string\n"); return 1; diff --git a/testApp/remote/pvget.cpp b/testApp/remote/pvget.cpp index efd5706..2dc8823 100644 --- a/testApp/remote/pvget.cpp +++ b/testApp/remote/pvget.cpp @@ -169,7 +169,7 @@ class ChannelGetRequesterImpl : public ChannelGetRequester std::cerr << "[" << m_channelName << "] failed to get: " << status.toString() << std::endl; { Lock lock(m_pointerMutex); - // this is OK since calle holds also owns it + // this is OK since caller holds also owns it m_channelGet.reset(); } } diff --git a/testApp/remote/pvput.cpp b/testApp/remote/pvput.cpp index 3368897..3c80ecb 100644 --- a/testApp/remote/pvput.cpp +++ b/testApp/remote/pvput.cpp @@ -525,8 +525,6 @@ PrintMode mode = ValueOnlyMode; char fieldSeparator = ' '; -//PVStructure::shared_pointer pvRequest; - void usage (void) { fprintf (stderr, "\nUsage: pvput [options] ...\n\n" diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index ee9caf1..5b10d31 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -424,29 +424,41 @@ class MockChannelRPC : public ChannelRPC } else { - int i = 0; - int totalFields = 1 + atoi(columns->get().c_str()); // labels, - StringArray fieldNames(totalFields); - FieldConstPtrArray fields(totalFields); - fieldNames[i] = "labels"; - fields[i++] = getFieldCreate()->createScalarArray(pvString); + + int columnsCount = atoi(columns->get().c_str()); + StringArray fieldNames(columnsCount); + FieldConstPtrArray fields(columnsCount); char sbuf[16]; vector labels; - for (; i < totalFields; i++) + for (int i = 0; i < columnsCount; i++) { - sprintf(sbuf, "column%d", i-1 ); + sprintf(sbuf, "column%d", i); fieldNames[i] = sbuf; fields[i] = getFieldCreate()->createScalarArray(pvDouble); labels.push_back(sbuf); } + Structure::const_shared_pointer valueStructure( + getFieldCreate()->createStructure(fieldNames, fields) + ); + + StringArray tableFieldNames(2); + FieldConstPtrArray tableFields(2); + tableFieldNames[0] = "labels"; + tableFields[0] = getFieldCreate()->createScalarArray(pvString); + tableFieldNames[1] = "value"; + tableFields[1] = valueStructure; + PVStructure::shared_pointer result( getPVDataCreate()->createPVStructure( - getFieldCreate()->createStructure("uri:ev4:nt/2012/pwd:NTTable", fieldNames, fields) + getFieldCreate()->createStructure( + "uri:ev4:nt/2012/pwd:NTTable", tableFieldNames, tableFields) ) ); static_pointer_cast(result->getScalarArrayField("labels", pvString))->put(0, labels.size(), &labels[0], 0); + PVStructure::shared_pointer resultValue = result->getStructureField("value"); + srand ( time(NULL) ); #define ROWS 10 @@ -460,7 +472,7 @@ class MockChannelRPC : public ChannelRPC iter++) { FILL_VALUES; - static_pointer_cast(result->getScalarArrayField(*iter, pvDouble))->put(0, ROWS, values, 0); + static_pointer_cast(resultValue->getScalarArrayField(*iter, pvDouble))->put(0, ROWS, values, 0); } m_channelRPCRequester->requestDone(Status::Ok, result); }