Exemplo n.º 1
0
wxString CFileDataIO::ReadOnlyString(bool bOptUTF8, uint16 raw_len) const
{
	// We only need to set the the NULL terminator, since we know that
	// reads will either succeed or throw an exception, in which case
	// we wont be returning anything
	std::vector<char> val_array(raw_len + 1);
	val_array[raw_len] = 0;
		
	char* val = &(val_array[0]);

	Read(val, raw_len);
	wxString str;
	
	if (CHECK_BOM(raw_len, val)) {
		// This is a UTF8 string with a BOM header, skip header.
		str = UTF82unicode(val + 3);
	} else if (bOptUTF8) {
		str = UTF82unicode(val);
		if (str.IsEmpty()) {
			// Fallback to Latin-1
			str = wxString(val, wxConvISO8859_1, raw_len);
		}
	} else {
		// Raw strings are written as Latin-1 (see CFileDataIO::WriteStringCore)
		str = wxString(val, wxConvISO8859_1, raw_len);
	}

	return str;
}
Exemplo n.º 2
0
// 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);
}
Exemplo n.º 3
0
/**
 * Creates a time series property from the currently opened log entry. It is
 * assumed to
 * have been checked to have a time field and the value entry's name is given as
 * an argument
 * @param file :: A reference to the file handle
 * @param prop_name :: The name of the property
 * @returns A pointer to a new property containing the time series
 */
Kernel::Property *
LoadNexusLogs::createTimeSeries(::NeXus::File &file,
                                const std::string &prop_name) const {
  file.openData("time");
  //----- Start time is an ISO8601 string date and time. ------
  std::string start;
  try {
    file.getAttr("start", start);
  } catch (::NeXus::Exception &) {
    // Some logs have "offset" instead of start
    try {
      file.getAttr("offset", start);
    } catch (::NeXus::Exception &) {
      g_log.warning() << "Log entry has no start time indicated.\n";
      file.closeData();
      throw;
    }
  }
  if (start.compare("No Time") == 0) {
    start = freqStart;
  }

  // Convert to date and time
  Kernel::DateAndTime start_time = Kernel::DateAndTime(start);
  std::string time_units;
  file.getAttr("units", time_units);
  if (time_units.compare("second") < 0 && time_units != "s" &&
      time_units != "minutes") // Can be s/second/seconds/minutes
  {
    file.closeData();
    throw ::NeXus::Exception("Unsupported time unit '" + time_units + "'");
  }
  //--- Load the seconds into a double array ---
  std::vector<double> time_double;
  try {
    file.getDataCoerce(time_double);
  } catch (::NeXus::Exception &e) {
    g_log.warning() << "Log entry's time field could not be loaded: '"
                    << e.what() << "'.\n";
    file.closeData();
    throw;
  }
  file.closeData(); // Close time data
  g_log.debug() << "   done reading \"time\" array\n";

  // Convert to seconds if needed
  if (time_units == "minutes") {
    std::transform(time_double.begin(), time_double.end(), time_double.begin(),
                   std::bind2nd(std::multiplies<double>(), 60.0));
  }
  // Now the values: Could be a string, int or double
  file.openData("value");
  // Get the units of the property
  std::string value_units("");
  try {
    file.getAttr("units", value_units);
  } catch (::NeXus::Exception &) {
    // Ignore missing units field.
    value_units = "";
  }

  // Now the actual data
  ::NeXus::Info info = file.getInfo();
  // Check the size
  if (size_t(info.dims[0]) != time_double.size()) {
    file.closeData();
    throw ::NeXus::Exception("Invalid value entry for time series");
  }
  if (file.isDataInt()) // Int type
  {
    std::vector<int> values;
    try {
      file.getDataCoerce(values);
      file.closeData();
    } catch (::NeXus::Exception &) {
      file.closeData();
      throw;
    }
    // Make an int TSP
    auto tsp = new TimeSeriesProperty<int>(prop_name);
    tsp->create(start_time, time_double, values);
    tsp->setUnits(value_units);
    g_log.debug() << "   done reading \"value\" array\n";
    return tsp;
  } else if (info.type == ::NeXus::CHAR) {
    std::string values;
    const int64_t item_length = info.dims[1];
    try {
      const int64_t nitems = info.dims[0];
      const int64_t total_length = nitems * item_length;
      boost::scoped_array<char> val_array(new char[total_length]);
      file.getData(val_array.get());
      file.closeData();
      values = std::string(val_array.get(), total_length);
    } catch (::NeXus::Exception &) {
      file.closeData();
      throw;
    }
    // The string may contain non-printable (i.e. control) characters, replace
    // these
    std::replace_if(values.begin(), values.end(), iscntrl, ' ');
    auto tsp = new TimeSeriesProperty<std::string>(prop_name);
    std::vector<DateAndTime> times;
    DateAndTime::createVector(start_time, time_double, times);
    const size_t ntimes = times.size();
    for (size_t i = 0; i < ntimes; ++i) {
      std::string value_i =
          std::string(values.data() + i * item_length, item_length);
      tsp->addValue(times[i], value_i);
    }
    tsp->setUnits(value_units);
    g_log.debug() << "   done reading \"value\" array\n";
    return tsp;
  } else if (info.type == ::NeXus::FLOAT32 || info.type == ::NeXus::FLOAT64) {
    std::vector<double> values;
    try {
      file.getDataCoerce(values);
      file.closeData();
    } catch (::NeXus::Exception &) {
      file.closeData();
      throw;
    }
    auto tsp = new TimeSeriesProperty<double>(prop_name);
    tsp->create(start_time, time_double, values);
    tsp->setUnits(value_units);
    g_log.debug() << "   done reading \"value\" array\n";
    return tsp;
  } else {
    throw ::NeXus::Exception(
        "Invalid value type for time series. Only int, double or strings are "
        "supported");
  }
}