bool ArchiveDataClient::getValues(int key, stdVector<stdString> &names, const epicsTime &start, const epicsTime &end, int count, int how, value_callback callback, void *callback_arg) { xmlrpc_value *name_array, *result, *element; size_t n; name_array = xmlrpc_build_value(&env, "()"); if (log_fault()) return false; for (n=0; n<names.size(); ++n) { element = xmlrpc_build_value(&env, "s", names[n].c_str()); if (log_fault()) return false; xmlrpc_array_append_item(&env, name_array, element); if (log_fault()) return false; xmlrpc_DECREF(element); } xmlrpc_int32 start_sec, start_nano, end_sec, end_nano; epicsTime2pieces(start, start_sec, start_nano); epicsTime2pieces(end, end_sec, end_nano); result = xmlrpc_client_call(&env, (char *)URL, "archiver.values", "(iViiiiii)", (xmlrpc_int32)key, name_array, start_sec, start_nano, end_sec, end_nano, (xmlrpc_int32)count, (xmlrpc_int32)how); if (log_fault()) return false; xmlrpc_DECREF(name_array); size_t channel_count = xmlrpc_array_size(&env, result); xmlrpc_value *channel_result; for (n=0; n<channel_count; ++n) { channel_result = xmlrpc_array_get_item(&env, result, n); if (log_fault()) return false; if (!decode_channel(channel_result, n, callback, callback_arg)) return false; } xmlrpc_DECREF(result); return true; }
// "visitor" for BinaryTree of channel names static void add_name_to_result(const ChannelInfo &info, void *arg) { UserArg *user_arg = (UserArg *)arg; xmlrpc_int32 ss, sn, es, en; epicsTime2pieces(info.start, ss, sn); epicsTime2pieces(info.end, es, en); LOG_MSG("Found name '%s'\n", info.name.c_str()); AutoXmlRpcValue channel(xmlrpc_build_value( user_arg->env, "{s:s,s:i,s:i,s:i,s:i}", "name", info.name.c_str(), "start_sec", ss, "start_nano", sn, "end_sec", es, "end_nano", en)); if (user_arg->env->fault_occurred) return; xmlrpc_array_append_item(user_arg->env, user_arg->result, channel); }
// Given a raw sample dbr_type/count/time/data, // map it onto xml_type/count and add to values. // Handles the special case data == 0, // which happens for undefined cells in a SpreadsheetReader. void encode_value(xmlrpc_env *env, DbrType dbr_type, DbrCount dbr_count, const epicsTime &time, const RawValue::Data *data, xmlrpc_int32 xml_type, xmlrpc_int32 xml_count, xmlrpc_value *values) { if (xml_count > dbr_count) xml_count = dbr_count; AutoXmlRpcValue val_array(xmlrpc_build_value(env, "()")); if (env->fault_occurred) return; int i; switch (xml_type) { case XML_STRING: { stdString txt; if (data) RawValue::getValueString(txt, dbr_type, dbr_count, data, 0); AutoXmlRpcValue element(xmlrpc_build_value(env, "s#", txt.c_str(), txt.length())); xmlrpc_array_append_item(env, val_array, element); } break; case XML_INT: case XML_ENUM: { long l; for (i=0; i < xml_count; ++i) { if (!data || !RawValue::getLong(dbr_type, dbr_count, data, l, i)) l = 0; AutoXmlRpcValue element(xmlrpc_build_value(env, "i", (xmlrpc_int32)l)); xmlrpc_array_append_item(env, val_array, element); } } break; case XML_DOUBLE: { double d; for (i=0; i < xml_count; ++i) { if (data && RawValue::getDouble(dbr_type, dbr_count, data, d, i)) { /* XML-RPC, being XML, sends all numbers as strings. * Unfortunately, XML-RPC also insists in the simple 'dot' * notation and prohibits exponential notation. * A number like 1e-300 would turn into * "0.0000000..." with 300 zeroes, * which is too long for the internal print buffer of * the xml-rpc C library. * Since such huge and tiny numbers can't be transferred, * they are replaced by 0 with stat/sevr UDF/INVALID. * * The cut-off point is somewhat arbitrary. * The XML-RPC library uses an internal print buffer * of about 120 characters. * Since PVs are usually scaled to be human-readable, * with only vacuum readings using exp. notation for * data like "1e-8 Torr", exponents of +-50 seemed * reasonable. */ if (d > 0.0) { if (d < 1e-50 || d > 1e50) { d = 0.0; data = 0; } } else if (d < 0.0) { if (d > -1e-50 || d < -1e50) { d = 0.0; data = 0; } } } else d = 0.0; AutoXmlRpcValue element(xmlrpc_build_value(env, "d", d)); xmlrpc_array_append_item(env, val_array, element); } } } xmlrpc_int32 secs, nano; epicsTime2pieces(time, secs, nano); AutoXmlRpcValue value; if (data) value.set(xmlrpc_build_value( env, "{s:i,s:i,s:i,s:i,s:V}", "stat", (xmlrpc_int32)RawValue::getStat(data), "sevr", (xmlrpc_int32)RawValue::getSevr(data), "secs", secs, "nano", nano, "value", (xmlrpc_value *)val_array)); else value.set(xmlrpc_build_value( env, "{s:i,s:i,s:i,s:i,s:V}", "stat", (xmlrpc_int32)UDF_ALARM, "sevr", (xmlrpc_int32)INVALID_ALARM, "secs", secs, "nano", nano, "value", (xmlrpc_value *)val_array)); xmlrpc_array_append_item(env, values, value); }