diff --git a/testApp/remote/eget.cpp b/testApp/remote/eget.cpp index 0250d4d..31b6f75 100644 --- a/testApp/remote/eget.cpp +++ b/testApp/remote/eget.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -366,9 +367,55 @@ char *url_encode(char *str) { +void formatNTTable(StringBuilder buffer, PVStructure *pvStruct) +{ + PVStringArray* labels = static_cast(pvStruct->getScalarArrayField("labels", pvString)); + if (labels == 0) + return; // TODO + + int numColumns = labels->getLength(); + //int count = pvStruct->getNumberFields(); + // TODO if (count < #numColumns) + + // next numColumns fields are columns + int maxValues = 0; + vector columnData; + PVFieldPtrArray fields = pvStruct->getPVFields(); + for (int i = 0; i < numColumns; i++) + { + DoubleArrayData values; + // TODO we relay on field ordering here (normativeType, labels, ) + PVDoubleArray* arrayField = static_cast(fields[i+2]); + int count = arrayField->get(0, arrayField->getLength(), &values); + if (count > maxValues) maxValues = count; + columnData.push_back(values); + } + std::cout << std::left; -void toNTString(StringBuilder buffer,PVField * pv,int notFirst) + // first print labels + StringArrayData data; + labels->get(0, numColumns, &data); + for (int i = 0; i < numColumns; i++) + { + std::cout << std::setw(16) << data.data[i]; + } + std::cout << std::endl; + + // than values + // TODO all the same length!!! + for (int r = 0; r < maxValues; r++) + { + for (int i = 0; i < numColumns; i++) + { + std::cout << std::setw(16) << columnData[i].data[r]; + } + std::cout << std::endl; + } + +} + +void toNTString(StringBuilder buffer, PVField *pv,int notFirst) { Type type = pv->getField()->getType(); if(type==structure) @@ -382,8 +429,7 @@ void toNTString(StringBuilder buffer,PVField * pv,int notFirst) if (value == "NTTable") { - // TODO - pv->toString(buffer); + formatNTTable(buffer, pvStruct); } else { @@ -606,19 +652,19 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester // access smart pointers { Lock lock(m_pointerMutex); - { - // TODO format normative types - if (terseMode) - convertToString(&str, pvResponse.get(), 0); - else - pvResponse->toString(&str); - } + + // TODO + pvResponse->toString(&str, 0); + std::cout << std::endl; + std::cout << str << std::endl; + std::cout << std::endl; + + toNTString(&str, pvResponse.get(), 0); + // this is OK since calle holds also owns it m_channelRPC.reset(); } - std::cout << str << std::endl; - m_event.signal(); } @@ -913,11 +959,20 @@ int main (int argc, char *argv[]) if (channelRequesterImpl->waitUntilConnected(timeOut)) { - shared_ptr getRequesterImpl(new ChannelRPCRequesterImpl(channel->getChannelName())); - ChannelRPC::shared_pointer channelRPC = channel->createChannelRPC(getRequesterImpl, pvRequest); - - channelRPC->request(args, true); - allOK &= getRequesterImpl->waitUntilRPC(timeOut); + shared_ptr rpcRequesterImpl(new ChannelRPCRequesterImpl(channel->getChannelName())); + ChannelRPC::shared_pointer channelRPC = channel->createChannelRPC(rpcRequesterImpl, pvRequest); + + if (rpcRequesterImpl->waitUntilConnected(timeOut)) + { + channelRPC->request(args, true); + allOK &= rpcRequesterImpl->waitUntilRPC(timeOut); + } + else + { + allOK = false; + channel->destroy(); + std::cout << "[" << channel->getChannelName() << "] RPC create timeout" << std::endl; + } } else { diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp index 49e751b..18942b7 100644 --- a/testApp/remote/testServer.cpp +++ b/testApp/remote/testServer.cpp @@ -8,6 +8,9 @@ #include #include +#include +#include + using namespace epics::pvAccess; using namespace epics::pvData; using namespace std; @@ -370,19 +373,20 @@ class MockChannelRPC : public ChannelRPC { private: ChannelRPCRequester::shared_pointer m_channelRPCRequester; + String m_channelName; PVStructure::shared_pointer m_pvStructure; protected: - MockChannelRPC(ChannelRPCRequester::shared_pointer const & channelRPCRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) : - m_channelRPCRequester(channelRPCRequester), m_pvStructure(pvStructure) + MockChannelRPC(ChannelRPCRequester::shared_pointer const & channelRPCRequester, String const & channelName, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) : + m_channelRPCRequester(channelRPCRequester), m_channelName(channelName), m_pvStructure(pvStructure) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelRPC); } public: - static ChannelRPC::shared_pointer create(ChannelRPCRequester::shared_pointer const & channelRPCRequester, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) + static ChannelRPC::shared_pointer create(ChannelRPCRequester::shared_pointer const & channelRPCRequester, String const & channelName, PVStructure::shared_pointer const & pvStructure, PVStructure::shared_pointer const & pvRequest) { - ChannelRPC::shared_pointer thisPtr(new MockChannelRPC(channelRPCRequester, pvStructure, pvRequest)); + ChannelRPC::shared_pointer thisPtr(new MockChannelRPC(channelRPCRequester, channelName, pvStructure, pvRequest)); // TODO pvRequest channelRPCRequester->channelRPCConnect(Status::Ok, thisPtr); return thisPtr; @@ -395,10 +399,65 @@ class MockChannelRPC : public ChannelRPC virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument, bool lastRequest) { - std::string s; - pvArgument->toString(&s); - std::cout << "RPC" << std::endl << s << std::endl; - m_channelRPCRequester->requestDone(Status::Ok, m_pvStructure); + if (m_channelName == "rpcNTTable") + { + // TODO type check, getStringField is verbose + PVString* columns = static_cast(pvArgument->getSubField("columns")); + if (columns == 0) + { + PVStructure::shared_pointer nullPtr; + Status errorStatus(Status::STATUSTYPE_ERROR, "no columns specified"); + m_channelRPCRequester->requestDone(errorStatus, nullPtr); + } + else + { + int i = 0; + int totalFields = 1 + 1 + atoi(columns->get().c_str()); // normativeType, labels, + FieldConstPtrArray fields = new FieldConstPtr[totalFields]; + fields[i++] = getFieldCreate()->createScalar("normativeType", pvString); + fields[i++] = getFieldCreate()->createScalarArray("labels", pvString); + char sbuf[16]; + vector labels; + for (; i < totalFields; i++) + { + sprintf(sbuf, "column%d", i-1 ); + fields[i] = getFieldCreate()->createScalarArray(sbuf, pvDouble); + labels.push_back(sbuf); + } + + PVStructure::shared_pointer result( + new PVStructure(NULL, getFieldCreate()->createStructure("", totalFields, fields))); + + result->getStringField("normativeType")->put("NTTable"); + static_cast(result->getScalarArrayField("labels", pvString))->put(0, labels.size(), &labels[0], 0); + + srand ( time(NULL) ); + + #define ROWS 10 + double values[ROWS]; + #define FILL_VALUES \ + for (int r = 0; r < ROWS; r++) \ + values[r] = (rand()-RAND_MAX/2)/(double)(RAND_MAX/2); + + for (vector::iterator iter = labels.begin(); + iter != labels.end(); + iter++) + { + FILL_VALUES; + static_cast(result->getScalarArrayField(*iter, pvDouble))->put(0, ROWS, values, 0); + } + m_channelRPCRequester->requestDone(Status::Ok, result); + } + } + else + { + std::string s; + pvArgument->toString(&s); + std::cout << "RPC" << std::endl << s << std::endl; + + m_channelRPCRequester->requestDone(Status::Ok, m_pvStructure); + } + if (lastRequest) destroy(); } @@ -682,6 +741,10 @@ class MockChannel : public Channel { printf("=============------------------------------------!!!\n"); */ } + else if (m_name.find("rpc") == 0) + { + m_pvStructure.reset(getPVDataCreate()->createPVStructure(0, name, 0, static_cast(0))); + } else { String allProperties("alarm,timeStamp,display,control,valueAlarm"); @@ -816,7 +879,7 @@ class MockChannel : public Channel { virtual ChannelRPC::shared_pointer createChannelRPC(ChannelRPCRequester::shared_pointer const & channelRPCRequester, epics::pvData::PVStructure::shared_pointer const & pvRequest) { - return MockChannelRPC::create(channelRPCRequester, m_pvStructure, pvRequest); + return MockChannelRPC::create(channelRPCRequester, m_name, m_pvStructure, pvRequest); } virtual epics::pvData::Monitor::shared_pointer createMonitor(