<commit_before>// $Id: ExportInterface.cpp 3045 2010-04-05 13:07:29Z hieuhoang1972 $

/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2009 University of Edinburgh

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/

/**
 * Moses interface for main function, for single-threaded and multi-threaded.
 **/
#include <exception>
#include <fstream>
#include <sstream>
#include <vector>

#include "util/random.hh"
#include "util/usage.hh"

#ifdef WIN32
// Include Visual Leak Detector
//#include <vld.h>
#endif

#include "Hypothesis.h"
#include "Manager.h"
#include "StaticData.h"
#include "TypeDef.h"
#include "Util.h"
#include "Timer.h"
#include "TranslationModel/PhraseDictionary.h"
#include "FF/StatefulFeatureFunction.h"
#include "FF/StatelessFeatureFunction.h"
#include "TranslationTask.h"
#include "ExportInterface.h"

#ifdef HAVE_PROTOBUF
#include "hypergraph.pb.h"
#endif

#ifdef PT_UG
#include <boost/foreach.hpp>
#include "TranslationModel/UG/mmsapt.h"
#include "TranslationModel/UG/generic/program_options/ug_splice_arglist.h"
#endif

#include "ExportInterface.h"
#ifdef HAVE_XMLRPC_C
#include <xmlrpc-c/base.hpp>
#include <xmlrpc-c/registry.hpp>
#include <xmlrpc-c/server_abyss.hpp>
#include "server/Translator.h"
#include "server/Optimizer.h"
#include "server/Updater.h"
#endif

using namespace std;
using namespace Moses;

namespace Moses
{
void OutputFeatureWeightsForHypergraph(std::ostream &outputSearchGraphStream)
{
  outputSearchGraphStream.setf(std::ios::fixed);
  outputSearchGraphStream.precision(6);
  StaticData::Instance().GetAllWeights().Save(outputSearchGraphStream);
}
} //namespace Moses

SimpleTranslationInterface::SimpleTranslationInterface(const string &mosesIni): m_staticData(StaticData::Instance())
{
    if (!m_params.LoadParam(mosesIni)) {
      cerr << "Error; Cannot load parameters at " << mosesIni<<endl;
      exit(1);
    }
    if (!StaticData::LoadDataStatic(&m_params, mosesIni.c_str())) {
      cerr << "Error; Cannot load static data in file " << mosesIni<<endl;
      exit(1);
    }

    util::rand_init();

}

SimpleTranslationInterface::~SimpleTranslationInterface()
{}

//the simplified version of string input/output translation
string SimpleTranslationInterface::translate(const string &inputString)
{
  boost::shared_ptr<Moses::IOWrapper> ioWrapper(new IOWrapper);
  // main loop over set of input sentences
  size_t sentEnd = inputString.rfind('\n'); //find the last \n, the input stream has to be appended with \n to be translated
  const string &newString = sentEnd != string::npos ? inputString : inputString + '\n';

  istringstream inputStream(newString);  //create the stream for the interface
  ioWrapper->SetInputStreamFromString(inputStream);
  ostringstream outputStream;
  ioWrapper->SetOutputStream2SingleBestOutputCollector(&outputStream);

  boost::shared_ptr<InputType> source = ioWrapper->ReadInput();
  if (!source) return "Error: Source==null!!!";
  IFVERBOSE(1) { ResetUserTime(); }

  FeatureFunction::CallChangeSource(&*source);

  // set up task of translating one sentence
  boost::shared_ptr<TranslationTask> task
    = TranslationTask::create(source, ioWrapper);
  task->Run();

  string output = outputStream.str();
  //now trim the end whitespace
  const string whitespace = " \t\f\v\n\r";
  size_t end = output.find_last_not_of(whitespace);
  return output.erase(end + 1);
}

Moses::StaticData& SimpleTranslationInterface::getStaticData()
{
  return StaticData::InstanceNonConst();
}
void SimpleTranslationInterface::DestroyFeatureFunctionStatic()
{
  FeatureFunction::Destroy();
}

Parameter params;

//! run moses in server mode
int
run_as_server()
{
#ifdef HAVE_XMLRPC_C
  int port; params.SetParameter(port, "server-port", 8080);
  bool isSerial; params.SetParameter(isSerial, "serial", false);
  string logfile; params.SetParameter(logfile, "server-log", string(""));
  size_t num_threads; params.SetParameter(num_threads, "threads", size_t(10));
  if (isSerial) VERBOSE(1,"Running server in serial mode." << endl);

  xmlrpc_c::registry myRegistry;

  xmlrpc_c::methodPtr const translator(new MosesServer::Translator(num_threads));
  xmlrpc_c::methodPtr const updater(new MosesServer::Updater);
  xmlrpc_c::methodPtr const optimizer(new MosesServer::Optimizer);

  myRegistry.addMethod("translate", translator);
  myRegistry.addMethod("updater", updater);
  myRegistry.addMethod("optimize", optimizer);

  xmlrpc_c::serverAbyss myAbyssServer(myRegistry, port, logfile);

  XVERBOSE(1,"Listening on port " << port << endl);
  if (isSerial) { while(1) myAbyssServer.runOnce(); }
  else myAbyssServer.run();

  std::cerr << "xmlrpc_c::serverAbyss.run() returned but should not." << std::endl;
  // #pragma message("BUILDING MOSES WITH SERVER SUPPORT")
#else
  // #pragma message("BUILDING MOSES WITHOUT SERVER SUPPORT")
  std::cerr << "Moses was compiled without server support." << endl;
#endif
  return 1;

}

int
batch_run()
{
  // shorthand for accessing information in StaticData
  const StaticData& staticData = StaticData::Instance();

  //initialise random numbers
  util::rand_init();

  IFVERBOSE(1) PrintUserTime("Created input-output object");

  // set up read/writing class:
  boost::shared_ptr<IOWrapper> ioWrapper(new IOWrapper);
  UTIL_THROW_IF2(ioWrapper == NULL, "Error; Failed to create IO object"
		 << " [" << HERE << "]");

  // check on weights
  const ScoreComponentCollection& weights = staticData.GetAllWeights();
  IFVERBOSE(2)
    {
      TRACE_ERR("The global weight vector looks like this: ");
      TRACE_ERR(weights);
      TRACE_ERR("\n");
    }

#ifdef WITH_THREADS
  ThreadPool pool(staticData.ThreadCount());
#endif

  std::string context_string;
  params.SetParameter(context_string,"context-string",string(""));

  // main loop over set of input sentences

  boost::shared_ptr<InputType> source;
  while ((source = ioWrapper->ReadInput()) != NULL)
    {
      IFVERBOSE(1) ResetUserTime();

      FeatureFunction::CallChangeSource(source.get());

      // set up task of translating one sentence
      boost::shared_ptr<TranslationTask>
	task = TranslationTask::create(source, ioWrapper);
      task->SetContextString(context_string);

      // Allow for (sentence-)context-specific processing prior to
      // decoding. This can be used, for example, for context-sensitive
      // phrase lookup.
      FeatureFunction::SetupAll(*task);

      // execute task
#ifdef WITH_THREADS
#ifdef PT_UG
      // simulated post-editing requires threads (within the dynamic phrase tables)
      // but runs all sentences serially, to allow updating of the bitext.
      bool spe = params.isParamSpecified("spe-src");
      if (spe)
	{
	  // simulated post-editing: always run single-threaded!
	  task->Run();
	  string src,trg,aln;
	  UTIL_THROW_IF2(!getline(*ioWrapper->spe_src,src), "[" << HERE << "] "
			 << "missing update data for simulated post-editing.");
	  UTIL_THROW_IF2(!getline(*ioWrapper->spe_trg,trg), "[" << HERE << "] "
			 << "missing update data for simulated post-editing.");
	  UTIL_THROW_IF2(!getline(*ioWrapper->spe_aln,aln), "[" << HERE << "] "
			 << "missing update data for simulated post-editing.");
	  BOOST_FOREACH (PhraseDictionary* pd, PhraseDictionary::GetColl())
	    {
	      Mmsapt* sapt = dynamic_cast<Mmsapt*>(pd);
	      if (sapt) sapt->add(src,trg,aln);
	      VERBOSE(1,"[" << HERE << " added src] " << src << endl);
	      VERBOSE(1,"[" << HERE << " added trg] " << trg << endl);
	      VERBOSE(1,"[" << HERE << " added aln] " << aln << endl);
	    }
	}
      else pool.Submit(task);
#else
      pool.Submit(task);

#endif
#else
      task->Run();
#endif
    }

  // we are done, finishing up
#ifdef WITH_THREADS
  pool.Stop(true); //flush remaining jobs
#endif

  FeatureFunction::Destroy();

  IFVERBOSE(1) util::PrintUsage(std::cerr);

#ifndef EXIT_RETURN
  //This avoids that destructors are called (it can take a long time)
  exit(EXIT_SUCCESS);
#else
  return EXIT_SUCCESS;
#endif
}

/** Called by main function of the command line version of the decoder **/
int decoder_main(int argc, char** argv)
{
  try
    {

#ifdef HAVE_PROTOBUF
      GOOGLE_PROTOBUF_VERIFY_VERSION;
#endif

      // echo command line, if verbose
      IFVERBOSE(1)
	{
	  TRACE_ERR("command: ");
	  for(int i=0; i<argc; ++i) TRACE_ERR(argv[i]<<" ");
	  TRACE_ERR(endl);
	}

      // set number of significant decimals in output
      FixPrecision(cout);
      FixPrecision(cerr);

      // load all the settings into the Parameter class
      // (stores them as strings, or array of strings)
      if (!params.LoadParam(argc,argv))
	exit(1);

      // initialize all "global" variables, which are stored in StaticData
      // note: this also loads models such as the language model, etc.
      if (!StaticData::LoadDataStatic(&params, argv[0]))
	exit(1);

      // setting "-show-weights" -> just dump out weights and exit
      if (params.isParamSpecified("show-weights"))
	{
	  ShowWeights();
	  exit(0);
	}

      if (params.GetParam("server"))
	return run_as_server();
      else
	return batch_run();

    }
  catch (const std::exception &e)
    {
      std::cerr << "Exception: " << e.what() << std::endl;
      return EXIT_FAILURE;
    }
}

<commit_msg>No try { ... } catch { ... } in debug mode.<commit_after>// $Id: ExportInterface.cpp 3045 2010-04-05 13:07:29Z hieuhoang1972 $

/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2009 University of Edinburgh

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/

/**
 * Moses interface for main function, for single-threaded and multi-threaded.
 **/
#include <exception>
#include <fstream>
#include <sstream>
#include <vector>

#include "util/random.hh"
#include "util/usage.hh"

#ifdef WIN32
// Include Visual Leak Detector
//#include <vld.h>
#endif

#include "Hypothesis.h"
#include "Manager.h"
#include "StaticData.h"
#include "TypeDef.h"
#include "Util.h"
#include "Timer.h"
#include "TranslationModel/PhraseDictionary.h"
#include "FF/StatefulFeatureFunction.h"
#include "FF/StatelessFeatureFunction.h"
#include "TranslationTask.h"
#include "ExportInterface.h"

#ifdef HAVE_PROTOBUF
#include "hypergraph.pb.h"
#endif

#ifdef PT_UG
#include <boost/foreach.hpp>
#include "TranslationModel/UG/mmsapt.h"
#include "TranslationModel/UG/generic/program_options/ug_splice_arglist.h"
#endif

#include "ExportInterface.h"
#ifdef HAVE_XMLRPC_C
#include <xmlrpc-c/base.hpp>
#include <xmlrpc-c/registry.hpp>
#include <xmlrpc-c/server_abyss.hpp>
#include "server/Translator.h"
#include "server/Optimizer.h"
#include "server/Updater.h"
#endif

using namespace std;
using namespace Moses;

namespace Moses
{
void OutputFeatureWeightsForHypergraph(std::ostream &outputSearchGraphStream)
{
  outputSearchGraphStream.setf(std::ios::fixed);
  outputSearchGraphStream.precision(6);
  StaticData::Instance().GetAllWeights().Save(outputSearchGraphStream);
}
} //namespace Moses

SimpleTranslationInterface::SimpleTranslationInterface(const string &mosesIni): m_staticData(StaticData::Instance())
{
    if (!m_params.LoadParam(mosesIni)) {
      cerr << "Error; Cannot load parameters at " << mosesIni<<endl;
      exit(1);
    }
    if (!StaticData::LoadDataStatic(&m_params, mosesIni.c_str())) {
      cerr << "Error; Cannot load static data in file " << mosesIni<<endl;
      exit(1);
    }

    util::rand_init();

}

SimpleTranslationInterface::~SimpleTranslationInterface()
{}

//the simplified version of string input/output translation
string SimpleTranslationInterface::translate(const string &inputString)
{
  boost::shared_ptr<Moses::IOWrapper> ioWrapper(new IOWrapper);
  // main loop over set of input sentences
  size_t sentEnd = inputString.rfind('\n'); //find the last \n, the input stream has to be appended with \n to be translated
  const string &newString = sentEnd != string::npos ? inputString : inputString + '\n';

  istringstream inputStream(newString);  //create the stream for the interface
  ioWrapper->SetInputStreamFromString(inputStream);
  ostringstream outputStream;
  ioWrapper->SetOutputStream2SingleBestOutputCollector(&outputStream);

  boost::shared_ptr<InputType> source = ioWrapper->ReadInput();
  if (!source) return "Error: Source==null!!!";
  IFVERBOSE(1) { ResetUserTime(); }

  FeatureFunction::CallChangeSource(&*source);

  // set up task of translating one sentence
  boost::shared_ptr<TranslationTask> task
    = TranslationTask::create(source, ioWrapper);
  task->Run();

  string output = outputStream.str();
  //now trim the end whitespace
  const string whitespace = " \t\f\v\n\r";
  size_t end = output.find_last_not_of(whitespace);
  return output.erase(end + 1);
}

Moses::StaticData& SimpleTranslationInterface::getStaticData()
{
  return StaticData::InstanceNonConst();
}
void SimpleTranslationInterface::DestroyFeatureFunctionStatic()
{
  FeatureFunction::Destroy();
}

Parameter params;

//! run moses in server mode
int
run_as_server()
{
#ifdef HAVE_XMLRPC_C
  int port; params.SetParameter(port, "server-port", 8080);
  bool isSerial; params.SetParameter(isSerial, "serial", false);
  string logfile; params.SetParameter(logfile, "server-log", string(""));
  size_t num_threads; params.SetParameter(num_threads, "threads", size_t(10));
  if (isSerial) VERBOSE(1,"Running server in serial mode." << endl);

  xmlrpc_c::registry myRegistry;

  xmlrpc_c::methodPtr const translator(new MosesServer::Translator(num_threads));
  xmlrpc_c::methodPtr const updater(new MosesServer::Updater);
  xmlrpc_c::methodPtr const optimizer(new MosesServer::Optimizer);

  myRegistry.addMethod("translate", translator);
  myRegistry.addMethod("updater", updater);
  myRegistry.addMethod("optimize", optimizer);

  xmlrpc_c::serverAbyss myAbyssServer(myRegistry, port, logfile);

  XVERBOSE(1,"Listening on port " << port << endl);
  if (isSerial) { while(1) myAbyssServer.runOnce(); }
  else myAbyssServer.run();

  std::cerr << "xmlrpc_c::serverAbyss.run() returned but should not." << std::endl;
  // #pragma message("BUILDING MOSES WITH SERVER SUPPORT")
#else
  // #pragma message("BUILDING MOSES WITHOUT SERVER SUPPORT")
  std::cerr << "Moses was compiled without server support." << endl;
#endif
  return 1;

}

int
batch_run()
{
  // shorthand for accessing information in StaticData
  const StaticData& staticData = StaticData::Instance();

  //initialise random numbers
  util::rand_init();

  IFVERBOSE(1) PrintUserTime("Created input-output object");

  // set up read/writing class:
  boost::shared_ptr<IOWrapper> ioWrapper(new IOWrapper);
  UTIL_THROW_IF2(ioWrapper == NULL, "Error; Failed to create IO object"
		 << " [" << HERE << "]");

  // check on weights
  const ScoreComponentCollection& weights = staticData.GetAllWeights();
  IFVERBOSE(2)
    {
      TRACE_ERR("The global weight vector looks like this: ");
      TRACE_ERR(weights);
      TRACE_ERR("\n");
    }

#ifdef WITH_THREADS
  ThreadPool pool(staticData.ThreadCount());
#endif

  std::string context_string;
  params.SetParameter(context_string,"context-string",string(""));

  // main loop over set of input sentences

  boost::shared_ptr<InputType> source;
  while ((source = ioWrapper->ReadInput()) != NULL)
    {
      IFVERBOSE(1) ResetUserTime();

      FeatureFunction::CallChangeSource(source.get());

      // set up task of translating one sentence
      boost::shared_ptr<TranslationTask>
	task = TranslationTask::create(source, ioWrapper);
      task->SetContextString(context_string);

      // Allow for (sentence-)context-specific processing prior to
      // decoding. This can be used, for example, for context-sensitive
      // phrase lookup.
      FeatureFunction::SetupAll(*task);

      // execute task
#ifdef WITH_THREADS
#ifdef PT_UG
      // simulated post-editing requires threads (within the dynamic phrase tables)
      // but runs all sentences serially, to allow updating of the bitext.
      bool spe = params.isParamSpecified("spe-src");
      if (spe)
	{
	  // simulated post-editing: always run single-threaded!
	  task->Run();
	  string src,trg,aln;
	  UTIL_THROW_IF2(!getline(*ioWrapper->spe_src,src), "[" << HERE << "] "
			 << "missing update data for simulated post-editing.");
	  UTIL_THROW_IF2(!getline(*ioWrapper->spe_trg,trg), "[" << HERE << "] "
			 << "missing update data for simulated post-editing.");
	  UTIL_THROW_IF2(!getline(*ioWrapper->spe_aln,aln), "[" << HERE << "] "
			 << "missing update data for simulated post-editing.");
	  BOOST_FOREACH (PhraseDictionary* pd, PhraseDictionary::GetColl())
	    {
	      Mmsapt* sapt = dynamic_cast<Mmsapt*>(pd);
	      if (sapt) sapt->add(src,trg,aln);
	      VERBOSE(1,"[" << HERE << " added src] " << src << endl);
	      VERBOSE(1,"[" << HERE << " added trg] " << trg << endl);
	      VERBOSE(1,"[" << HERE << " added aln] " << aln << endl);
	    }
	}
      else pool.Submit(task);
#else
      pool.Submit(task);

#endif
#else
      task->Run();
#endif
    }

  // we are done, finishing up
#ifdef WITH_THREADS
  pool.Stop(true); //flush remaining jobs
#endif

  FeatureFunction::Destroy();

  IFVERBOSE(1) util::PrintUsage(std::cerr);

#ifndef EXIT_RETURN
  //This avoids that destructors are called (it can take a long time)
  exit(EXIT_SUCCESS);
#else
  return EXIT_SUCCESS;
#endif
}

/** Called by main function of the command line version of the decoder **/
int decoder_main(int argc, char** argv)
{
#ifdef NDEBUG
  try
#endif
    {
#ifdef HAVE_PROTOBUF
      GOOGLE_PROTOBUF_VERIFY_VERSION;
#endif

      // echo command line, if verbose
      IFVERBOSE(1)
	{
	  TRACE_ERR("command: ");
	  for(int i=0; i<argc; ++i) TRACE_ERR(argv[i]<<" ");
	  TRACE_ERR(endl);
	}

      // set number of significant decimals in output
      FixPrecision(cout);
      FixPrecision(cerr);

      // load all the settings into the Parameter class
      // (stores them as strings, or array of strings)
      if (!params.LoadParam(argc,argv))
	exit(1);

      // initialize all "global" variables, which are stored in StaticData
      // note: this also loads models such as the language model, etc.
      if (!StaticData::LoadDataStatic(&params, argv[0]))
	exit(1);

      // setting "-show-weights" -> just dump out weights and exit
      if (params.isParamSpecified("show-weights"))
	{
	  ShowWeights();
	  exit(0);
	}

      if (params.GetParam("server"))
	return run_as_server();
      else
	return batch_run();

    }
#ifdef NDEBUG
  catch (const std::exception &e)
    {
      std::cerr << "Exception: " << e.what() << std::endl;
      return EXIT_FAILURE;
    }
#endif
}

<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2014, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file TivaDev.hxx
 * This file implements the device class prototypes for TivaWare.
 *
 * @author Stuart W. Baker
 * @date 6 May 2014
 */

#ifndef _FREERTOS_DRIVERS_TI_TIVADEV_HXX_
#define _FREERTOS_DRIVERS_TI_TIVADEV_HXX_

#ifndef gcc
#define gcc
#endif

#include <cstdint>

#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"
#include "usblib/usblib.h"
#include "usblib/usbcdc.h"
#include "usblib/usb-ids.h"
#include "usblib/device/usbdevice.h"
#include "usblib/device/usbdcdc.h"

#include "Serial.hxx"
#include "Can.hxx"

/* This is fixed and equals the USB packet size that the CDC device will
 * advertise to be able to receive. This is a performance parameter, 64 is the
 * largest packet size permitted by USB for virtual serial ports. */
#define USB_CDC_TX_DATA_SIZE 64
#define USB_CDC_RX_DATA_SIZE 64

/** Private data for this implementation of serial.
 */
class TivaCdc : public Serial
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param interrupt interrupt number used by the device
     */
    TivaCdc(const char *name, uint32_t interrupt);

    /** Destructor.
     */
    ~TivaCdc()
    {
    }

    /** @todo (Stuart Baker) this should be made private */
    /** handle an interrupt.
     */
    void interrupt_handler();

private:
    void enable(); /**< function to enable device */
    void disable(); /**< function to disable device */
    void tx_char(); /**< function to try and transmit a character */

    static unsigned long control_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data);

    static unsigned long rx_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data);

    static unsigned long tx_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data);

    tUSBDCDCDevice usbdcdcDevice; /**< CDC serial device instance */
    /** buffer for pending tx data */
    unsigned char txData[USB_CDC_TX_DATA_SIZE];
    /** buffer for pending rx data */
    unsigned char rxData[USB_CDC_RX_DATA_SIZE];
    uint32_t interrupt; /**< interrupt number for device */
    bool connected; /**< connection status */
    bool enabled; /**< enabled status */
    int woken; /**< task woken metadata for ISR */

    /** Default constructor.
     */
    TivaCdc();

    DISALLOW_COPY_AND_ASSIGN(TivaCdc);
};

/** Specialization of Serial driver for Tiva UART.
 */
class TivaUart : public Serial
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param base base address of this device
     * @param interrupt interrupt number of this device
     */
    TivaUart(const char *name, unsigned long base, uint32_t interrupt);

    /** Destructor.
     */
    ~TivaUart()
    {
    }

    /** @todo (Stuart Baker) this should be made private */
    /** handle an interrupt.
     */
    void interrupt_handler();

private:
    void enable(); /**< function to enable device */
    void disable(); /**< function to disable device */
    void tx_char(); /**< function to try and transmit a character */

    unsigned long base; /**< base address of this device */
    unsigned long interrupt; /**< interrupt of this device */
    bool txPending; /**< transmission currently pending */

    /** Default constructor.
     */
    TivaUart();

    DISALLOW_COPY_AND_ASSIGN(TivaUart);
};

/** Specialization of CAN driver for Tiva CAN.
 */
class TivaCan : public Can
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param base base address of this device
     * @param interrupt interrupt number of this device
     */
    TivaCan(const char *name, unsigned long base, uint32_t interrupt);

    /** Destructor.
     */
    ~TivaCan()
    {
    }

    /** @todo (Stuart Baker) this should be made private */
    /** handle an interrupt.
     */
    void interrupt_handler();

private:
    void enable(); /**< function to enable device */
    void disable(); /**< function to disable device */
    void tx_msg(); /**< function to try and transmit a message */

    unsigned long base; /**< base address of this device */
    unsigned long interrupt; /**< interrupt of this device */
    uint8_t data[8]; /**< transmit data */
    bool txPending; /**< transmission currently pending */

    /** Default constructor.
     */
    TivaCan();

    DISALLOW_COPY_AND_ASSIGN(TivaCan);
};

/** A device driver for sending DCC packets.  If the packet queue is empty,
 *  then the device driver automatically sends out idle DCC packets.  The
 *  device driver uses two instances of the 16/32-bit timer pairs.  The user
 *  is responsible for providing interrupt entry point for the interval timer
 *  and calling the inline method @ref interrupt_handler on behalf of this
 *  device driver.
 *
 *  Write calls work by sending the whole DCC packet excluding the X-OR linkage
 *  byte (which will be calculated automatically by the driver).  Only one DCC
 *  packet may be written per call to the write method.  If there is no space
 *  currently available in the write queue, the write method will return -1
 *  with errno set to ENOSPC.
 *
 *  Handling of write throttling:
 *
 *  The driver uses a second interrupt, used as a software interrupt at the
 *  FreeRTOS priority level, to communicate back information on when the device
 *  is writable. It is okay to use the interrupt for the second timer for this
 *  purpose. This interrupt will be enabled in the IOCTL after the
 *  writenotifiable is set, disabled in the interrupt itself when the
 *  writenotifiable is cleared. It is set pending at startup and when the dcc
 *  interrupt frees up a packet from the queue, and it is cleared pending when
 *  a write realizes there is no space for a buffer.
 */
class TivaDCC : public Node
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param ccp_base base address of a capture compare pwm timer pair
     * @param interval_base base address of an interval timer
     * @param interrupt interrupt number of interval timer
     * @param os_interrupt an otherwise unused interrupt number (cound be that of the capture compare pwm timer)
     * @param preamble_count number of preamble bits to send exclusive of
     *        end of packet '1' bit
     * @param one_bit_period number of system clock cycles for a one bit
     * @param zero_bit_period number of system clock cycles for a one bit
     * @param startup_delay offset for introducing some deadband at startup
     * @param deadband_adjust ajustment factor for adding deadband
     * @param railcom_cuttout true to produce the RailCom cuttout, else false
     */
    TivaDCC(const char *name,
            unsigned long ccp_base,
            unsigned long interval_base,
            uint32_t interrupt,
            uint32_t os_interrupt,
            int preamble_count,
            int one_bit_period,
            int zero_bit_period,
            int startup_delay,
            int deadband_adjust,
            bool railcom_cuttout = false);

    /** Destructor.
     */
    ~TivaDCC()
    {
    }

    /** Handle an interrupt.
     */
    inline void interrupt_handler();

    /** Handles a software interrupt to FreeRTOS. This should be called on the
     * interrupt number that is submitted as os_interrupt to the
     * constructor. */
    inline void os_interrupt_handler();

private:
    /** Read from a file or device.
     * @param file file reference for this device
     * @param buf location to place read data
     * @param count number of bytes to read
     * @return number of bytes read upon success, -1 upon failure with errno containing the cause
     */
    ssize_t read(File *file, void *buf, size_t count) OVERRIDE;

    /** Write to a file or device.
     * @param file file reference for this device
     * @param buf location to find write data
     * @param count number of bytes to write
     * @return number of bytes written upon success, -1 upon failure with errno containing the cause
     */
    ssize_t write(File *file, const void *buf, size_t count) OVERRIDE;

    /** Request an ioctl transaction
     * @param file file reference for this device
     * @param node node reference for this device
     * @param key ioctl key
     * @param data key data
     */
    int ioctl(File *file, unsigned long int key, unsigned long data) OVERRIDE;

    void enable(){} /**< function to enable device */
    void disable(){} /**< function to disable device */

    /** Discards all pending buffers.  Called after disable().
     */
    void flush_buffers(){};

    /** number of outgoing messages we can queue */
    static const size_t Q_SIZE = 4;

    /** maximum packet size we can support */
    static const size_t MAX_PKT_SIZE = 6;

    /** Queue structure for holding outgoing DCC packets.
     */
    struct Q
    {
        size_t count; /**< number of items in the queue */
        size_t rdIndex; /**< current read index */
        size_t wrIndex; /**< current write index */
        uint8_t data[Q_SIZE][MAX_PKT_SIZE + 1]; /**< queue data */
    };

    unsigned long ccpBase; /**< capture compare pwm base address */
    unsigned long intervalBase; /**< interval timer base address */
    uint32_t interrupt; /**< interrupt number of interval timer */
    int preambleCount; /**< number of preamble bits to send */
    int oneBitPeriod; /**< period of one bit */
    int zeroBitPeriod; /**< period of zero bit */
    int startupDelay; /**< startup offset */
    int deadbandAdjust; /**< deadband adjustment */
    bool railcomCuttout; /**< true if we should produce the RailCom cuttout */
    uint32_t osInterrupt; /**< interrupt used to notify FreeRTOS. */
    Notifiable* writableNotifiable; /**< Notify this when we have free buffers. */

    /** idle packet */
    static const uint8_t IDLE_PKT[3];

    Q q; /**< DCC packet queue */

    /** Default constructor.
     */
    TivaDCC();

    DISALLOW_COPY_AND_ASSIGN(TivaDCC);
};

__attribute__((optimize("-O3")))
inline void TivaDCC::os_interrupt_handler()
{
    HASSERT(writableNotifiable);
    Notifiable* n = writableNotifiable;
    writableNotifiable = nullptr;
    MAP_IntDisable(osInterrupt);
    n->notify_from_isr();
}

/** Handle an interrupt.
 */
__attribute__((optimize("-O3")))
inline void TivaDCC::interrupt_handler()
{
    enum State
    {
        PREAMBLE,
        START,
        DATA_0,
        DATA_1,
        DATA_2,
        DATA_3,
        DATA_4,
        DATA_5,
        DATA_6,
        DATA_7,
        FRAME,
    };

    static State state = PREAMBLE;
    static int preamble_count = 0;
    static int last_bit = 1;
    static int count = 0;
    static uint8_t xor_byte;
    static const uint8_t *packet = IDLE_PKT;
    int current_bit;

    MAP_TimerIntClear(intervalBase, TIMER_TIMA_TIMEOUT);

    switch (state)
    {
        default:
        case PREAMBLE:
            current_bit = 1;
            if (++preamble_count == preambleCount)
            {
                state = START;
                preamble_count = 0;
            }
            break;
        case START:
            current_bit = 0;
            count = 0;
            xor_byte = 0;
            state = DATA_0;
            break;
        case DATA_0:
        case DATA_1:
        case DATA_2:
        case DATA_3:
        case DATA_4:
        case DATA_5:
        case DATA_6:
        case DATA_7:
            if (count < packet[0])
            {
                current_bit = (packet[count + 1] >> (state - DATA_0)) & 0x01;
            }
            else
            {
                current_bit = (xor_byte >> (state - DATA_0)) & 0x01;
            }
            state = static_cast<State>(static_cast<int>(state) + 1);
            break;
        case FRAME:
            if (++count > packet[0])
            {
                if (packet != IDLE_PKT)
                {
                    --q.count;
                    ++q.rdIndex;
                    if (q.rdIndex == Q_SIZE)
                    {
                        q.rdIndex = 0;
                    }
                    MAP_IntPendSet(osInterrupt);
                }
                if (q.count)
                {
                    packet = &q.data[q.rdIndex][0];
                }
                else
                {
                    packet = IDLE_PKT;
                }
                current_bit = 1;
                state = PREAMBLE;
            }
            else
            {
                xor_byte ^= packet[count];
                current_bit = 0;
                state = DATA_0;
            }
            break;
    }

    if (last_bit != current_bit)
    {
        if (current_bit)
        {
            MAP_TimerLoadSet(intervalBase, TIMER_A, oneBitPeriod);
            MAP_TimerLoadSet(ccpBase, TIMER_A, oneBitPeriod);
            MAP_TimerLoadSet(ccpBase, TIMER_B, oneBitPeriod);
            MAP_TimerMatchSet(ccpBase, TIMER_A, (oneBitPeriod >> 1) - deadbandAdjust);
            MAP_TimerMatchSet(ccpBase, TIMER_B, (oneBitPeriod >> 1) + deadbandAdjust);
        }
        else
        {
            MAP_TimerLoadSet(intervalBase, TIMER_A, zeroBitPeriod);
            MAP_TimerLoadSet(ccpBase, TIMER_A, zeroBitPeriod);
            MAP_TimerLoadSet(ccpBase, TIMER_B, zeroBitPeriod);
            MAP_TimerMatchSet(ccpBase, TIMER_A, (zeroBitPeriod >> 1) - deadbandAdjust);
            MAP_TimerMatchSet(ccpBase, TIMER_B, (zeroBitPeriod >> 1) + deadbandAdjust);
        }
        last_bit = current_bit;
    }
}

#endif /* _FREERTOS_DRIVERS_TI_TIVADEV_HXX_ */

<commit_msg>Fixes bit ordering in TivaDCC: standard says MSB-first, the first implementation had the bits reversed.<commit_after>/** \copyright
 * Copyright (c) 2014, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file TivaDev.hxx
 * This file implements the device class prototypes for TivaWare.
 *
 * @author Stuart W. Baker
 * @date 6 May 2014
 */

#ifndef _FREERTOS_DRIVERS_TI_TIVADEV_HXX_
#define _FREERTOS_DRIVERS_TI_TIVADEV_HXX_

#ifndef gcc
#define gcc
#endif

#include <cstdint>

#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"
#include "usblib/usblib.h"
#include "usblib/usbcdc.h"
#include "usblib/usb-ids.h"
#include "usblib/device/usbdevice.h"
#include "usblib/device/usbdcdc.h"

#include "Serial.hxx"
#include "Can.hxx"

/* This is fixed and equals the USB packet size that the CDC device will
 * advertise to be able to receive. This is a performance parameter, 64 is the
 * largest packet size permitted by USB for virtual serial ports. */
#define USB_CDC_TX_DATA_SIZE 64
#define USB_CDC_RX_DATA_SIZE 64

/** Private data for this implementation of serial.
 */
class TivaCdc : public Serial
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param interrupt interrupt number used by the device
     */
    TivaCdc(const char *name, uint32_t interrupt);

    /** Destructor.
     */
    ~TivaCdc()
    {
    }

    /** @todo (Stuart Baker) this should be made private */
    /** handle an interrupt.
     */
    void interrupt_handler();

private:
    void enable(); /**< function to enable device */
    void disable(); /**< function to disable device */
    void tx_char(); /**< function to try and transmit a character */

    static unsigned long control_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data);

    static unsigned long rx_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data);

    static unsigned long tx_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data);

    tUSBDCDCDevice usbdcdcDevice; /**< CDC serial device instance */
    /** buffer for pending tx data */
    unsigned char txData[USB_CDC_TX_DATA_SIZE];
    /** buffer for pending rx data */
    unsigned char rxData[USB_CDC_RX_DATA_SIZE];
    uint32_t interrupt; /**< interrupt number for device */
    bool connected; /**< connection status */
    bool enabled; /**< enabled status */
    int woken; /**< task woken metadata for ISR */

    /** Default constructor.
     */
    TivaCdc();

    DISALLOW_COPY_AND_ASSIGN(TivaCdc);
};

/** Specialization of Serial driver for Tiva UART.
 */
class TivaUart : public Serial
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param base base address of this device
     * @param interrupt interrupt number of this device
     */
    TivaUart(const char *name, unsigned long base, uint32_t interrupt);

    /** Destructor.
     */
    ~TivaUart()
    {
    }

    /** @todo (Stuart Baker) this should be made private */
    /** handle an interrupt.
     */
    void interrupt_handler();

private:
    void enable(); /**< function to enable device */
    void disable(); /**< function to disable device */
    void tx_char(); /**< function to try and transmit a character */

    unsigned long base; /**< base address of this device */
    unsigned long interrupt; /**< interrupt of this device */
    bool txPending; /**< transmission currently pending */

    /** Default constructor.
     */
    TivaUart();

    DISALLOW_COPY_AND_ASSIGN(TivaUart);
};

/** Specialization of CAN driver for Tiva CAN.
 */
class TivaCan : public Can
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param base base address of this device
     * @param interrupt interrupt number of this device
     */
    TivaCan(const char *name, unsigned long base, uint32_t interrupt);

    /** Destructor.
     */
    ~TivaCan()
    {
    }

    /** @todo (Stuart Baker) this should be made private */
    /** handle an interrupt.
     */
    void interrupt_handler();

private:
    void enable(); /**< function to enable device */
    void disable(); /**< function to disable device */
    void tx_msg(); /**< function to try and transmit a message */

    unsigned long base; /**< base address of this device */
    unsigned long interrupt; /**< interrupt of this device */
    uint8_t data[8]; /**< transmit data */
    bool txPending; /**< transmission currently pending */

    /** Default constructor.
     */
    TivaCan();

    DISALLOW_COPY_AND_ASSIGN(TivaCan);
};

/** A device driver for sending DCC packets.  If the packet queue is empty,
 *  then the device driver automatically sends out idle DCC packets.  The
 *  device driver uses two instances of the 16/32-bit timer pairs.  The user
 *  is responsible for providing interrupt entry point for the interval timer
 *  and calling the inline method @ref interrupt_handler on behalf of this
 *  device driver.
 *
 *  Write calls work by sending the whole DCC packet excluding the X-OR linkage
 *  byte (which will be calculated automatically by the driver).  Only one DCC
 *  packet may be written per call to the write method.  If there is no space
 *  currently available in the write queue, the write method will return -1
 *  with errno set to ENOSPC.
 *
 *  Handling of write throttling:
 *
 *  The driver uses a second interrupt, used as a software interrupt at the
 *  FreeRTOS priority level, to communicate back information on when the device
 *  is writable. It is okay to use the interrupt for the second timer for this
 *  purpose. This interrupt will be enabled in the IOCTL after the
 *  writenotifiable is set, disabled in the interrupt itself when the
 *  writenotifiable is cleared. It is set pending at startup and when the dcc
 *  interrupt frees up a packet from the queue, and it is cleared pending when
 *  a write realizes there is no space for a buffer.
 */
class TivaDCC : public Node
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param ccp_base base address of a capture compare pwm timer pair
     * @param interval_base base address of an interval timer
     * @param interrupt interrupt number of interval timer
     * @param os_interrupt an otherwise unused interrupt number (cound be that of the capture compare pwm timer)
     * @param preamble_count number of preamble bits to send exclusive of
     *        end of packet '1' bit
     * @param one_bit_period number of system clock cycles for a one bit
     * @param zero_bit_period number of system clock cycles for a one bit
     * @param startup_delay offset for introducing some deadband at startup
     * @param deadband_adjust ajustment factor for adding deadband
     * @param railcom_cuttout true to produce the RailCom cuttout, else false
     */
    TivaDCC(const char *name,
            unsigned long ccp_base,
            unsigned long interval_base,
            uint32_t interrupt,
            uint32_t os_interrupt,
            int preamble_count,
            int one_bit_period,
            int zero_bit_period,
            int startup_delay,
            int deadband_adjust,
            bool railcom_cuttout = false);

    /** Destructor.
     */
    ~TivaDCC()
    {
    }

    /** Handle an interrupt.
     */
    inline void interrupt_handler();

    /** Handles a software interrupt to FreeRTOS. This should be called on the
     * interrupt number that is submitted as os_interrupt to the
     * constructor. */
    inline void os_interrupt_handler();

private:
    /** Read from a file or device.
     * @param file file reference for this device
     * @param buf location to place read data
     * @param count number of bytes to read
     * @return number of bytes read upon success, -1 upon failure with errno containing the cause
     */
    ssize_t read(File *file, void *buf, size_t count) OVERRIDE;

    /** Write to a file or device.
     * @param file file reference for this device
     * @param buf location to find write data
     * @param count number of bytes to write
     * @return number of bytes written upon success, -1 upon failure with errno containing the cause
     */
    ssize_t write(File *file, const void *buf, size_t count) OVERRIDE;

    /** Request an ioctl transaction
     * @param file file reference for this device
     * @param node node reference for this device
     * @param key ioctl key
     * @param data key data
     */
    int ioctl(File *file, unsigned long int key, unsigned long data) OVERRIDE;

    void enable(){} /**< function to enable device */
    void disable(){} /**< function to disable device */

    /** Discards all pending buffers.  Called after disable().
     */
    void flush_buffers(){};

    /** number of outgoing messages we can queue */
    static const size_t Q_SIZE = 4;

    /** maximum packet size we can support */
    static const size_t MAX_PKT_SIZE = 6;

    /** Queue structure for holding outgoing DCC packets.
     */
    struct Q
    {
        size_t count; /**< number of items in the queue */
        size_t rdIndex; /**< current read index */
        size_t wrIndex; /**< current write index */
        uint8_t data[Q_SIZE][MAX_PKT_SIZE + 1]; /**< queue data */
    };

    unsigned long ccpBase; /**< capture compare pwm base address */
    unsigned long intervalBase; /**< interval timer base address */
    uint32_t interrupt; /**< interrupt number of interval timer */
    int preambleCount; /**< number of preamble bits to send */
    int oneBitPeriod; /**< period of one bit */
    int zeroBitPeriod; /**< period of zero bit */
    int startupDelay; /**< startup offset */
    int deadbandAdjust; /**< deadband adjustment */
    bool railcomCuttout; /**< true if we should produce the RailCom cuttout */
    uint32_t osInterrupt; /**< interrupt used to notify FreeRTOS. */
    Notifiable* writableNotifiable; /**< Notify this when we have free buffers. */

    /** idle packet */
    static const uint8_t IDLE_PKT[3];

    Q q; /**< DCC packet queue */

    /** Default constructor.
     */
    TivaDCC();

    DISALLOW_COPY_AND_ASSIGN(TivaDCC);
};

__attribute__((optimize("-O3")))
inline void TivaDCC::os_interrupt_handler()
{
    HASSERT(writableNotifiable);
    Notifiable* n = writableNotifiable;
    writableNotifiable = nullptr;
    MAP_IntDisable(osInterrupt);
    n->notify_from_isr();
}

/** Handle an interrupt.
 */
__attribute__((optimize("-O3")))
inline void TivaDCC::interrupt_handler()
{
    enum State
    {
        PREAMBLE,
        START,
        DATA_0,
        DATA_1,
        DATA_2,
        DATA_3,
        DATA_4,
        DATA_5,
        DATA_6,
        DATA_7,
        FRAME,
    };

    static State state = PREAMBLE;
    static int preamble_count = 0;
    static int last_bit = 1;
    static int count = 0;
    static uint8_t xor_byte;
    static const uint8_t *packet = IDLE_PKT;
    int current_bit;

    MAP_TimerIntClear(intervalBase, TIMER_TIMA_TIMEOUT);

    switch (state)
    {
        default:
        case PREAMBLE:
            current_bit = 1;
            if (++preamble_count == preambleCount)
            {
                state = START;
                preamble_count = 0;
            }
            break;
        case START:
            current_bit = 0;
            count = 0;
            xor_byte = 0;
            state = DATA_0;
            break;
        case DATA_0:
        case DATA_1:
        case DATA_2:
        case DATA_3:
        case DATA_4:
        case DATA_5:
        case DATA_6:
        case DATA_7:
            if (count < packet[0])
            {
                current_bit = (packet[count + 1] >> (DATA_7 - state)) & 0x01;
            }
            else
            {
                current_bit = (xor_byte >> (DATA_7 - state)) & 0x01;
            }
            state = static_cast<State>(static_cast<int>(state) + 1);
            break;
        case FRAME:
            if (++count > packet[0])
            {
                if (packet != IDLE_PKT)
                {
                    --q.count;
                    ++q.rdIndex;
                    if (q.rdIndex == Q_SIZE)
                    {
                        q.rdIndex = 0;
                    }
                    MAP_IntPendSet(osInterrupt);
                }
                if (q.count)
                {
                    packet = &q.data[q.rdIndex][0];
                }
                else
                {
                    packet = IDLE_PKT;
                }
                current_bit = 1;
                state = PREAMBLE;
            }
            else
            {
                xor_byte ^= packet[count];
                current_bit = 0;
                state = DATA_0;
            }
            break;
    }

    if (last_bit != current_bit)
    {
        if (current_bit)
        {
            MAP_TimerLoadSet(intervalBase, TIMER_A, oneBitPeriod);
            MAP_TimerLoadSet(ccpBase, TIMER_A, oneBitPeriod);
            MAP_TimerLoadSet(ccpBase, TIMER_B, oneBitPeriod);
            MAP_TimerMatchSet(ccpBase, TIMER_A, (oneBitPeriod >> 1) - deadbandAdjust);
            MAP_TimerMatchSet(ccpBase, TIMER_B, (oneBitPeriod >> 1) + deadbandAdjust);
        }
        else
        {
            MAP_TimerLoadSet(intervalBase, TIMER_A, zeroBitPeriod);
            MAP_TimerLoadSet(ccpBase, TIMER_A, zeroBitPeriod);
            MAP_TimerLoadSet(ccpBase, TIMER_B, zeroBitPeriod);
            MAP_TimerMatchSet(ccpBase, TIMER_A, (zeroBitPeriod >> 1) - deadbandAdjust);
            MAP_TimerMatchSet(ccpBase, TIMER_B, (zeroBitPeriod >> 1) + deadbandAdjust);
        }
        last_bit = current_bit;
    }
}

#endif /* _FREERTOS_DRIVERS_TI_TIVADEV_HXX_ */

<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "go_quic_server_packet_writer.h"

#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/sparse_histogram.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"

#include "go_functions.h"

namespace net {

GoQuicServerPacketWriter::GoQuicServerPacketWriter(
    void* go_udp_conn,
    QuicBlockedWriterInterface* blocked_writer,
    void* go_task_runner)
    : go_udp_conn_(go_udp_conn),
      go_task_runner_(go_task_runner),
      blocked_writer_(blocked_writer),
      write_blocked_(false),
      weak_factory_(this) {
}

GoQuicServerPacketWriter::~GoQuicServerPacketWriter() {
}

WriteResult GoQuicServerPacketWriter::WritePacketWithCallback(
    const char* buffer,
    size_t buf_len,
    const IPAddressNumber& self_address,
    const IPEndPoint& peer_address,
    WriteCallback callback) {
  DCHECK(callback_.is_null());
  callback_ = callback;
  WriteResult result = WritePacket(buffer, buf_len, self_address, peer_address);
  if (result.status != WRITE_STATUS_BLOCKED) {
    callback_.Reset();
  }
  return result;
}

void GoQuicServerPacketWriter::OnWriteComplete(int rv) {
  DCHECK_NE(rv, ERR_IO_PENDING);
  write_blocked_ = false;
  WriteResult result(rv < 0 ? WRITE_STATUS_ERROR : WRITE_STATUS_OK, rv);
  if (!callback_.is_null()) {
    base::ResetAndReturn(&callback_).Run(result);
  }
  blocked_writer_->OnCanWrite();
}

bool GoQuicServerPacketWriter::IsWriteBlockedDataBuffered() const {
  // UDPServerSocket::SendTo buffers the data until the Write is permitted.
  return true;
}

bool GoQuicServerPacketWriter::IsWriteBlocked() const {
  return write_blocked_;
}

void GoQuicServerPacketWriter::SetWritable() {
  write_blocked_ = false;
}

WriteResult GoQuicServerPacketWriter::WritePacket(
    const char* buffer,
    size_t buf_len,
    const IPAddressNumber& self_address,
    const IPEndPoint& peer_address) {
//  scoped_refptr<StringIOBuffer> buf(
//      new StringIOBuffer(std::string(buffer, buf_len)));
  DCHECK(!IsWriteBlocked());
//  DCHECK(!callback_.is_null());
/*  TODO(hodduc) See quic_time_wait_list_manager.cc:WriteToWire. It should call WritePacketWithCallback to hold callback, but it isn't now. We turn off this check temporarily. */
  int rv;
  if (buf_len <= static_cast<size_t>(std::numeric_limits<int>::max())) {
    WriteToUDP_C(go_udp_conn_, (void *)(&peer_address), (void *)buffer, buf_len, (void *)this, go_task_runner_);

/*    rv = socket_->SendTo(buf.get(),
                         static_cast<int>(buf_len),
                         peer_address,
                         base::Bind(&GoQuicServerPacketWriter::OnWriteComplete,
                                    weak_factory_.GetWeakPtr()));                                  TODO(hodduc) */
    rv = ERR_IO_PENDING;                      // TODO(hodduc)
  } else {
    rv = ERR_MSG_TOO_BIG;
  }
  WriteStatus status = WRITE_STATUS_OK;
  if (rv < 0) {
    if (rv != ERR_IO_PENDING) {
      UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError", -rv);
      status = WRITE_STATUS_ERROR;
    } else {
      status = WRITE_STATUS_BLOCKED;
      write_blocked_ = true;
    }
  }
  return WriteResult(status, rv);
}

}  // namespace net
<commit_msg>Re-add callback null check<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "go_quic_server_packet_writer.h"

#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/sparse_histogram.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"

#include "go_functions.h"

namespace net {

GoQuicServerPacketWriter::GoQuicServerPacketWriter(
    void* go_udp_conn,
    QuicBlockedWriterInterface* blocked_writer,
    void* go_task_runner)
    : go_udp_conn_(go_udp_conn),
      go_task_runner_(go_task_runner),
      blocked_writer_(blocked_writer),
      write_blocked_(false),
      weak_factory_(this) {
}

GoQuicServerPacketWriter::~GoQuicServerPacketWriter() {
}

WriteResult GoQuicServerPacketWriter::WritePacketWithCallback(
    const char* buffer,
    size_t buf_len,
    const IPAddressNumber& self_address,
    const IPEndPoint& peer_address,
    WriteCallback callback) {
  DCHECK(callback_.is_null());
  callback_ = callback;
  WriteResult result = WritePacket(buffer, buf_len, self_address, peer_address);
  if (result.status != WRITE_STATUS_BLOCKED) {
    callback_.Reset();
  }
  return result;
}

void GoQuicServerPacketWriter::OnWriteComplete(int rv) {
  DCHECK_NE(rv, ERR_IO_PENDING);
  write_blocked_ = false;
  WriteResult result(rv < 0 ? WRITE_STATUS_ERROR : WRITE_STATUS_OK, rv);
  if (!callback_.is_null()) {
    base::ResetAndReturn(&callback_).Run(result);
  }
  blocked_writer_->OnCanWrite();
}

bool GoQuicServerPacketWriter::IsWriteBlockedDataBuffered() const {
  // UDPServerSocket::SendTo buffers the data until the Write is permitted.
  return true;
}

bool GoQuicServerPacketWriter::IsWriteBlocked() const {
  return write_blocked_;
}

void GoQuicServerPacketWriter::SetWritable() {
  write_blocked_ = false;
}

WriteResult GoQuicServerPacketWriter::WritePacket(
    const char* buffer,
    size_t buf_len,
    const IPAddressNumber& self_address,
    const IPEndPoint& peer_address) {
//  scoped_refptr<StringIOBuffer> buf(
//      new StringIOBuffer(std::string(buffer, buf_len)));
  DCHECK(!IsWriteBlocked());
  DCHECK(!callback_.is_null());
/*  TODO(hodduc) See quic_time_wait_list_manager.cc:WriteToWire. It should call WritePacketWithCallback to hold callback, but it isn't now. We turn off this check temporarily. */
  int rv;
  if (buf_len <= static_cast<size_t>(std::numeric_limits<int>::max())) {
    WriteToUDP_C(go_udp_conn_, (void *)(&peer_address), (void *)buffer, buf_len, (void *)this, go_task_runner_);

/*    rv = socket_->SendTo(buf.get(),
                         static_cast<int>(buf_len),
                         peer_address,
                         base::Bind(&GoQuicServerPacketWriter::OnWriteComplete,
                                    weak_factory_.GetWeakPtr()));                                  TODO(hodduc) */
    rv = ERR_IO_PENDING;                      // TODO(hodduc)
  } else {
    rv = ERR_MSG_TOO_BIG;
  }
  WriteStatus status = WRITE_STATUS_OK;
  if (rv < 0) {
    if (rv != ERR_IO_PENDING) {
      UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError", -rv);
      status = WRITE_STATUS_ERROR;
    } else {
      status = WRITE_STATUS_BLOCKED;
      write_blocked_ = true;
    }
  }
  return WriteResult(status, rv);
}

}  // namespace net
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "header.h"
#include "stride.h"
#include "math/math.h"
#include "dwi/gradient.h"
#include "gui/dialog/file.h"
#include "gui/dialog/list.h"
#include "gui/dialog/image_properties.h"

namespace MR
{
  namespace GUI
  {
    namespace Dialog
    {

      ImageProperties::ImageProperties (QWidget* parent, const MR::Header& header) :
        QDialog (parent), H (header), save_data (0, 0)
      {
        model = new TreeModel (this);

        TreeItem* root = model->rootItem;

        root->appendChild (new TreeItem ("File", H.name(), root));
        assert (H.format());
        root->appendChild (new TreeItem ("Format", H.format(), root));

        if (H.keyval().size()) {
          TreeItem* keyvals = new TreeItem ("Key/value pairs", std::string(), root);
          root->appendChild (keyvals);
          for (auto n : H.keyval()) {
            if (n.first != "dw_scheme") {
              if (n.second.find ('\n') == n.second.npos) {
                keyvals->appendChild (new TreeItem (n.first, n.second, keyvals));
              } else {
                const auto lines = split_lines (n.second);
                TreeItem* multi_line_keyval = new TreeItem (n.first, std::string(), keyvals);
                keyvals->appendChild (multi_line_keyval);
                for (auto l : lines)
                  multi_line_keyval->appendChild (new TreeItem (std::string(), l, multi_line_keyval));
              }
            }
          }
        }

        std::string text;
        text = str (H.size (0));
        for (size_t n = 1; n < H.ndim(); ++n)
          text += " x " + str (H.size (n));
        root->appendChild (new TreeItem ("Dimensions", text, root));

        text = str (H.spacing (0));
        for (size_t n = 1; n < H.ndim(); ++n)
          text += " x " + str (H.spacing (n));
        root->appendChild (new TreeItem ("Voxel size", text, root));

        root->appendChild (new TreeItem ("Data type", H.datatype().description(), root));

        MR::Stride::List strides = MR::Stride::get_symbolic (H);
        text = str (strides[0]);
        for (size_t n = 1; n != strides.size(); ++n)
          text += ", " + str (strides[n]);
        root->appendChild (new TreeItem ("Strides", text, root));

        root->appendChild (new TreeItem ("Data scaling",
                                         "offset: " + str (H.intensity_offset()) + ", multiplier = " + str (H.intensity_scale()), root));

        Eigen::IOFormat Fmt (6, 0, ", ", "\n", "[", "]");
        TreeItem* transform = new TreeItem ("Transform", std::string(), root);
        root->appendChild (transform);
        for (size_t n = 0; n < 3; ++n) {
          std::stringstream ss;
          ss << H.transform().matrix().row (n).format (Fmt);
          transform->appendChild (new TreeItem (std::string(), ss.str(), transform));
        }

        auto DW_scheme = DWI::parse_DW_scheme (H);
        if (DW_scheme.rows()) {
          if (DW_scheme.cols() != 4) {
            root->appendChild (new TreeItem ("Diffusion scheme", "(invalid)", root));
          }
          else {
            TreeItem* scheme = new TreeItem ("Diffusion scheme", std::string(), root);
            root->appendChild (scheme);
            for (size_t n = 0; n < size_t(DW_scheme.rows()); ++n) {
              std::stringstream ss;
              ss << DW_scheme.row (n).format (Fmt);
              scheme->appendChild (new TreeItem (std::string(), ss.str(), scheme));
            }
          }
        }

        view = new QTreeView;
        view->setModel (model);
        view->resizeColumnToContents (0);
        view->resizeColumnToContents (1);
        view->setMinimumSize (500, 200);
        view->setContextMenuPolicy (Qt::CustomContextMenu);
        connect (view, SIGNAL (customContextMenuRequested (const QPoint&)),
                 this, SLOT (context_menu (const QPoint&)));

        QDialogButtonBox* buttonBox = new QDialogButtonBox (QDialogButtonBox::Ok);
        connect (buttonBox, SIGNAL (accepted()), this, SLOT (accept()));

        QVBoxLayout* layout = new QVBoxLayout (this);
        layout->addWidget (view);
        layout->addWidget (buttonBox);
        setLayout (layout);

        setWindowTitle (tr ("Image Properties"));
        setSizeGripEnabled (true);
        adjustSize();
      }

      void ImageProperties::context_menu (const QPoint& point)
      {
        QModelIndex k = view->indexAt (point);
        if (!k.isValid()) return;
        k = k.sibling (k.row(), 0);

        while (k.parent().isValid()) k = k.parent();
        std::string text = k.data().toString().toUtf8().constData();

        if (text == "Transform") save_data = H.transform().matrix();
        else if (text == "Diffusion scheme") save_data = DWI::parse_DW_scheme (H);
        else {
          save_data.resize (0, 0);
          return;
        }

        QAction* save_action = new QAction (tr ("&Save as..."), this);
        connect (save_action, SIGNAL (triggered()), this, SLOT (write_to_file()));

        QMenu menu (this);
        menu.addAction (save_action);
        menu.exec (view->viewport()->mapToGlobal (point));
      }

      void ImageProperties::write_to_file ()
      {
        assert (save_data.rows());
        std::string name = File::get_save_name (this, "Save as...", "dwgrad.txt");
        if (name.size())
          MR::save_matrix (save_data, name);
      }

    }
  }
}

<commit_msg>mrview: display extended gbtable in properties box<commit_after>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "header.h"
#include "stride.h"
#include "math/math.h"
#include "dwi/gradient.h"
#include "gui/dialog/file.h"
#include "gui/dialog/list.h"
#include "gui/dialog/image_properties.h"

namespace MR
{
  namespace GUI
  {
    namespace Dialog
    {

      ImageProperties::ImageProperties (QWidget* parent, const MR::Header& header) :
        QDialog (parent), H (header), save_data (0, 0)
      {
        model = new TreeModel (this);

        TreeItem* root = model->rootItem;

        root->appendChild (new TreeItem ("File", H.name(), root));
        assert (H.format());
        root->appendChild (new TreeItem ("Format", H.format(), root));

        if (H.keyval().size()) {
          TreeItem* keyvals = new TreeItem ("Key/value pairs", std::string(), root);
          root->appendChild (keyvals);
          for (auto n : H.keyval()) {
            if (n.first != "dw_scheme") {
              if (n.second.find ('\n') == n.second.npos) {
                keyvals->appendChild (new TreeItem (n.first, n.second, keyvals));
              } else {
                const auto lines = split_lines (n.second);
                TreeItem* multi_line_keyval = new TreeItem (n.first, std::string(), keyvals);
                keyvals->appendChild (multi_line_keyval);
                for (auto l : lines)
                  multi_line_keyval->appendChild (new TreeItem (std::string(), l, multi_line_keyval));
              }
            }
          }
        }

        std::string text;
        text = str (H.size (0));
        for (size_t n = 1; n < H.ndim(); ++n)
          text += " x " + str (H.size (n));
        root->appendChild (new TreeItem ("Dimensions", text, root));

        text = str (H.spacing (0));
        for (size_t n = 1; n < H.ndim(); ++n)
          text += " x " + str (H.spacing (n));
        root->appendChild (new TreeItem ("Voxel size", text, root));

        root->appendChild (new TreeItem ("Data type", H.datatype().description(), root));

        MR::Stride::List strides = MR::Stride::get_symbolic (H);
        text = str (strides[0]);
        for (size_t n = 1; n != strides.size(); ++n)
          text += ", " + str (strides[n]);
        root->appendChild (new TreeItem ("Strides", text, root));

        root->appendChild (new TreeItem ("Data scaling",
                                         "offset: " + str (H.intensity_offset()) + ", multiplier = " + str (H.intensity_scale()), root));

        Eigen::IOFormat Fmt (6, 0, ", ", "\n", "[", "]");
        TreeItem* transform = new TreeItem ("Transform", std::string(), root);
        root->appendChild (transform);
        for (size_t n = 0; n < 3; ++n) {
          std::stringstream ss;
          ss << H.transform().matrix().row (n).format (Fmt);
          transform->appendChild (new TreeItem (std::string(), ss.str(), transform));
        }

        auto DW_scheme = DWI::parse_DW_scheme (H);
        if (DW_scheme.rows()) {
          if (DW_scheme.cols() >= 4) {
            root->appendChild (new TreeItem ("Diffusion scheme", "(invalid)", root));
          }
          else {
            TreeItem* scheme = new TreeItem ("Diffusion scheme", std::string(), root);
            root->appendChild (scheme);
            for (size_t n = 0; n < size_t(DW_scheme.rows()); ++n) {
              std::stringstream ss;
              ss << DW_scheme.row (n).format (Fmt);
              scheme->appendChild (new TreeItem (std::string(), ss.str(), scheme));
            }
          }
        }

        view = new QTreeView;
        view->setModel (model);
        view->resizeColumnToContents (0);
        view->resizeColumnToContents (1);
        view->setMinimumSize (500, 200);
        view->setContextMenuPolicy (Qt::CustomContextMenu);
        connect (view, SIGNAL (customContextMenuRequested (const QPoint&)),
                 this, SLOT (context_menu (const QPoint&)));

        QDialogButtonBox* buttonBox = new QDialogButtonBox (QDialogButtonBox::Ok);
        connect (buttonBox, SIGNAL (accepted()), this, SLOT (accept()));

        QVBoxLayout* layout = new QVBoxLayout (this);
        layout->addWidget (view);
        layout->addWidget (buttonBox);
        setLayout (layout);

        setWindowTitle (tr ("Image Properties"));
        setSizeGripEnabled (true);
        adjustSize();
      }

      void ImageProperties::context_menu (const QPoint& point)
      {
        QModelIndex k = view->indexAt (point);
        if (!k.isValid()) return;
        k = k.sibling (k.row(), 0);

        while (k.parent().isValid()) k = k.parent();
        std::string text = k.data().toString().toUtf8().constData();

        if (text == "Transform") save_data = H.transform().matrix();
        else if (text == "Diffusion scheme") save_data = DWI::parse_DW_scheme (H);
        else {
          save_data.resize (0, 0);
          return;
        }

        QAction* save_action = new QAction (tr ("&Save as..."), this);
        connect (save_action, SIGNAL (triggered()), this, SLOT (write_to_file()));

        QMenu menu (this);
        menu.addAction (save_action);
        menu.exec (view->viewport()->mapToGlobal (point));
      }

      void ImageProperties::write_to_file ()
      {
        assert (save_data.rows());
        std::string name = File::get_save_name (this, "Save as...", "dwgrad.txt");
        if (name.size())
          MR::save_matrix (save_data, name);
      }

    }
  }
}

<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
// Licensed to Qualys, Inc. (QUALYS) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// QUALYS licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/// @file
/// IronBee - Unit testing utility functions implementation.
/// @brief IronBee — String Util Test Functions
///
/// @author Nick LeRoy <nleroy@qualys.com>
//////////////////////////////////////////////////////////////////////////////
#ifndef __IBTEST_STRBASE_HH__
#define __IBTEST_STRBASE_HH__

#include "ironbee_config_auto.h"

#include <ironbee/types.h>
#include <ironbee/string.h>
#include <ironbee/util.h>
#include "ibtest_textbuf.hh"

#include "gtest/gtest.h"

#include <stdexcept>
#include <assert.h>
#include <stdio.h>

// Single test data point
class BaseTestDatum
{
public:
    BaseTestDatum()
        : m_end(true),
          m_lineno(0),
          m_inbuf(1, "")
    { };

    BaseTestDatum(size_t lno, size_t bufsize, const char *in)
        : m_end(false),
          m_lineno(lno),
          m_inbuf(bufsize, in)
    { };

    BaseTestDatum(size_t lno, size_t bufsize, const char *in, size_t len)
        : m_end(false),
          m_lineno(lno),
          m_inbuf(bufsize, in, len)
    {
    };

    // Accessors
    size_t LineNo(void) const { return m_lineno; };
    bool IsEnd(void) const { return m_end; };
    const TextBuf &InBuf(void) const { return m_inbuf; };

private:
    bool               m_end;         // Special case: End marker.
    size_t             m_lineno;      // Test's line number
    TextBuf            m_inbuf;       // Input text buffer
};

// Formatted call text buffer
class CallTextBuf : public TextBuf
{
public:
    CallTextBuf(size_t bufsize, const char *fn) :
        TextBuf(bufsize, fn)
    {
    };

    const char *Stringize(const char *op, const BaseTestDatum &datum)
    {
        snprintf(m_fmtbuf, m_size,
                 "%s(%s, \"%s\", ...)", m_buf, op, datum.InBuf().GetFmt());
        return m_fmtbuf;
    };
};

// Base class for string modification tests
class BaseStrModTest : public ::testing::Test
{
public:
    BaseStrModTest(size_t call_buf_size, size_t buf_size,
                   ib_strmod_fn_t fn, const char *fn_name,
                   ib_strmod_ex_fn_t ex_fn, const char *ex_fn_name)
        : m_strmod_fn(fn),
          m_callbuf(call_buf_size, fn_name),
          m_strmod_ex_fn(ex_fn),
          m_ex_callbuf(call_buf_size, ex_fn_name),
          m_op(IB_STROP_INPLACE),
          m_inbuf(buf_size),
          m_outbuf(buf_size)
    {
        ib_status_t rc = ib_mpool_create(&m_mpool, NULL, NULL);
        if (rc != IB_OK) {
            throw std::runtime_error("Could not create mpool.");
        }
    }

    void SetOp(ib_strop_t op) { m_op = op; };
    ib_strop_t Op(void) const { return m_op; };
    const char *OpStr( void ) const { return OpStr(m_op); };
    const char *OpStr( ib_strop_t op ) const
    {
        switch (op) {
        case IB_STROP_INPLACE:
            return "INPLACE";
        case IB_STROP_COW:
            return "COW";
        case IB_STROP_COPY:
            return "COPY";
        }
        assert(0);
    }

    virtual const char *FnName(void) const = 0;
    ib_mpool_t *MemPool( void ) { return m_mpool; };

    const char *BoolStr(ib_bool_t v) const
    {
        return (v == IB_TRUE ? "IB_TRUE" : "IB_FALSE");
    }
    const char *BoolStr(bool v) const
    {
        return (v == true ? "true" : "false");
    }
    const char *TriStr(ib_tristate_t v) const
    {
        switch (v) {
        case IB_TRI_FALSE:
            return "TRI/FALSE";
        case IB_TRI_TRUE:
            return "TRI/TRUE";
        case IB_TRI_UNSET:
            return "TRI/UNSET";
        }
        assert(0);
    }

    virtual bool ExpectCowAlias(bool mod) const
    {
        return (mod == false) ? true : false;
    }

    ib_flags_t ExpectedResult(ib_strop_t op, ib_bool_t mod) const
    {
        return ExpectedResult(op, (mod == IB_TRUE) ? true : false);
    }
    ib_flags_t ExpectedResult(ib_strop_t op, bool mod) const
    {
        ib_flags_t result;

        switch (op) {
        case IB_STROP_INPLACE:
            result = IB_STRFLAG_ALIAS;
            break;

        case IB_STROP_COPY:
            result = IB_STRFLAG_NEWBUF;
            break;

        case IB_STROP_COW:
            result = ExpectCowAlias(mod) ? IB_STRFLAG_ALIAS : IB_STRFLAG_NEWBUF;
            break;
        }
        if (mod == true) {
            result |= IB_STRFLAG_MODIFIED;
        }
        return result;
    }

    bool AllSpace( const TextBuf *buf=NULL ) const
    {
        if (buf == NULL) {
            buf = &m_inbuf;
        }
        const char *p = buf->GetBuf();
        const char *end = p + buf->GetLen();
        while(p < end) {
            if (isspace(*p) == 0) {
                return false;
            }
            ++p;
        }
        return true;
    }

    bool LeftSpace( const TextBuf *buf=NULL ) const
    {
        if (buf == NULL) {
            buf = &m_inbuf;
        }
        const char *p = buf->GetBuf();
        if ( (buf->GetLen() > 0) && (isspace(*p) != 0) ) {
            return true;
        }
        else {
            return false;
        }
    }

    bool RightSpace( const TextBuf *buf=NULL ) const
    {
        if (buf == NULL) {
            buf = &m_inbuf;
        }
        const char *p = buf->GetBuf() + buf->GetLen() - 1;
        if ( (buf->GetLen() > 0) && (isspace(*p) != 0) ) {
            return true;
        }
        else {
            return false;
        }
    }

    const std::string &ResultStr(ib_flags_t result) const
    {
        std::string s;
        return ResultStr(result, s);
    }
    const std::string &ResultStr(ib_flags_t result, std::string &s) const
    {
        int n = 0;
        if (result == IB_STRFLAG_NONE) {
            s = "<None>";
            return s;
        }
        s = "<";
        if (ib_flags_all(result, IB_STRFLAG_MODIFIED) == IB_TRUE) {
            if (n++ > 0) {
                s += ",";
            }
            s += "MODIFIED";
        }
        if (ib_flags_all(result, IB_STRFLAG_NEWBUF) == IB_TRUE) {
            if (n++ > 0) {
                s += ",";
            }
            s += "NEWBUF";
        }
        if (ib_flags_all(result, IB_STRFLAG_ALIAS) == IB_TRUE) {
            if (n++ > 0) {
                s += ",";
            }
            s += "ALIAS";
        }
        s += ">";
        return s;
    }

    ib_status_t RunTest(const BaseTestDatum &test, ib_flags_t &result)
    {
        if (m_strmod_fn != NULL) {
            return RunTestStr(test, result);
        }
        else if (m_strmod_ex_fn != NULL) {
            return RunTestEx(test, result);
        }
        else {
            assert (0);
        }
    }

    ib_status_t RunTestStr(const BaseTestDatum &test, ib_flags_t &result)
    {
        char *out = NULL;
        char *in;
        ib_status_t rc;

        m_inbuf.Set(test.InBuf());
        in = const_cast<char *>(m_inbuf.GetBuf());
        assert(in != NULL);
        assert(m_strmod_fn != NULL);
        rc = m_strmod_fn(m_op, MemPool(), in, &out, &result);
        if (rc == IB_OK) {
            m_outbuf.SetStr(out);
        }
        return rc;
    }

    virtual ib_status_t RunTestEx(const BaseTestDatum &test, ib_flags_t &result)
    {
        uint8_t *out;
        size_t outlen;
        ib_status_t rc;

        m_inbuf.Set(test.InBuf());

        rc = m_strmod_ex_fn(m_op, MemPool(),
                            const_cast<uint8_t *>(m_inbuf.GetText()),
                            m_inbuf.GetLen(),
                            &out, &outlen,
                            &result);
        if (rc == IB_OK) {
            m_outbuf.SetText((char *)out, outlen);
        }
        return rc;
    }

    void CheckResult(int lineno,
                     const BaseTestDatum &test,
                     ib_status_t rc,
                     ib_flags_t exresult,
                     ib_flags_t result)
    {
        std::string s1, s2;
        EXPECT_EQ(IB_OK, rc)
            << "Line " << lineno << ": "
            << Stringize(test) << " returned " << rc;
        if (rc != IB_OK) {
            return;
        }

        // NEWBUF and ALIAS result flags should never both be set
        ib_bool_t both =
            ib_flags_all(result, IB_STRFLAG_NEWBUF|IB_STRFLAG_ALIAS);
        ASSERT_EQ(IB_FALSE, both)
            << "Line " << lineno << ": " << Stringize(test)
            << " both NEWBUF and ALIAS result flags are set!"
            << ResultStr(result, s1);

        // Build the expected output
        EXPECT_EQ(exresult, result)
            << "Line " << lineno << ": " << Stringize(test)
            << " expected result=" << ResultStr(exresult, s1) << exresult
            << " actual=" << ResultStr(result, s2) << result;
    }

    const char *Stringize(const BaseTestDatum &test)
    {
        return m_callbuf.Stringize(OpStr(m_op), test);
    }

protected:
    ib_strmod_fn_t    m_strmod_fn;     // String mod function
    CallTextBuf       m_callbuf;       // Call string buffer
    ib_strmod_ex_fn_t m_strmod_ex_fn;  // ex version of string mod function
    CallTextBuf       m_ex_callbuf;       // Call string buffer
    ib_strop_t        m_op;            // String operation
    ib_mpool_t       *m_mpool;         // Memory pool to use
    TextBuf           m_inbuf;         // Copy of input
    TextBuf           m_outbuf;        // Output buffer
};

#endif
<commit_msg>Ensure that flags are zeroed out if we use |= on them.<commit_after>//////////////////////////////////////////////////////////////////////////////
// Licensed to Qualys, Inc. (QUALYS) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// QUALYS licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/// @file
/// IronBee - Unit testing utility functions implementation.
/// @brief IronBee — String Util Test Functions
///
/// @author Nick LeRoy <nleroy@qualys.com>
//////////////////////////////////////////////////////////////////////////////
#ifndef __IBTEST_STRBASE_HH__
#define __IBTEST_STRBASE_HH__

#include "ironbee_config_auto.h"

#include <ironbee/types.h>
#include <ironbee/string.h>
#include <ironbee/util.h>
#include "ibtest_textbuf.hh"

#include "gtest/gtest.h"

#include <stdexcept>
#include <assert.h>
#include <stdio.h>

// Single test data point
class BaseTestDatum
{
public:
    BaseTestDatum()
        : m_end(true),
          m_lineno(0),
          m_inbuf(1, "")
    { };

    BaseTestDatum(size_t lno, size_t bufsize, const char *in)
        : m_end(false),
          m_lineno(lno),
          m_inbuf(bufsize, in)
    { };

    BaseTestDatum(size_t lno, size_t bufsize, const char *in, size_t len)
        : m_end(false),
          m_lineno(lno),
          m_inbuf(bufsize, in, len)
    {
    };

    // Accessors
    size_t LineNo(void) const { return m_lineno; };
    bool IsEnd(void) const { return m_end; };
    const TextBuf &InBuf(void) const { return m_inbuf; };

private:
    bool               m_end;         // Special case: End marker.
    size_t             m_lineno;      // Test's line number
    TextBuf            m_inbuf;       // Input text buffer
};

// Formatted call text buffer
class CallTextBuf : public TextBuf
{
public:
    CallTextBuf(size_t bufsize, const char *fn) :
        TextBuf(bufsize, fn)
    {
    };

    const char *Stringize(const char *op, const BaseTestDatum &datum)
    {
        snprintf(m_fmtbuf, m_size,
                 "%s(%s, \"%s\", ...)", m_buf, op, datum.InBuf().GetFmt());
        return m_fmtbuf;
    };
};

// Base class for string modification tests
class BaseStrModTest : public ::testing::Test
{
public:
    BaseStrModTest(size_t call_buf_size, size_t buf_size,
                   ib_strmod_fn_t fn, const char *fn_name,
                   ib_strmod_ex_fn_t ex_fn, const char *ex_fn_name)
        : m_strmod_fn(fn),
          m_callbuf(call_buf_size, fn_name),
          m_strmod_ex_fn(ex_fn),
          m_ex_callbuf(call_buf_size, ex_fn_name),
          m_op(IB_STROP_INPLACE),
          m_inbuf(buf_size),
          m_outbuf(buf_size)
    {
        ib_status_t rc = ib_mpool_create(&m_mpool, NULL, NULL);
        if (rc != IB_OK) {
            throw std::runtime_error("Could not create mpool.");
        }
    }

    void SetOp(ib_strop_t op) { m_op = op; };
    ib_strop_t Op(void) const { return m_op; };
    const char *OpStr( void ) const { return OpStr(m_op); };
    const char *OpStr( ib_strop_t op ) const
    {
        switch (op) {
        case IB_STROP_INPLACE:
            return "INPLACE";
        case IB_STROP_COW:
            return "COW";
        case IB_STROP_COPY:
            return "COPY";
        }
        assert(0);
    }

    virtual const char *FnName(void) const = 0;
    ib_mpool_t *MemPool( void ) { return m_mpool; };

    const char *BoolStr(ib_bool_t v) const
    {
        return (v == IB_TRUE ? "IB_TRUE" : "IB_FALSE");
    }
    const char *BoolStr(bool v) const
    {
        return (v == true ? "true" : "false");
    }
    const char *TriStr(ib_tristate_t v) const
    {
        switch (v) {
        case IB_TRI_FALSE:
            return "TRI/FALSE";
        case IB_TRI_TRUE:
            return "TRI/TRUE";
        case IB_TRI_UNSET:
            return "TRI/UNSET";
        }
        assert(0);
    }

    virtual bool ExpectCowAlias(bool mod) const
    {
        return (mod == false) ? true : false;
    }

    ib_flags_t ExpectedResult(ib_strop_t op, ib_bool_t mod) const
    {
        return ExpectedResult(op, (mod == IB_TRUE) ? true : false);
    }
    ib_flags_t ExpectedResult(ib_strop_t op, bool mod) const
    {
        ib_flags_t result = 0;

        switch (op) {
        case IB_STROP_INPLACE:
            result = IB_STRFLAG_ALIAS;
            break;

        case IB_STROP_COPY:
            result = IB_STRFLAG_NEWBUF;
            break;

        case IB_STROP_COW:
            result = ExpectCowAlias(mod) ? IB_STRFLAG_ALIAS : IB_STRFLAG_NEWBUF;
            break;
        }
        if (mod == true) {
            result |= IB_STRFLAG_MODIFIED;
        }
        return result;
    }

    bool AllSpace( const TextBuf *buf=NULL ) const
    {
        if (buf == NULL) {
            buf = &m_inbuf;
        }
        const char *p = buf->GetBuf();
        const char *end = p + buf->GetLen();
        while(p < end) {
            if (isspace(*p) == 0) {
                return false;
            }
            ++p;
        }
        return true;
    }

    bool LeftSpace( const TextBuf *buf=NULL ) const
    {
        if (buf == NULL) {
            buf = &m_inbuf;
        }
        const char *p = buf->GetBuf();
        if ( (buf->GetLen() > 0) && (isspace(*p) != 0) ) {
            return true;
        }
        else {
            return false;
        }
    }

    bool RightSpace( const TextBuf *buf=NULL ) const
    {
        if (buf == NULL) {
            buf = &m_inbuf;
        }
        const char *p = buf->GetBuf() + buf->GetLen() - 1;
        if ( (buf->GetLen() > 0) && (isspace(*p) != 0) ) {
            return true;
        }
        else {
            return false;
        }
    }

    const std::string &ResultStr(ib_flags_t result) const
    {
        std::string s;
        return ResultStr(result, s);
    }
    const std::string &ResultStr(ib_flags_t result, std::string &s) const
    {
        int n = 0;
        if (result == IB_STRFLAG_NONE) {
            s = "<None>";
            return s;
        }
        s = "<";
        if (ib_flags_all(result, IB_STRFLAG_MODIFIED) == IB_TRUE) {
            if (n++ > 0) {
                s += ",";
            }
            s += "MODIFIED";
        }
        if (ib_flags_all(result, IB_STRFLAG_NEWBUF) == IB_TRUE) {
            if (n++ > 0) {
                s += ",";
            }
            s += "NEWBUF";
        }
        if (ib_flags_all(result, IB_STRFLAG_ALIAS) == IB_TRUE) {
            if (n++ > 0) {
                s += ",";
            }
            s += "ALIAS";
        }
        s += ">";
        return s;
    }

    ib_status_t RunTest(const BaseTestDatum &test, ib_flags_t &result)
    {
        if (m_strmod_fn != NULL) {
            return RunTestStr(test, result);
        }
        else if (m_strmod_ex_fn != NULL) {
            return RunTestEx(test, result);
        }
        else {
            assert (0);
        }
    }

    ib_status_t RunTestStr(const BaseTestDatum &test, ib_flags_t &result)
    {
        char *out = NULL;
        char *in;
        ib_status_t rc;

        m_inbuf.Set(test.InBuf());
        in = const_cast<char *>(m_inbuf.GetBuf());
        assert(in != NULL);
        assert(m_strmod_fn != NULL);
        rc = m_strmod_fn(m_op, MemPool(), in, &out, &result);
        if (rc == IB_OK) {
            m_outbuf.SetStr(out);
        }
        return rc;
    }

    virtual ib_status_t RunTestEx(const BaseTestDatum &test, ib_flags_t &result)
    {
        uint8_t *out;
        size_t outlen;
        ib_status_t rc;

        m_inbuf.Set(test.InBuf());

        rc = m_strmod_ex_fn(m_op, MemPool(),
                            const_cast<uint8_t *>(m_inbuf.GetText()),
                            m_inbuf.GetLen(),
                            &out, &outlen,
                            &result);
        if (rc == IB_OK) {
            m_outbuf.SetText((char *)out, outlen);
        }
        return rc;
    }

    void CheckResult(int lineno,
                     const BaseTestDatum &test,
                     ib_status_t rc,
                     ib_flags_t exresult,
                     ib_flags_t result)
    {
        std::string s1, s2;
        EXPECT_EQ(IB_OK, rc)
            << "Line " << lineno << ": "
            << Stringize(test) << " returned " << rc;
        if (rc != IB_OK) {
            return;
        }

        // NEWBUF and ALIAS result flags should never both be set
        ib_bool_t both =
            ib_flags_all(result, IB_STRFLAG_NEWBUF|IB_STRFLAG_ALIAS);
        ASSERT_EQ(IB_FALSE, both)
            << "Line " << lineno << ": " << Stringize(test)
            << " both NEWBUF and ALIAS result flags are set!"
            << ResultStr(result, s1);

        // Build the expected output
        EXPECT_EQ(exresult, result)
            << "Line " << lineno << ": " << Stringize(test)
            << " expected result=" << ResultStr(exresult, s1) << exresult
            << " actual=" << ResultStr(result, s2) << result;
    }

    const char *Stringize(const BaseTestDatum &test)
    {
        return m_callbuf.Stringize(OpStr(m_op), test);
    }

protected:
    ib_strmod_fn_t    m_strmod_fn;     // String mod function
    CallTextBuf       m_callbuf;       // Call string buffer
    ib_strmod_ex_fn_t m_strmod_ex_fn;  // ex version of string mod function
    CallTextBuf       m_ex_callbuf;       // Call string buffer
    ib_strop_t        m_op;            // String operation
    ib_mpool_t       *m_mpool;         // Memory pool to use
    TextBuf           m_inbuf;         // Copy of input
    TextBuf           m_outbuf;        // Output buffer
};

#endif
<|endoftext|>