text:
/*-----------------------------------------------------------------------------+
Interval Container Library
Author: Joachim Faulhaber
Copyright (c) 2007-2009: Joachim Faulhaber
Copyright (c) 1999-2006: Cortex Software GmbH, Kantstrasse 57, Berlin
+------------------------------------------------------------------------------+
   Distributed under the Boost Software License, Version 1.0.
      (See accompanying file LICENCE.txt or copy at
           http://www.boost.org/LICENSE_1_0.txt)
+-----------------------------------------------------------------------------*/
/** Example interval_container.cpp \file interval_container.cpp

    \brief Demonstrates basic characteristics of interval container objects.

    \include interval_container_/interval_container.cpp
*/
//[example_interval_container
#include <iostream>
#include <boost/icl/interval_set.hpp>
#include <boost/icl/separate_interval_set.hpp>
#include <boost/icl/split_interval_set.hpp>
#include <boost/icl/split_interval_map.hpp>
#include "../toytime.hpp"

using namespace std;
using namespace boost::icl;

void interval_container_basics()
{
    interval<Time>::type night_and_day(Time(monday,   20,00), Time(tuesday,  20,00));
    interval<Time>::type day_and_night(Time(tuesday,   7,00), Time(wednesday, 7,00));
    interval<Time>::type  next_morning(Time(wednesday, 7,00), Time(wednesday,10,00));
    interval<Time>::type  next_evening(Time(wednesday,18,00), Time(wednesday,21,00));

    // An interval set of type interval_set joins intervals that that overlap or touch each other.
    interval_set<Time> joinedTimes;
    joinedTimes.insert(night_and_day);
    joinedTimes.insert(day_and_night); //overlapping in 'day' [07:00, 20.00)
    joinedTimes.insert(next_morning);  //touching
    joinedTimes.insert(next_evening);  //disjoint

    cout << "Joined times  :" << joinedTimes << endl;

    // A separate interval set of type separate_interval_set joins intervals that that
    // overlap but it preserves interval borders that just touch each other. You may
    // represent time grids like the months of a year as a split_interval_set.
    separate_interval_set<Time> separateTimes;
    separateTimes.insert(night_and_day);
    separateTimes.insert(day_and_night); //overlapping in 'day' [07:00, 20.00)
    separateTimes.insert(next_morning);  //touching
    separateTimes.insert(next_evening);  //disjoint

    cout << "Separate times:" << separateTimes << endl;

    // A split interval set of type split_interval_set preserves all interval
    // borders. On insertion of overlapping intervals the intervals in the
    // set are split up at the interval borders of the inserted interval.
    split_interval_set<Time> splitTimes;
    splitTimes += night_and_day;
    splitTimes += day_and_night; //overlapping in 'day' [07:00, 20:00)
    splitTimes += next_morning;  //touching
    splitTimes += next_evening;  //disjoint

    cout << "Split times   :\n" << splitTimes << endl;

    // A split interval map splits up inserted intervals on overlap and aggregates the
    // associated quantities via the operator +=
    split_interval_map<Time, int> overlapCounter;
    overlapCounter += make_pair(night_and_day,1);
    overlapCounter += make_pair(day_and_night,1); //overlapping in 'day' [07:00, 20.00)
    overlapCounter += make_pair(next_morning, 1); //touching
    overlapCounter += make_pair(next_evening, 1); //disjoint

    cout << "Split times overlap counted:\n" << overlapCounter << endl;

    // An interval map joins touching intervals, if associated values are equal
    interval_map<Time, int> joiningOverlapCounter;
    joiningOverlapCounter = overlapCounter;
    cout << "Times overlap counted:\n" << joiningOverlapCounter << endl;
}

int main()
{
    cout << ">>Interval Container Library: Sample interval_container.cpp <<\n";
    cout << "--------------------------------------------------------------\n";
    interval_container_basics();
    return 0;
}

// Program output:
/* ----------------------------------------------------------------------------
>>Interval Container Library: Sample interval_container.cpp <<
--------------------------------------------------------------
Joined times  :[mon:20:00,wed:10:00)[wed:18:00,wed:21:00)
Separate times:[mon:20:00,wed:07:00)[wed:07:00,wed:10:00)[wed:18:00,wed:21:00)
Split times   :
[mon:20:00,tue:07:00)[tue:07:00,tue:20:00)[tue:20:00,wed:07:00)
[wed:07:00,wed:10:00)[wed:18:00,wed:21:00)
Split times overlap counted:
{([mon:20:00,tue:07:00)->1)([tue:07:00,tue:20:00)->2)([tue:20:00,wed:07:00)->1)
([wed:07:00,wed:10:00)->1)([wed:18:00,wed:21:00)->1)}
Times overlap counted:
{([mon:20:00,tue:07:00)->1)([tue:07:00,tue:20:00)->2)([tue:20:00,wed:10:00)->1)
([wed:18:00,wed:21:00)->1)}
-----------------------------------------------------------------------------*/
//]


text:
/*    This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
 *    See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
 *    Author(s):       Siargey Kachanovich
 *
 *    Copyright (C) 2016 Inria
 *
 *    Modification(s):
 *      - YYYY/MM Author: Description of the modification
 */

#include <gudhi/Simplex_tree.h>
#include <gudhi/Euclidean_strong_witness_complex.h>
#include <gudhi/Persistent_cohomology.h>
#include <gudhi/Points_off_io.h>
#include <gudhi/pick_n_random_points.h>
#include <gudhi/choose_n_farthest_points.h>

#include <boost/program_options.hpp>

#include <CGAL/Epick_d.h>

#include <string>
#include <vector>
#include <limits>  // infinity

using K = CGAL::Epick_d<CGAL::Dynamic_dimension_tag>;
using Point_d = K::Point_d;

using Point_vector = std::vector<Point_d>;
using Strong_witness_complex = Gudhi::witness_complex::Euclidean_strong_witness_complex<K>;
using SimplexTree = Gudhi::Simplex_tree<>;

using Filtration_value = SimplexTree::Filtration_value;

using Field_Zp = Gudhi::persistent_cohomology::Field_Zp;
using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology<SimplexTree, Field_Zp>;

void program_options(int argc, char* argv[], int& nbL, std::string& file_name, std::string& filediag,
                     Filtration_value& max_squared_alpha, int& p, int& dim_max, Filtration_value& min_persistence);

int main(int argc, char* argv[]) {
  std::string file_name;
  std::string filediag;
  Filtration_value max_squared_alpha;
  int p, nbL, lim_d;
  Filtration_value min_persistence;
  SimplexTree simplex_tree;

  program_options(argc, argv, nbL, file_name, filediag, max_squared_alpha, p, lim_d, min_persistence);

  // Extract the points from the file file_name
  Point_vector witnesses, landmarks;
  Gudhi::Points_off_reader<Point_d> off_reader(file_name);
  if (!off_reader.is_valid()) {
    std::cerr << "Witness complex - Unable to read file " << file_name << "\n";
    exit(-1);  // ----- >>
  }
  witnesses = Point_vector(off_reader.get_point_cloud());
  std::clog << "Successfully read " << witnesses.size() << " points.\n";
  std::clog << "Ambient dimension is " << witnesses[0].dimension() << ".\n";

  // Choose landmarks (decomment one of the following two lines)
  // Gudhi::subsampling::pick_n_random_points(point_vector, nbL, std::back_inserter(landmarks));
  Gudhi::subsampling::choose_n_farthest_points(K().squared_distance_d_object(), witnesses, nbL,
                                               Gudhi::subsampling::random_starting_point,
                                               std::back_inserter(landmarks));

  // Compute witness complex
  Strong_witness_complex strong_witness_complex(landmarks, witnesses);

  strong_witness_complex.create_complex(simplex_tree, max_squared_alpha, lim_d);

  std::clog << "The complex contains " << simplex_tree.num_simplices() << " simplices \n";
  std::clog << "   and has dimension " << simplex_tree.dimension() << " \n";

  // Sort the simplices in the order of the filtration
  simplex_tree.initialize_filtration();

  // Compute the persistence diagram of the complex
  Persistent_cohomology pcoh(simplex_tree);
  // initializes the coefficient field for homology
  pcoh.init_coefficients(p);

  pcoh.compute_persistent_cohomology(min_persistence);

  // Output the diagram in filediag
  if (filediag.empty()) {
    pcoh.output_diagram();
  } else {
    std::ofstream out(filediag);
    pcoh.output_diagram(out);
    out.close();
  }

  return 0;
}

void program_options(int argc, char* argv[], int& nbL, std::string& file_name, std::string& filediag,
                     Filtration_value& max_squared_alpha, int& p, int& dim_max, Filtration_value& min_persistence) {
  namespace po = boost::program_options;

  po::options_description hidden("Hidden options");
  hidden.add_options()("input-file", po::value<std::string>(&file_name),
                       "Name of file containing a point set in off format.");

  po::options_description visible("Allowed options", 100);
  Filtration_value default_alpha = std::numeric_limits<Filtration_value>::infinity();
  visible.add_options()("help,h", "produce help message")("landmarks,l", po::value<int>(&nbL),
                                                          "Number of landmarks to choose from the point cloud.")(
      "output-file,o", po::value<std::string>(&filediag)->default_value(std::string()),
      "Name of file in which the persistence diagram is written. Default print in std::clog")(
      "max-sq-alpha,a", po::value<Filtration_value>(&max_squared_alpha)->default_value(default_alpha),
      "Maximal squared relaxation parameter.")(
      "field-charac,p", po::value<int>(&p)->default_value(11),
      "Characteristic p of the coefficient field Z/pZ for computing homology.")(
      "min-persistence,m", po::value<Filtration_value>(&min_persistence)->default_value(0),
      "Minimal lifetime of homology feature to be recorded. Default is 0. Enter a negative value to see zero length "
      "intervals")("cpx-dimension,d", po::value<int>(&dim_max)->default_value(std::numeric_limits<int>::max()),
                   "Maximal dimension of the strong witness complex we want to compute.");

  po::positional_options_description pos;
  pos.add("input-file", 1);

  po::options_description all;
  all.add(visible).add(hidden);
  po::variables_map vm;

  po::store(po::command_line_parser(argc, argv).options(all).positional(pos).run(), vm);
  po::notify(vm);

  if (vm.count("help") || !vm.count("input-file")) {
    std::clog << std::endl;
    std::clog << "Compute the persistent homology with coefficient field Z/pZ \n";
    std::clog << "of a Strong witness complex defined on a set of input points.\n \n";
    std::clog << "The output diagram contains one bar per line, written with the convention: \n";
    std::clog << "   p   dim b d \n";
    std::clog << "where dim is the dimension of the homological feature,\n";
    std::clog << "b and d are respectively the birth and death of the feature and \n";
    std::clog << "p is the characteristic of the field Z/pZ used for homology coefficients." << std::endl << std::endl;

    std::clog << "Usage: " << argv[0] << " [options] input-file" << std::endl << std::endl;
    std::clog << visible << std::endl;
    exit(-1);
  }
}

ext: cpp

max_stars_repo_name: VincentRouvreau/gudhi-devel

max_issues_repo_name: gspr/gudhi-devel

max_forks_repo_name: gspr/gudhi-devel


text:
#include "s3.h"

#include <aws/core/Aws.h>
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/GetObjectRequest.h>
#include <aws/s3/model/HeadObjectRequest.h>
#include <aws/s3/model/ListObjectsV2Request.h>
#include <pxr/base/tf/diagnosticLite.h>
#include <pxr/base/tf/fileUtils.h>
#include <pxr/base/tf/pathUtils.h>
#include <time.h>

#include <boost/asio/async_result.hpp>
#include <fstream>
#include <iostream>

PXR_NAMESPACE_USING_DIRECTIVE

// -------------------------------------------------------------------------------
// If you want to print out a stacktrace everywhere S3_WARN is called, set this
// to a value > 0 - it will print out this number of stacktrace entries
#define USD_S3_DEBUG_STACKTRACE_SIZE 0

#if USD_S3_DEBUG_STACKTRACE_SIZE > 0

#include <execinfo.h>

#define S3_WARN                                                       \
  {                                                                   \
    void* backtrace_array[USD_S3_DEBUG_STACKTRACE_SIZE];              \
    size_t stack_size =                                               \
        backtrace(backtrace_array, USD_S3_DEBUG_STACKTRACE_SIZE);     \
    TF_WARN("\n\n====================================\n");            \
    TF_WARN("Stacktrace:\n");                                         \
    backtrace_symbols_fd(backtrace_array, stack_size, STDERR_FILENO); \
  }                                                                   \
  TF_WARN

#else  // STACKTRACE_SIZE

#define S3_WARN TF_WARN

#endif  // STACKTRACE_SIZE

// -------------------------------------------------------------------------------

// If you want to control the number of seconds an idle connection is kept alive
// for, set this to something other than zero

#define SESSION_WAIT_TIMEOUT 0

#if SESSION_WAIT_TIMEOUT > 0

#define _USD_S3_SIMPLE_QUOTE(ARG) #ARG
#define _USD_S3_EXPAND_AND_QUOTE(ARG) _SIMPLE_QUOTE(ARG)
#define SET_SESSION_WAIT_TIMEOUT_QUERY \
  ("SET SESSION wait_timeout=" _USD_S3_EXPAND_AND_QUOTE(SESSION_WAIT_TIMEOUT))
#define SET_SESSION_WAIT_TIMEOUT_QUERY_STRLEN \
  (sizeof(SET_SESSION_WAIT_TIMEOUT_QUERY) - 1)

#endif  // SESSION_WAIT_TIMEOUT

// -------------------------------------------------------------------------------

namespace {

constexpr double INVALID_TIME = std::numeric_limits<double>::lowest();

// using mutex_scoped_lock = std::lock_guard<std::mutex>;

// Otherwise clang static analyser will throw errors.
template <size_t len>
constexpr size_t cexpr_strlen(const char (&)[len]) {
  return len - 1;
}

// Parse an S3 url and strip off the prefix ('s3:', 's3:/' or 's3://')
// e.g. s3://bucket/object.usd returns bucket/object.usd
std::string ParsePath(const std::string& path) {
  constexpr auto schema_length_short = cexpr_strlen(usd_s3::S3_PREFIX_SHORT);
  return path.substr(path.find_first_not_of("/", schema_length_short));
}

// Get the bucket from a parsed path
// e.g. 'bucket/object.usd' returns 'bucket'
//      'bucket/somedir/object.usd' returns 'bucket'
const std::string GetBucketName(const std::string& path) {
  return path.substr(0, path.find_first_of('/'));
}

// Get the object from a parsed path
// e.g. 'bucket/object.usd' returns 'object.usd'
//      'bucket/somedir/object.usd' returns 'somedir/object.usd'
//      'bucket/object.usd?versionId=abc123' returns object.usd
const std::string GetObjectName(const std::string& path) {
  const int i = path.find_first_of('/');
  return path.substr(i, path.find_first_of('?') - i);
}

// Check if a parsed path uses S3 versioning
// e.g. 'bucket/object.usd' returns False
//      'bucket/object.usd?versionId=abc123' returns True
const bool UsesVersioning(const std::string& path) {
  return path.find("versionId=") != std::string::npos;
}

// Get the version ID of a parsed path uses S3 versioning
// e.g. 'bucket/object.usd' returns an empty string
//      'bucket/object.usd?versionId=abc123' returns abc123
const std::string GetObjectVersionid(const std::string& path) {
  const uint i = path.find_first_of("versionId=");
  return (i != std::string::npos) ? path.substr(i + 10) : std::string();
}

// get an environment variable
std::string GetEnvVar(const std::string& env_var,
                      const std::string& default_value) {
  const auto env_var_value = getenv(env_var.c_str());
  return (env_var_value != nullptr) ? env_var_value : default_value;
}

}  // namespace

namespace usd_s3 {
Aws::SDKOptions options;
Aws::S3::S3Client* s3_client;

enum CacheState { CACHE_MISSING, CACHE_NEEDS_FETCHING, CACHE_FETCHED };

struct Cache {
  CacheState state;
  std::string local_path;
  double timestamp;  // date last modified
  bool is_pinned;    // pinned (versioned) objects don't need to be checked for
                     // changes
  std::string ETag;  // md5 hash
};

std::map<std::string, Cache> cached_requests;

// Determine a local path for an asset
std::string GeneratePath(const std::string& path) {
  const std::string local_dir = GetEnvVar(CACHE_PATH_ENV_VAR, "/tmp");
  return TfNormPath(local_dir + "/" + GetBucketName(path) + "/" +
                    GetObjectName(path));
}

// Check / resolve an asset with an S3 HEAD request and store the result in the
// cache Set CACHE_NEEDS_FETCHING if the asset was updated Requires the asset to
// be fetched before --
std::string check_object(const std::string& path, Cache& cache) {
  if (s3_client == nullptr) {
    return std::string();
  }

  Aws::S3::Model::HeadObjectRequest head_request;
  Aws::String bucket_name = GetBucketName(path).c_str();
  Aws::String object_name = GetObjectName(path).c_str();
  head_request.WithBucket(bucket_name).WithKey(object_name);

  if (UsesVersioning(path)) {
    Aws::String object_versionid = GetObjectVersionid(path).c_str();
    head_request.WithVersionId(object_versionid);
    cache.is_pinned = true;
  }

  auto head_object_outcome = s3_client->HeadObject(head_request);

  if (head_object_outcome.IsSuccess()) {
    // TODO set local_dir in S3 constructor
    double date_modified = head_object_outcome.GetResult()
                               .GetLastModified()
                               .SecondsWithMSPrecision();
    // check
    std::string local_path = GeneratePath(path);
    if (date_modified > cache.timestamp) {
      cache.state = CACHE_NEEDS_FETCHING;
    }
    cache.timestamp = date_modified;
    cache.local_path = local_path;

    return local_path;
  } else {
    cache.timestamp = INVALID_TIME;
    std::cout << "HeadObjects error: "
              << head_object_outcome.GetError().GetExceptionName() << " "
              << head_object_outcome.GetError().GetMessage() << std::endl;
    return std::string();
  };
}

// Fetch an asset from S3 to the local_path set in the cache object.
// Check for the presence of a local cache and only fetch the asset
// when it was modified after the cached timestamp.
bool fetch_object(const std::string& path, Cache& cache) {
  if (s3_client == nullptr) {
    return false;
  }

  Aws::S3::Model::GetObjectRequest object_request;
  Aws::String bucket_name = GetBucketName(path).c_str();
  Aws::String object_name = GetObjectName(path).c_str();
  object_request.WithBucket(bucket_name).WithKey(object_name);

  if (UsesVersioning(path)) {
    Aws::String object_versionid = GetObjectVersionid(path).c_str();
    object_request.WithVersionId(object_versionid);
    cache.is_pinned = true;
  }

  double local_date_modified_old = cache.timestamp;

  // Only download the asset if there's no local copy or if the local copy is
  // outdated The GET request returns a 304 (not modified).
  const std::string local_path = cache.local_path;
  if (TfPathExists(local_path)) {
    double local_date_modified;
    if (ArchGetModificationTime(local_path.c_str(), &local_date_modified)) {
      cache.timestamp = local_date_modified;
      object_request.WithIfModifiedSince(local_date_modified);
    }
  }

  auto get_object_outcome = s3_client->GetObject(object_request);

  if (get_object_outcome.IsSuccess()) {
    // prepare cache directory
    const std::string& bucket_path =
        cache.local_path.substr(0, cache.local_path.find_last_of('/'));
    if (!TfIsDir(bucket_path)) {
      bool isSuccess = TfMakeDirs(bucket_path);
      if (!isSuccess) {
        return false;
      }
    }
    cache.timestamp = local_date_modified_old;
    Aws::OFStream local_file;
    local_file.open(cache.local_path, std::ios::out | std::ios::binary);
    local_file << get_object_outcome.GetResult().GetBody().rdbuf();
    cache.timestamp = get_object_outcome.GetResult()
                          .GetLastModified()
                          .SecondsWithMSPrecision();
    // get_object_outcome.GetResult().GetVersionId().c_str());
    cache.state = CACHE_FETCHED;
    cache.ETag = get_object_outcome.GetResult().GetETag().c_str();
    return true;
  } else {
    if (get_object_outcome.GetError().GetResponseCode() ==
        Aws::Http::HttpResponseCode::NOT_MODIFIED) {
      // cache.timestamp =
      // get_object_outcome.GetResult().GetLastModified().SecondsWithMSPrecision();
      cache.state = CACHE_FETCHED;
      return true;
    }
    std::cout << "GetObject error: "
              << get_object_outcome.GetError().GetExceptionName() << " "
              << get_object_outcome.GetError().GetMessage() << std::endl;
    return false;
  }
}

S3::S3() {
  Aws::InitAPI(options);

  Aws::Client::ClientConfiguration config;
  config.scheme = Aws::Http::Scheme::HTTP;

  // set a custom endpoint e.g. an ActiveScale system node or minio server
  if (!GetEnvVar(ENDPOINT_ENV_VAR, "").empty()) {
    config.endpointOverride = (GetEnvVar(ENDPOINT_ENV_VAR, "")).c_str();
  }
  if (!GetEnvVar(PROXY_HOST_ENV_VAR, "").empty()) {
    config.proxyHost = GetEnvVar(PROXY_HOST_ENV_VAR, "").c_str();
    config.proxyPort = atoi(GetEnvVar(PROXY_PORT_ENV_VAR, "80").c_str());
  }

  config.connectTimeoutMs = 3000;
  config.requestTimeoutMs = 3000;

  // create a client with useVirtualAddressing=false to use path style
  // addressing see https://github.com/aws/aws-sdk-cpp/issues/587
  s3_client = Aws::New<Aws::S3::S3Client>(
      "s3resolver", config,
      Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);
}

S3::~S3() {
  Aws::Delete(s3_client);
  Aws::ShutdownAPI(options);
}

// Resolve an asset path such as 's3://hello/world.usd'
// Checks if the asset exists and returns a local path for the asset
std::string S3::ResolveName(const std::string& asset_path) {
  const auto path = ParsePath(asset_path);
  const auto cached_result = cached_requests.find(path);
  if (cached_result != cached_requests.end()) {
    if (cached_result->second.state == CACHE_FETCHED) {
      return check_object(path, cached_result->second);
    }
    if (cached_result->second.state != CACHE_MISSING) {
      return cached_result->second.local_path;
    }
    return "s3://" + cached_result->second.local_path;
  } else {
    Cache cache{CACHE_NEEDS_FETCHING, GeneratePath(path)};
    // std::string result = check_object(path, cache);
    cached_requests.insert(std::make_pair("s3://" + path, cache));
    return cache.local_path;
  }
}

// Update asset info for resolved assets
// If the asset needs fetching, nothing is done as the cache is updated during
// the fetch phase If the asset doesn't need fetching, also do nothing (lol)
void S3::UpdateAssetInfo(const std::string& asset_path) {
  // const auto path = parse_path(asset_path);
  // const auto cached_result = cached_requests.find(path);
  // if (cached_result != cached_requests.end()) {
  //     //
  //     if (cached_result->second.state == CACHE_NEEDS_FETCHING) {
  //         return;
  //     }

  //     TF_DEBUG(S3_DBG).Msg("S3: update_asset_info %s cache state %d\n",
  //     path.c_str(), cached_result->second.state);
  //     //cached_result->second.state = CACHE_NEEDS_FETCHING;
  //     //cached_result->second.timestamp = INVALID_TIME;
  //     //check_object(path, cached_result->second);
  // }
}

// Fetch an asset to a local path
// The asset should be resolved first and exist in the cache
bool S3::FetchAsset(const std::string& asset_path,
                    const std::string& local_path) {
  const auto path = ParsePath(asset_path);
  if (s3_client == nullptr) {
    return false;
  }

  const auto cached_result = cached_requests.find(path);
  if (cached_result == cached_requests.end()) {
    S3_WARN("[S3Resolver] %s was not resolved before fetching!", path.c_str());
    return false;
  }

  if (cached_result->second.state == CACHE_NEEDS_FETCHING) {
    cached_result->second.state =
        CACHE_MISSING;  // we'll set this up if fetching is successful
    bool success = fetch_object(path, cached_result->second);
    return success;
  }
  return true;
}

// returns true if the path matches the S3 schema
bool S3::MatchesSchema(const std::string& path) {
  constexpr auto schema_length_short = cexpr_strlen(usd_s3::S3_PREFIX_SHORT);
  return path.compare(0, schema_length_short, usd_s3::S3_PREFIX_SHORT) == 0;
}

// returns the timestamp of the local cached asset
double S3::GetTimestamp(const std::string& asset_path) {
  const auto path = ParsePath(asset_path);
  if (s3_client == nullptr) {
    return 1.0;
  }

  const auto cached_result = cached_requests.find(path);
  if (cached_result == cached_requests.end() ||
      cached_result->second.state == CACHE_MISSING) {
    S3_WARN("[S3Resolver] %s is missing when querying timestamps!",
            path.c_str());
    return 1.0;
  } else {
    return cached_result->second.timestamp;
  }
}

// refresh all assets with this prefix
void S3::Refresh(const std::string& prefix) {
  if (prefix.empty()) {
    // refresh all assets
    cached_requests.clear();
  } else {
    // and reload based on S3 list operation with prefix
    cached_requests.clear();
  }
}

}  // namespace usd_s3

ext: cc


text: #include <boost/locale/boundary/types.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
// Copyright Cromwell D. Enage 2019.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_PARAMETER_COMPOSE_HPP
#define BOOST_PARAMETER_COMPOSE_HPP

#include <boost/parameter/aux_/arg_list.hpp>

namespace boost { namespace parameter {

    inline BOOST_CONSTEXPR ::boost::parameter::aux::empty_arg_list compose()
    {
        return ::boost::parameter::aux::empty_arg_list();
    }
}} // namespace boost::parameter

#include <boost/parameter/config.hpp>

#if defined(BOOST_PARAMETER_HAS_PERFECT_FORWARDING)

namespace boost { namespace parameter { namespace aux {

#if defined(BOOST_PARAMETER_CAN_USE_MP11)
    template <typename ...TaggedArgs>
    struct compose_arg_list
    {
        using type = ::boost::parameter::aux::flat_like_arg_list<
            ::boost::parameter::aux::flat_like_arg_tuple<
                typename TaggedArgs::base_type::key_type
              , typename TaggedArgs::base_type
            >...
        >;
    };
#else   // !defined(BOOST_PARAMETER_CAN_USE_MP11)
    template <typename TaggedArg0, typename ...TaggedArgs>
    struct compose_arg_list;

    template <typename TaggedArg0>
    struct compose_arg_list<TaggedArg0>
    {
        typedef ::boost::parameter::aux::arg_list<TaggedArg0> type;
    };

    template <typename TaggedArg0, typename ...TaggedArgs>
    struct compose_arg_list
    {
        typedef ::boost::parameter::aux::arg_list<
            TaggedArg0
          , typename ::boost::parameter::aux
            ::compose_arg_list<TaggedArgs...>::type
        > type;
    };
#endif  // BOOST_PARAMETER_CAN_USE_MP11
}}} // namespace boost::parameter::aux

#include <boost/parameter/are_tagged_arguments.hpp>
#include <boost/core/enable_if.hpp>

namespace boost { namespace parameter { namespace result_of {

    template <typename ...TaggedArgs>
    struct compose
      : ::boost::lazy_enable_if<
            ::boost::parameter::are_tagged_arguments<TaggedArgs...>
          , ::boost::parameter::aux::compose_arg_list<TaggedArgs...>
        >
    {
    };

    template <>
    struct compose<>
    {
        typedef ::boost::parameter::aux::empty_arg_list type;
    };
}}} // namespace boost::parameter::result_of

namespace boost { namespace parameter {

    template <typename TaggedArg0, typename ...TaggedArgs>
    inline BOOST_CONSTEXPR typename ::boost::parameter::result_of
    ::compose<TaggedArg0,TaggedArgs...>::type
        compose(TaggedArg0 const& arg0, TaggedArgs const&... args)
    {
        return typename ::boost::parameter::aux
        ::compose_arg_list<TaggedArg0,TaggedArgs...>::type(
            ::boost::parameter::aux::value_type_is_not_void()
          , arg0
          , args...
        );
    }
}} // namespace boost::parameter

#else   // !defined(BOOST_PARAMETER_HAS_PERFECT_FORWARDING)

#define BOOST_PARAMETER_compose_arg_list_type_suffix(z, n, suffix) suffix

#include <boost/preprocessor/cat.hpp>

#define BOOST_PARAMETER_compose_arg_list_type_prefix(z, n, prefix)           \
    ::boost::parameter::aux::arg_list<BOOST_PP_CAT(prefix, n)
/**/

#include <boost/preprocessor/facilities/intercept.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>

#define BOOST_PARAMETER_compose_arg_list_type(z, n, prefix)                  \
    BOOST_PP_CAT(BOOST_PP_ENUM_, z)(                                         \
        n, BOOST_PARAMETER_compose_arg_list_type_prefix, prefix              \
    ) BOOST_PP_CAT(BOOST_PP_REPEAT_, z)(                                     \
        n, BOOST_PARAMETER_compose_arg_list_type_suffix, >                   \
    )
/**/

#include <boost/parameter/aux_/void.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>

#if defined(BOOST_NO_SFINAE)
#define BOOST_PARAMETER_compose_arg_list_function_overload(z, n, prefix)     \
    template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename prefix)>                 \
    inline BOOST_CONSTEXPR                                                   \
    BOOST_PARAMETER_compose_arg_list_type(z, n, prefix)                      \
        compose(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, prefix, const& a))       \
    {                                                                        \
        return BOOST_PARAMETER_compose_arg_list_type(z, n, prefix)(          \
            BOOST_PP_ENUM_PARAMS_Z(z, n, a)                                  \
            BOOST_PP_ENUM_TRAILING_PARAMS_Z(                                 \
                z                                                            \
              , BOOST_PP_SUB(BOOST_PARAMETER_COMPOSE_MAX_ARITY, n)           \
              , ::boost::parameter::aux::void_reference() BOOST_PP_INTERCEPT \
            )                                                                \
        );                                                                   \
    }
/**/
#else   // !defined(BOOST_NO_SFINAE)
#include <boost/parameter/are_tagged_arguments.hpp>
#include <boost/core/enable_if.hpp>

namespace boost { namespace parameter { namespace result_of {

    template <
        BOOST_PP_ENUM_BINARY_PARAMS(
            BOOST_PP_INC(BOOST_PARAMETER_COMPOSE_MAX_ARITY)
          , typename TaggedArg
          , = void BOOST_PP_INTERCEPT
        )
    >
    struct compose;

    template <>
    struct compose<>
    {
        typedef ::boost::parameter::aux::empty_arg_list type;
    };
}}} // namespace boost::parameter::result_of

#define BOOST_PARAMETER_compose_arg_list_function_overload(z, n, prefix)     \
namespace boost { namespace parameter { namespace result_of {                \
    template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename prefix)>                 \
    struct compose<BOOST_PP_ENUM_PARAMS_Z(z, n, prefix)>                     \
      : ::boost::enable_if<                                                  \
            ::boost::parameter                                               \
            ::are_tagged_arguments<BOOST_PP_ENUM_PARAMS_Z(z, n, prefix)>     \
          , BOOST_PARAMETER_compose_arg_list_type(z, n, prefix)              \
        >                                                                    \
    {                                                                        \
    };                                                                       \
}}}                                                                          \
namespace boost { namespace parameter {                                      \
    template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename prefix)>                 \
    inline BOOST_CONSTEXPR typename ::boost::parameter::result_of            \
    ::compose<BOOST_PP_ENUM_PARAMS_Z(z, n, prefix)>::type                    \
        compose(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, prefix, const& a))       \
    {                                                                        \
        return BOOST_PARAMETER_compose_arg_list_type(z, n, prefix)(          \
            BOOST_PP_ENUM_PARAMS_Z(z, n, a)                                  \
            BOOST_PP_ENUM_TRAILING_PARAMS_Z(                                 \
                z                                                            \
              , BOOST_PP_SUB(BOOST_PARAMETER_COMPOSE_MAX_ARITY, n)           \
              , ::boost::parameter::aux::void_reference() BOOST_PP_INTERCEPT \
            )                                                                \
        );                                                                   \
    }                                                                        \
}}
/**/
#endif  // BOOST_NO_SFINAE

#include <boost/preprocessor/repetition/repeat_from_to.hpp>

BOOST_PP_REPEAT_FROM_TO(
    1
  , BOOST_PP_INC(BOOST_PARAMETER_COMPOSE_MAX_ARITY)
  , BOOST_PARAMETER_compose_arg_list_function_overload
  , TaggedArg
)

#undef BOOST_PARAMETER_compose_arg_list_function_overload
#undef BOOST_PARAMETER_compose_arg_list_type
#undef BOOST_PARAMETER_compose_arg_list_type_prefix
#undef BOOST_PARAMETER_compose_arg_list_type_suffix

#endif  // BOOST_PARAMETER_HAS_PERFECT_FORWARDING
#endif  // include guard


text:
/*
 *
 * 	NN4MC Main Code:
 *
 *   This code takes in the user inputs and generates
 *   	the neural network code through command terminal
 *   	inputs.
 */

#include <iostream>
#include <vector>
#include <cstdlib>
#include "parser/h5_parser.h"
#include "datastructures/tensor.h"
#include "generator/weight_generator.h"
#include "datastructures/weights.h"
#include "generator/layer_generator.h"
#include "generator/code_generator.h"
#include "datastructures/Layer.h"
#include "datastructures/NeuralNetwork.h"
#include <boost/program_options.hpp>
#include <exception>
#include <string>

using namespace boost::program_options;

void print_help_options(options_description opt){
	std::cout << opt << std::endl;
}

int main(int argc, const char *argv[])
{
    // Parsing arguments:
    try{
        options_description options{"NN4MC Options"};
        options.add_options()
            ("help,h", "help screen")
            ("source,s", value<std::string>(), "name of the hdf5 file")
            ("target,t", value<std::string>(), "name of the target folder the code will be offloaded")
            ("verbose,v",value<bool>()->default_value(true), "print neural network configuration json")
	;
        variables_map vm;
        store(parse_command_line(argc, argv, options), vm);
        notify(vm);

        if (vm.count("help") || vm.count("h")){
       		print_help_options(options);
	} else if (vm.count("source") || vm.count("s")){
 	    HDF5Parser P(vm["source"].as<std::string>());

	    P.parse();

	    NeuralNetwork* NN = P.get_neural_network();

	    NeuralNetwork::iterator it;

	    NN->reset();

	    CodeGenerator* code_gen = new CodeGenerator(NN, "templates/c_standard", vm["target"].as<std::string>());
	    code_gen->generate();
	    code_gen->dump();

	    delete NN;
	    delete code_gen;
	}
    }
    catch (std::exception& ex){
   	std::cerr << ex.what() << "\n";
    }
    return 0;
}


text:
/*
Copyright 2011 Ryan Fobel, 2013 Christian Fobel

This file is part of dmf_control_board.

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

dmf_control_board 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with dmf_control_board.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "RemoteObject.h"

#if defined(AVR)
  #include <util/crc16.h>
  #include <AdvancedADC.h>
#endif
#if defined(AVR) || defined(__SAM3X8E__)
  #include "Arduino.h"
  #include <Wire.h>
  #include <SPI.h>
  #include <OneWire.h>
  #ifdef AVR
    #include <AdvancedADC.h>
    #include <EEPROM.h>
  #elif defined(__SAM3X8E__)
    #include <DueFlashStorage.h>
    extern DueFlashStorage EEPROM;
  #endif
  extern "C" void __cxa_pure_virtual(void); // These declarations are needed for
  void __cxa_pure_virtual(void) {}          // virtual functions on the Arduino.
#else
  #include <string>
  #include <boost/thread.hpp>
  #include <boost/timer.hpp>
  #include <boost/date_time/posix_time/posix_time_types.hpp>
  #include <boost/format.hpp>
  #include <exception>
  using namespace std;
  using boost::format;
#endif

#ifdef __SAM3X8E__
  const char RemoteObject::MCU_TYPE_[] = "SAM3X8E";
#else
  const char RemoteObject::MCU_TYPE_[] = "ATmega2560";
#endif // __SAM3X8E__

RemoteObject::RemoteObject(bool crc_enabled
#if !( defined(AVR) || defined(__SAM3X8E__) )
                           ,const char* class_name //used for logging
#endif
                           ) : crc_enabled_(crc_enabled)
#if !( defined(AVR) || defined(__SAM3X8E__) )
                               ,class_name_(class_name)
#endif
                               {
    bytes_received_ = 0;
    un_escaping_ = false;
    payload_length_ = 0;
    bytes_read_ = 0;
    bytes_written_ = 0;
    debug_ = false;

#if defined(AVR) || defined(__SAM3X8E__)
    // Initialize pin mode and state of digital pins from persistent storage
    // _(i.e., EEPROM on AVR)_.
    for (uint8_t i = 0; i <= 54 / 8; i++) {
        uint8_t mode = persistent_read(PERSISTENT_PIN_MODE_ADDRESS + i);
        uint8_t state = persistent_read(PERSISTENT_PIN_STATE_ADDRESS + i);
        for (uint8_t j = 0; j < 8; j++) {
            if (i * 8 + j < 54) {
                pinMode(i * 8 + j, (~mode >> j) & 0x01);
                digitalWrite(i * 8 + j, (~state >> j) & 0x01);
            }
        }
    }
#endif
}

RemoteObject::~RemoteObject() {}

void RemoteObject::send_byte(const uint8_t b) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
    const char* function_name = "send_byte()";
#endif
    if (b == FRAME_BOUNDARY || b == CONTROL_ESCAPE) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
        log_message(str(format("write escape (0x%0X)") % (int)b).c_str(),
                    function_name);
#endif
        Serial.write(CONTROL_ESCAPE);
        Serial.write(b ^ ESCAPE_XOR);
    } else {
#if !( defined(AVR) || defined(__SAM3X8E__) )
        log_message(str(format("write (0x%0X)") % (int)b).c_str(),
                    function_name);
#endif
        Serial.write(b);
    }
}

uint16_t RemoteObject::update_crc(uint16_t crc, uint8_t data) {
#if defined(AVR)
  crc = _crc16_update(crc,data);
#else
  crc ^= data;
  for (uint8_t i=0; i<8; i++) {
    if (crc & 1) {
      crc = (crc >> 1) ^ 0xA001;
    } else {
      crc = (crc >> 1);
    }
  }
#endif
  return crc;
}

void RemoteObject::send_preamble(const uint8_t cmd) {
  payload_length_ = bytes_written_;
#if !( defined(AVR) || defined(__SAM3X8E__) )
  const char* function_name = "send_preamble()";
  log_message(str(format("command=0x%0X (%d), payload_length=%d") %
    (int)cmd % (int)cmd % payload_length_).c_str(), function_name);
#endif
  Serial.write(FRAME_BOUNDARY);
  if (crc_enabled_) {
    tx_crc_ = 0xFFFF; // reset crc
    tx_crc_ = update_crc(tx_crc_, cmd);
  }
  send_byte(cmd);
  if (payload_length_<128) {
    if (crc_enabled_) {
      tx_crc_ = update_crc(tx_crc_, (uint8_t)payload_length_);
    }
    send_byte((uint8_t)payload_length_);
  } else {
    if (crc_enabled_) {
      tx_crc_ = update_crc(tx_crc_, (uint8_t)((0x8000|payload_length_)>>8));
      tx_crc_ = update_crc(tx_crc_, (uint8_t)payload_length_);
    }
    send_byte((uint8_t)((0x8000|payload_length_)>>8));
    send_byte((uint8_t)payload_length_);
  }
}

uint8_t RemoteObject::send_command(const uint8_t cmd) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
  const char* function_name = "send_command()";
  log_separator();
  log_message("",function_name);
#endif
  packet_cmd_ = cmd;
  send_preamble(cmd);
  send_payload();
  waiting_for_reply_to_ = cmd;
  return_code_ = wait_for_reply();
  return return_code_;
}

void RemoteObject::send_non_blocking_command(const uint8_t cmd) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
  const char* function_name = "send_non_blocking_command()";
  log_separator();
  log_message("", function_name);
#endif
  packet_cmd_ = cmd;
  send_preamble(cmd);
  send_payload();
  waiting_for_reply_to_ = cmd;
}

void RemoteObject::send_interrupt() {
  // send a dummy byte
  send_byte(0);
}

void RemoteObject::serialize(const uint8_t* u,const uint16_t size) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
  const char* function_name = "serialize()";
  log_message(str(format("%d bytes.") % size).c_str(), function_name);
#endif
  //TODO check that MAX_PAYLOAD_LENGTH isn't exceeded
  for (uint16_t i = 0; i < size; i++) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
    log_message(str(format("(0x%0X) byte %d") % int(u[i]) % i).c_str(),
      function_name);
#endif
    payload_[bytes_written_+i] = u[i];
  }
  bytes_written_ += size;
}

void RemoteObject::send_payload() {
#if !( defined(AVR) || defined(__SAM3X8E__) )
  const char* function_name = "send_payload()";
  log_message(str(format("%d bytes") % payload_length_).c_str(), function_name);
#endif
  for (uint16_t i = 0; i < payload_length_; i++) {
    if (crc_enabled_) {
      tx_crc_ = update_crc(tx_crc_, payload_[i]);
    }
    send_byte(payload_[i]);
  }
  if (crc_enabled_) {
    send_byte((uint8_t)tx_crc_);
    send_byte((uint8_t)(tx_crc_>>8));
  }
  payload_length_ = 0;
  bytes_written_ = 0;
}

void RemoteObject::send_reply(uint8_t return_code) {
  serialize(&return_code,1);
  send_preamble(packet_cmd_);
  send_payload();
}

const char* RemoteObject::read_string() {
  // TODO check that we're not reading past the end of the buffer
  uint8_t length = strlen((const char*)payload_)+1;
  bytes_read_ += length;
#if !( defined(AVR) || defined(__SAM3X8E__) )
  const char* function_name = "read_string()";
  log_message(str(format("=\"%s\", bytes_read_=%d") %
    (const char*)(payload_+bytes_read_-length) % bytes_read_).c_str(),
    function_name);
#endif
  return (const char*)(payload_+bytes_read_-length);
}

uint8_t RemoteObject::wait_for_reply() {
#if !( defined(AVR) || defined(__SAM3X8E__) )
  const char* function_name = "wait_for_reply()";
  log_message("", function_name);
  time_cmd_sent_ = boost::posix_time::microsec_clock::universal_time();
  uint8_t cmd = packet_cmd_;
#endif
  while (waiting_for_reply_to_) {
    listen();
#if !( defined(AVR) || defined(__SAM3X8E__) )
    if ((boost::posix_time::microsec_clock::universal_time()
       -time_cmd_sent_).total_milliseconds()>TIMEOUT_MILLISECONDS) {
      return_code_ = RETURN_TIMEOUT;
      throw runtime_error(str(format("Command 0x%0X (%d) timeout.") %
        (int)cmd % (int)cmd).c_str());
    }
#endif
  }
#if !( defined(AVR) || defined(__SAM3X8E__) )
  log_message(str(format("return code=%d, cmd returned in %d us") %
    (int)return_code_ % (boost::posix_time::microsec_clock::universal_time()
    -time_cmd_sent_).total_microseconds()).c_str(), function_name);
  if (return_code_!=RETURN_OK) {
    throw runtime_error(str(format("Error sending command 0x%0X (%d). "
        "Return code=%d.") % (int)cmd % (int)cmd % (int)return_code_).c_str());
  }
#endif
  return return_code_;
}

uint8_t RemoteObject::validate_reply(const uint8_t cmd) {
  if (wait_for_reply() == RETURN_OK) {
    if (cmd!=(packet_cmd_^0x80)) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
      throw runtime_error(str(format("Requesting for data from command 0x%0X "
        "(%d), but the previously sent command was 0x%0X (%d).") % int(cmd) %
        int(cmd) % int(packet_cmd_) % int(packet_cmd_)).c_str());
#endif
      return RETURN_GENERAL_ERROR;

    // if we've previously read bytes from the buffer, throw an error
    } else if (bytes_read()) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
      throw runtime_error("Data from this command has already been retrieved.");
#endif
      return RETURN_GENERAL_ERROR;
    }
  }
  return return_code_;
}

void RemoteObject::process_packet() {
    if (packet_cmd_ & 0x80) {
        /* Commands have MSB == 1, so this packet contains a command.  Start
         * preparing the response and process the command. */

        // Flip the MSB for reply
        packet_cmd_ = packet_cmd_ ^ 0x80;
        return_code_ = RETURN_UNKNOWN_COMMAND;
        process_command(packet_cmd_ ^ 0x80);
#if !( defined(AVR) || defined(__SAM3X8E__) )
        log_separator();
#endif
    } else {
        // This packet does not contain a command, so assume it is a response.
        return_code_ = payload_[payload_length_ - 1];
        /* Decrement the payload-length because we've already read the return
         * code (which was included in the payload-length). */
        payload_length_--;
#if !( defined(AVR) || defined(__SAM3X8E__) )
        const char* function_name = "process_packet()";
        log_message(str(format("(0x%0X). This packet is a reply to command "
                              "(%d)") % (packet_cmd_ ^ 0x80) %
                              (packet_cmd_^0x80)).c_str(), function_name);
        log_message(str(format("Return code=%d") % (int)return_code()).c_str(),
                              function_name);
        log_message(str(format("Payload length=%d") % payload_length()).c_str(),
                              function_name);
        log_separator();
#endif
    }
}

uint8_t RemoteObject::process_command(uint8_t cmd) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
  const char* function_name = "process_command()";
  log_message(str(format("command=0x%0X (%d)") % cmd % cmd).c_str(),
              function_name);
#endif
  switch(cmd) {
#if defined(AVR) || defined(__SAM3X8E__) // Commands that only the Arduino handles
    case CMD_GET_PROTOCOL_NAME:
      if (payload_length() == 0) {
        serialize(protocol_name(), strlen(protocol_name()));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_PROTOCOL_VERSION:
      if (payload_length() == 0) {
        serialize(protocol_version(), strlen(protocol_version()));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_DEVICE_NAME:
      if (payload_length() == 0) {
        serialize(name(), strlen(name()));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_MANUFACTURER:
      if (payload_length() == 0) {
        serialize(manufacturer(), strlen(manufacturer()));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_SOFTWARE_VERSION:
      if (payload_length() == 0) {
        serialize(software_version(), strlen(software_version()));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_HARDWARE_VERSION:
      if (payload_length() == 0) {
        serialize(hardware_version(), strlen(hardware_version()));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_URL:
      if (payload_length() == 0) {
        serialize(url(), strlen(url()));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_MCU_TYPE:
      if (payload_length() == 0) {
        serialize(MCU_TYPE_, strlen(MCU_TYPE_));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_SET_PIN_MODE:
      if (payload_length() == 2) {
        uint8_t pin = read<uint8_t>();
        uint8_t mode = read<uint8_t>();
        pinMode(pin, mode);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_DIGITAL_WRITE:
      if (payload_length() == 2) {
        uint8_t pin = read<uint8_t>();
        uint8_t value = read<uint8_t>();
        digitalWrite(pin, value);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_DIGITAL_READ:
      if (payload_length() == 1) {
        uint8_t pin = read<uint8_t>();
        uint8_t value = digitalRead(pin);
        serialize(&value,sizeof(value));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_ANALOG_WRITE:
      if (payload_length() == 2) {
        uint8_t pin =  read<uint8_t>();
        uint16_t value = read<uint16_t>();
        analogWrite(pin, value);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_ANALOG_READ:
      uint8_t n_channels;
      uint16_t n_samples;
      return_code_ = RETURN_BAD_PACKET_SIZE;
      if (payload_length() >= 2) {
        n_channels = read<uint8_t>();
        uint8_t pins[n_channels];
        if ( (payload_length() == 2 && n_channels == 1) ||
             (payload_length() == (1+n_channels)*sizeof(uint8_t) +
                 sizeof(uint16_t)) ) {
          for (uint8_t i = 0; i < n_channels; i++) {
            pins[i] = read<uint8_t>();
          }
          if (payload_length() == 2) {
            n_samples = 1;
          } else {
            n_samples = read<uint16_t>();
          }
          if (n_samples > (MAX_PAYLOAD_LENGTH)/sizeof(uint16_t)) {
            return_code_ = RETURN_MAX_PAYLOAD_EXCEEDED;
          } else {
            return_code_ = RETURN_OK;
            // perform analog reads
            AdvancedADC.setBuffer((uint16_t*)payload(), n_samples);
            AdvancedADC.setChannels(pins, n_channels);
            AdvancedADC.begin();
            while(!AdvancedADC.finished());
            // update the number of bytes written
            bytes_written(n_samples*sizeof(uint16_t));
          }
        }
      }
      break;
    case CMD_PERSISTENT_WRITE:
      if (payload_length() == 3) {
        uint16_t address = read<uint16_t>();
        uint8_t value = read<uint8_t>();
        persistent_write(address, value);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_PERSISTENT_READ:
      if (payload_length() == 2) {
        uint16_t address = read<uint16_t>();
        uint8_t value = persistent_read(address);
        serialize(&value,sizeof(value));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_ONEWIRE_GET_ADDRESS:
      if (payload_length() == 2) {
        uint8_t pin = read<uint8_t>();
        uint8_t index = read<uint8_t>();
        uint8_t addr[8];
        uint8_t ret;
        OneWire ow(pin);
        ow.reset_search();
        for (uint8_t i = 0; i <= index; i++) {
          ret = ow.search(addr);
        }
        if (ret) {
          serialize(addr, 8*sizeof(uint8_t));
          return_code_ = RETURN_OK;
        } else { // No more addresses
          return_code_ = RETURN_BAD_INDEX;
        }
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_ONEWIRE_READ:
      if (payload_length() == 11) {
        uint8_t pin = read<uint8_t>();
        uint8_t addr[8];
        for (uint8_t i = 0; i < 8; i++) {
          addr[i] = read<uint8_t>();
        }
        uint8_t command = read<uint8_t>();
        uint8_t n_bytes = read<uint8_t>();
        OneWire ow(pin);
        ow.reset();
        ow.select(addr);
        ow.write(command);
        for (uint8_t i = 0; i < n_bytes; i++) {
          uint8_t data = ow.read();
          serialize(&data, sizeof(uint8_t));
        }
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_ONEWIRE_WRITE:
      if (payload_length() == 11) {
        uint8_t pin = read<uint8_t>();
        uint8_t addr[8];
        for (uint8_t i = 0; i < 8; i++) {
          addr[i] = read<uint8_t>();
        }
        uint8_t value = read<uint8_t>();
        uint8_t power = read<uint8_t>();
        OneWire ow(pin);
        ow.reset();
        ow.select(addr);
        ow.write(value,power);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_I2C_READ:
      if (payload_length() == 2) {
        uint8_t n_bytes_read = 0;
        uint8_t address = read<uint8_t>();
        uint8_t n_bytes_to_read = read<uint8_t>();
        Wire.requestFrom(address, n_bytes_to_read);
        while (Wire.available()) {
          uint8_t data = Wire.read();
          serialize(&data, sizeof(uint8_t));
          n_bytes_read++;
        }
        if (n_bytes_read == n_bytes_to_read) {
          return_code_ = RETURN_OK;
        } else {
          return_code_ = RETURN_GENERAL_ERROR;
        }
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_I2C_WRITE:
      if (payload_length() >= 1) {
        uint8_t address = read<uint8_t>();
        Wire.beginTransmission(address);
        for (uint8_t i = 0; i < payload_length()-1; i++) {
          Wire.write(read<uint8_t>());
        }
        Wire.endTransmission();
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_SPI_SET_BIT_ORDER:
      if (payload_length() == 1) {
        uint8_t order = read<uint8_t>();
#ifdef __SAM3X8E__
        SPI.setBitOrder((BitOrder)order);
#else
        SPI.setBitOrder(order);
#endif
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_SPI_SET_CLOCK_DIVIDER:
      if (payload_length() == 1) {
        uint8_t divider = read<uint8_t>();
        SPI.setClockDivider(divider);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_SPI_SET_DATA_MODE:
      if (payload_length() == 1) {
        uint8_t mode = read<uint8_t>();
        SPI.setDataMode(mode);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_SPI_TRANSFER:
      if (payload_length() == 1) {
        uint8_t value = read<uint8_t>();
        uint8_t data = SPI.transfer(value);
        serialize(&data, sizeof(data));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_DEBUG_BUFFER:
      if (payload_length() == 0) {
        serialize(debug_buffer_, debug_buffer_length_);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
#endif
#ifdef AVR // only on Arduino Mega 2560
    case CMD_GET_SAMPLING_RATE:
      if (payload_length() == 0) {
        float sampling_rate = AdvancedADC.samplingRate();
        serialize(&sampling_rate, sizeof(sampling_rate));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_SET_SAMPLING_RATE:
      if (payload_length() == sizeof(float)) {
        float sampling_rate = read_float();
        AdvancedADC.setSamplingRate(sampling_rate);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_ADC_PRESCALER:
      if (payload_length() == 0) {
        uint16_t prescaler = AdvancedADC.prescaler();
        serialize(&prescaler, sizeof(prescaler));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_SET_ADC_PRESCALER:
      if (payload_length() == sizeof(uint16_t)) {
        uint16_t prescaler = read_uint16();
        if (prescaler >=2 && prescaler <= 7) {
          AdvancedADC.setPrescaler((uint8_t)prescaler);
          AdvancedADC.setAutoTrigger(false);
          return_code_ = RETURN_OK;
        } else {
          return_code_ = RETURN_BAD_INDEX;
        }
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_GET_AREF:
      if (payload_length() == 0) {
        serialize(&aref_, sizeof(aref_));
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
    case CMD_I2C_SCAN:
      if (payload_length() == 0) {
        i2c_scan(true);
        return_code_ = RETURN_OK;
      } else {
        return_code_ = RETURN_BAD_PACKET_SIZE;
      }
      break;
#endif
  }
  send_reply(return_code_);
  return return_code_;
}

void RemoteObject::process_serial_input(uint8_t byte) {
    /*
     * Process the next available _byte_ in the serial receive buffer.
     */
#if !( defined(AVR) || defined(__SAM3X8E__) )
    const char* function_name = "process_serial_input()";
#endif
    /* Since the packet grammar defined in `Remoteobject.h` reserves certain
     * byte values as special markers _(e.g., `start_flag`, `end_flag`), we
     * provide a mechanism to [escape][1] a reserved byte value, such that it
     * can be included in a packet's payload without disrupting the processing
     * of the packet.  To do this, we allow reserved byte values to be
     * prepended by an [escape character][1] with the value `CONTROL_ESCAPE`.
     *
     * [1]: http://en.wikipedia.org/wiki/Escape_character
     */
    if (byte == CONTROL_ESCAPE) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
        log_message(str(format("(0x%0X) Escape") % (int)byte).c_str(),
                              function_name);
#endif
        /* Update our state to indicate that we are currently processing an
         * [escape character][1] sequence and will need to return to normal
         * processing for the next byte.
         *
         * [1]: http://en.wikipedia.org/wiki/Escape_character
         */
        un_escaping_ = true;
        return;
    } else if (un_escaping_) {
        /* TODO: What does `ESCAPE_XOR` do? */
        byte ^= ESCAPE_XOR;
#if !( defined(AVR) || defined(__SAM3X8E__) )
        log_message(str(format("(0x%0X) Un-escaping") % (int)byte).c_str(),
                              function_name);
#endif
    }

    if (byte == FRAME_BOUNDARY && !un_escaping_) {
        /* The current byte marks a frame-boundary, since it matches the
         * `start_flag` or `end_flag` of the packet grammar defined in
         * `Remoteobject.h`.
         *
         * __NB__ If `un_escaping_` is `true`, it would indicate that the
         * previous byte was an [escape character][1] and that the current byte
         * has been XOR'ed with `ESCAPE_XOR` to ensure it does not conflict
         * with one of the reserved byte values.  Therefore, if the previous
         * character was an escape character and the current byte _(which has
         * been XOR'ed with `ESCAPE_XOR`)_ is equal to the `FRAME_BOUNDARY`, we
         * should not actually treat it as a `FRAME_BOUNDARY`.
         *
         * [1]: http://en.wikipedia.org/wiki/Escape_character
         */
#if !( defined(AVR) || defined(__SAM3X8E__) )
        log_separator();
        log_message(str(format("(0x%0X) Frame Boundary") % (int)byte).c_str(),
                              function_name);
#endif
        if (bytes_received_ > 0) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
            /* Since our current processing state indicates that we have
             * already received some bytes, we are not expecting a
             * `FRAME_BOUNDARY`, so log the packet as invalid.
             */
            log_message(str(format("(0x%0X) Invalid packet") %
                (int)byte).c_str(), function_name);
#endif
        }
        bytes_received_ = 0;
    } else {
        if (bytes_received_ == 0) { // command byte
#if !( defined(AVR) || defined(__SAM3X8E__) )
            log_message(str(format("(0x%0X) Command byte (%d)") % (int)byte %
                                  (int)byte).c_str(), function_name);
#endif
            packet_cmd_ = byte;
            if (crc_enabled_) {
                rx_crc_ = 0xFFFF; // reset the crc
            }
        } else if (bytes_received_ == 1) { // payload length
            if (byte & 0x80) {
                header_length_ = 3;
                payload_length_ = (byte & 0x7F) << 8;
            } else {
                header_length_ = 2;
                payload_length_ = byte;
            }
        // payload length (byte 2)
        } else if (bytes_received_ == 2 && header_length_ == 3) {
            payload_length_ += byte;
        } else if (bytes_received_ - header_length_ < payload_length_) {
            // payload
            // TODO: check that MAX_PAYLOAD_LENGTH isn't exceeded
            payload_[bytes_received_ - header_length_] = byte;
        } else if (bytes_received_ - header_length_ < payload_length_ + 2) {
            // crc
        } else {
          // TODO: error
        }
#if !( defined(AVR) || defined(__SAM3X8E__) )
        if (bytes_received_ == header_length_) {
            /* We've received all header bytes, so we can report the
             * payload-length _(which was included in the packet header)_. */
            log_message(str(format("Payload length=%d") %
                        payload_length_).c_str(), function_name);
        }
#endif
        if (crc_enabled_) {
            /* CRC is enabled, so update the CRC-checksum with the current
             * byte. */
            rx_crc_ = update_crc(rx_crc_, byte);
        }
        bytes_received_++;
#if !( defined(AVR) || defined(__SAM3X8E__) )
        if (byte >= 0x20 && byte <= 0x7E) {
            /* The byte value is within the [ASCII][1] character range, so
             * display the corresponding character.
             *
             * [1]: http://www.asciitable.com */
            log_message(str(format("(0x%0X) %d bytes received (\'%c\')") %
                        (int)byte % bytes_received_ % byte).c_str(),
                        function_name);
        } else {
            log_message(str(format("(0x%0X) %d bytes received") % (int)byte %
                                  bytes_received_).c_str(), function_name);
        }
#endif
        if (bytes_received_ ==
            payload_length_ + header_length_ + 2 * crc_enabled_) {
            /* We have read the number of bytes that make up a packet,
             * according to the grammar defined in `RemoteObject.h`, so process
             * the packet contents.
             *
             * __NB__ Recall that the length of a packet varies according to
             * whether or not a CRC-value is provided.  This is taken into
             * account here by including the `2 * crc_enabled_` term in the
             * condition above.  In the case where CRC-checking is not enabled,
             * the term will evaluate to 0.
             */
            bytes_received_ = 0;
            bytes_read_ = 0;
            bytes_written_ = 0;
            if (crc_enabled_) {
                /* CRC checking is enabled, so verify that the CRC matches the
                 * CRC value sent in the packet. */
                if (rx_crc_ == 0) {
#if !( defined(AVR) || defined(__SAM3X8E__) )
                    log_message("End of Packet. CRC OK.", function_name);
#endif
                    process_packet();
                } else {
#if !( defined(AVR) || defined(__SAM3X8E__) )
                    log_message("End of Packet. CRC Error.", function_name);
#endif
                }
            } else {
                /* CRC checking is not enabled, so just proceed with processing
                 * the packet contents. */
#if !( defined(AVR) || defined(__SAM3X8E__) )
                log_message("End of Packet", function_name);
#endif
                process_packet();
            }
#if !( defined(AVR) || defined(__SAM3X8E__) )
            log_separator();
#endif
            // If we're not expecting something else, stop waiting
            if (waiting_for_reply_to_ &&
                packet_cmd_ == (waiting_for_reply_to_ ^ 0x80)) {
                waiting_for_reply_to_ = 0;
            }
#if !( defined(AVR) || defined(__SAM3X8E__) )
            else {
                log_message("Not the expected reply, keep waiting.",
                            function_name);
            }
#endif
        }
    }
    if (un_escaping_) {
        /* If we were handling the escaping of a byte, reset the escaping state
         * to resume normal packet processing. */
        un_escaping_ = false;
    }
}

void RemoteObject::listen() {
    while (Serial.available() > 0) {
        process_serial_input(Serial.read());
    }
}

#if defined(AVR) || defined(__SAM3X8E__)
////////////////////////////////////////////////////////////////////////////////
//
// These functions are only defined on the Arduino
//
////////////////////////////////////////////////////////////////////////////////

void /* DEVICE */ RemoteObject::begin() {
  uint32_t baud_rate;
  for (uint8_t i = 0; i < 4; i++) {
    ((uint8_t*)&baud_rate)[i] = persistent_read(PERSISTENT_BAUD_RATE_ADDRESS
                                                + i);
  }
  // if the baud rate hasn't been set (default is that all bits are high)
  if (baud_rate == 0xFFFFFFFF) {
    baud_rate = 115200;
    // write the baud_rate to eeprom
    for (uint8_t i = 0; i < 4; i++) {
      persistent_write(PERSISTENT_BAUD_RATE_ADDRESS + i,
        ((uint8_t*)&baud_rate)[i]);
    }
  }
  Serial.begin(baud_rate);
  Wire.begin();
  SPI.begin();

  aref_ = AdvancedADC.readVcc();
  Serial.print("Analog Reference=");
  Serial.print(aref_);
  Serial.println(" V");
}

void /* DEVICE */ RemoteObject::i2c_scan(bool serialize_to_payload) {
  for (uint8_t i = 8; i < 120; i++) {
    Wire.beginTransmission(i);
    if (Wire.endTransmission() == 0) {
      if (serialize_to_payload) {
        serialize(&i, sizeof(i));
      }
      Serial.print("Found i2c address: ");
      Serial.print(i, DEC);
      Serial.print(" (0x");
      Serial.print(i, HEX);
      Serial.println (")");
      delay(1);  // maybe unneeded?
    }
  }
}

void /* DEVICE */ RemoteObject::i2c_write(const uint8_t address,
                                          const uint8_t data) {
    Wire.beginTransmission(address);
    Wire.write(data);
    Wire.endTransmission();
}

void /* DEVICE */ RemoteObject::i2c_write(const uint8_t address,
                                          const uint8_t* data,
                                          const uint8_t n_bytes) {
    Wire.beginTransmission(address);
    for (uint8_t i = 0; i < n_bytes; i++) {
        Wire.write(data[i]);
    }
    Wire.endTransmission();
}

uint8_t /* DEVICE */ RemoteObject::i2c_read(const uint8_t address,
                                            uint8_t* data,
                                            const uint8_t n_bytes_to_read) {
    uint8_t n_bytes_read = 0;
    Wire.requestFrom(address, n_bytes_to_read);
    while (Wire.available()) {
        data[n_bytes_read++] = Wire.read();
    }
    return n_bytes_read;
}

uint8_t /* HOST */ RemoteObject::persistent_read(uint16_t address) {
    return EEPROM.read(address);
}

void /* HOST */ RemoteObject::persistent_write(uint16_t address,
                                               uint8_t value) {
    EEPROM.write(address, value);
}

#else
////////////////////////////////////////////////////////////////////////////////
//
// These functions are only defined on the PC
//
////////////////////////////////////////////////////////////////////////////////

uint8_t /* HOST */ RemoteObject::connect(const char* port,
                                         uint32_t baud_rate) {
  const char* function_name = "connect()";
  int return_code = Serial.begin(port, baud_rate);

  // wait up to 10 s for the Arduino to send something on the
  // serial port so that we know it's ready
  if (return_code == 0) {
    boost::posix_time::ptime t =
      boost::posix_time::microsec_clock::universal_time();
    while (Serial.available()==false && \
      (boost::posix_time::microsec_clock::universal_time()-t)
      .total_seconds()<10) {
    }
    // flush the serial buffer to clear startup message
    while (Serial.available()) {
      // This delay needs to be >=500 ms for R2 and R3 boards. Use 1000 ms to
      // be safe.
      boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
      Serial.flush();
    }
  }
  log_message(str(format("Serial.begin(%s, %d)=%d") % port % baud_rate %
    return_code).c_str(), function_name);

  if (return_code == 0) {
    // verify that the device name and hardware version are correct
    std::string remote_name;
    std::string remote_hardware_version;
    try {
      remote_name = name();
      remote_hardware_version = hardware_version();
    } catch(...) {
      // close the Serial port if we can't get a name/version
      Serial.end();
      throw;
    }
    log_message(str(format("name()=\"%s\", hardware_version()=\"%s\"") %
      remote_name % remote_hardware_version).c_str(), function_name);
    if (remote_name == host_name()) {
      return RETURN_OK;
    } else {
      Serial.end();
      throw runtime_error(str(format("Remote device is not a %s.") %
        host_name()).c_str());
    }
  }
  throw runtime_error(str(format("Could not connect to port %s.") %
    port).c_str());
}

void /* HOST */ RemoteObject::set_debug(const bool debug) {
  debug_ = debug;
}

string /* HOST */ RemoteObject::protocol_name() {
  const char* function_name = "protocol_name()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_PROTOCOL_NAME) == RETURN_OK) {
    string protocol_name = read_string();
    log_message(str(format("protocol_name=%s") % protocol_name).c_str(),
      function_name);
    return protocol_name;
  }
  return "";
}

string /* HOST */ RemoteObject::protocol_version() {
  const char* function_name = "protocol_version()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_PROTOCOL_VERSION) == RETURN_OK) {
    string protocol_version = read_string();
    log_message(str(format("protocol_version=%s") % protocol_version).c_str(),
      function_name);
    return protocol_version;
  }
  return "";
}

string /* HOST */ RemoteObject::name() {
  const char* function_name = "name()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_DEVICE_NAME) == RETURN_OK) {
    string name = read_string();
    log_message(str(format("name=%s") % name).c_str(), function_name);
    return name;
  }
  return "";
}

string /* HOST */ RemoteObject::manufacturer() {
  const char* function_name = "manufacturer()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_MANUFACTURER) == RETURN_OK) {
    string manufacturer = read_string();
    log_message(str(format("manufacturer=%s") % manufacturer).c_str(),
      function_name);
    return manufacturer;
  }
  return "";
}

string /* HOST */ RemoteObject::software_version() {
  const char* function_name = "software_version()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_SOFTWARE_VERSION) == RETURN_OK) {
    string software_version = read_string();
    log_message(str(format("software_version=%s") % software_version).c_str(),
      function_name);
    return software_version;
  }
  return "";
}

string /* HOST */ RemoteObject::hardware_version() {
  const char* function_name = "hardware_version()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_HARDWARE_VERSION) == RETURN_OK) {
    string hardware_version = read_string();
    log_message(str(format("hardware_version=%s") % hardware_version).c_str(),
      function_name);
    return hardware_version;
  }
  return "";
}

string /* HOST */ RemoteObject::url() {
  const char* function_name = "url()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_URL) == RETURN_OK) {
    string url = read_string();
    log_message(str(format("url=%s") % url).c_str(), function_name);
    return url;
  }
  return "";
}

string /* HOST */ RemoteObject::mcu_type() {
  const char* function_name = "mcu_type()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_MCU_TYPE) == RETURN_OK) {
    string mcu_type = read_string();
    log_message(str(format("mcu_type=%s") % mcu_type).c_str(),
      function_name);
    return mcu_type;
  }
  return "";
}

void /* HOST */ RemoteObject::set_pin_mode(uint8_t pin, bool mode) {
  const char* function_name = "set_pin_mode()";
  log_separator();
  log_message("send command", function_name);
  serialize(&pin,sizeof(pin));
  uint8_t data = mode;
  serialize(&data,sizeof(data));
  if (send_command(CMD_SET_PIN_MODE) == RETURN_OK) {
    log_message(str(format("pin %d mode=%d") % pin % mode).c_str(),
      function_name);
  }
}

uint8_t /* HOST */ RemoteObject::digital_read(uint8_t pin) {
  const char* function_name = "digital_read()";
  log_separator();
  log_message("send command", function_name);
  serialize(&pin,sizeof(pin));
  if (send_command(CMD_DIGITAL_READ) == RETURN_OK) {
    uint8_t value = read<uint8_t>();
    log_message(str(format("pin %d value=%d") % pin % value).c_str(),
      function_name);
    return value;
  }
  return 0;
}

void /* HOST */ RemoteObject::digital_write(uint8_t pin, bool value) {
  const char* function_name = "digital_write()";
  log_separator();
  log_message("send command", function_name);
  serialize(&pin,sizeof(pin));
  uint8_t data = value;
  serialize(&data,sizeof(data));
  if (send_command(CMD_DIGITAL_WRITE) == RETURN_OK) {
    log_message(str(format("pin %d value=%d") % pin % value).c_str(),
      function_name);
  }
}

uint16_t /* HOST */ RemoteObject::analog_read(uint8_t pin) {
  const char* function_name = "analog_read()";
  log_separator();
  log_message("send command", function_name);
  uint8_t n_channels = 1;
  serialize(&n_channels,sizeof(n_channels));
  serialize(&pin,sizeof(pin));
  if (send_command(CMD_ANALOG_READ) == RETURN_OK) {
    uint16_t value = read<uint16_t>();
    log_message(str(format("pin %d value=%d") % pin % value).c_str(),
      function_name);
    return value;
  }
  return 0;
}

std::vector<uint16_t> /* HOST */ RemoteObject::analog_reads(
    std::vector<uint8_t> pins, uint16_t n_samples) {
  const char* function_name = "analog_reads()";
  log_separator();
  log_message("send command", function_name);
  uint8_t n_channels = pins.size();
  serialize(&n_channels, sizeof(n_channels));
  serialize(&pins[0], n_channels*sizeof(uint8_t));
  serialize(&n_samples, sizeof(n_samples));
  if (send_command(CMD_ANALOG_READ) == RETURN_OK) {
    if (payload_length()==n_samples*sizeof(uint16_t)) {
      std::vector<uint16_t> buffer(n_samples);
      for (uint16_t i=0; i<n_samples; i++) {
        buffer[i] = read<uint16_t>();
      }
      return buffer;
    } else {
      return_code_ = RETURN_BAD_PACKET_SIZE;
    }
  }
  return std::vector<uint16_t>();
}

void /* HOST */ RemoteObject::analog_write(uint8_t pin, uint16_t value) {
  const char* function_name = "analog_write()";
  log_separator();
  log_message("send command", function_name);
  serialize(&pin,sizeof(pin));
  serialize(&value,sizeof(value));
  if (send_command(CMD_DIGITAL_WRITE) == RETURN_OK) {
    log_message(str(format("pin %d value=%d") % pin % value).c_str(),
      function_name);
  }
}

uint8_t /* HOST */ RemoteObject::persistent_read(uint16_t address) {
  const char* function_name = "persistent_read()";
  log_separator();
  log_message("send command", function_name);
  serialize(&address,sizeof(address));
  if (send_command(CMD_PERSISTENT_READ) == RETURN_OK) {
    uint8_t value = read<uint8_t>();
    log_message(str(format("address %d value=%d") % address % value).c_str(),
      function_name);
    return value;
  }
  return 0;
}

void /* HOST */ RemoteObject::persistent_write(uint16_t address,
                                               uint8_t value) {
  const char* function_name = "persistent_write()";
  log_separator();
  log_message("send command", function_name);
  serialize(&address,sizeof(address));
  serialize(&value,sizeof(value));
  if (send_command(CMD_PERSISTENT_WRITE) == RETURN_OK) {
    log_message(str(format("address %d value=%d") % address % value).c_str(),
      function_name);
  }
}

std::vector<uint8_t> /* HOST */ RemoteObject::onewire_address(uint8_t pin,
                                                              uint8_t index) {
  const char* function_name = "onewire_address()";
  log_separator();
  log_message("send command", function_name);
  serialize(&pin, sizeof(pin));
  serialize(&index, sizeof(index));
  if (send_command(CMD_ONEWIRE_GET_ADDRESS) == RETURN_OK) {
    log_message(str(format("pin %d, index=%d") % pin % index).c_str(),
      function_name);
    std::vector<uint8_t> address;
    for (int i = 0; i < payload_length(); i++) {
      address.push_back(read<uint8_t>());
    }
    return address;
  }
  return std::vector<uint8_t>();
}

std::vector<uint8_t> /* HOST */ RemoteObject::onewire_read(uint8_t pin,
                                                           std::vector<uint8_t>
                                                           address,
                                                           uint8_t command,
                                                           uint8_t n_bytes) {
  const char* function_name = "onewire_read()";
  log_separator();
  log_message("send command", function_name);
  if (address.size()==8) {
    serialize(&pin,sizeof(pin));
    serialize(&address[0],8*sizeof(uint8_t));
    serialize(&command,sizeof(command));
    serialize(&n_bytes,sizeof(n_bytes));
    if (send_command(CMD_ONEWIRE_READ) == RETURN_OK) {
      std::vector<uint8_t> data;
      for (uint8_t i=0; i<n_bytes; i++) {
        data.push_back(read<uint8_t>());
      }
      log_message(str(format("pin %d, command=%d, n_bytes=%d") % pin % command %
        n_bytes).c_str(), function_name);
      return data;
    }
  }
  return std::vector<uint8_t>();
}

void /* HOST */ RemoteObject::onewire_write(uint8_t pin,
                                            std::vector<uint8_t> address,
                                            uint8_t value, uint8_t power) {
  const char* function_name = "onewire_write()";
  log_separator();
  log_message("send command", function_name);
  if (address.size()==8) {
    serialize(&pin,sizeof(pin));
    serialize(&address[0],8*sizeof(uint8_t));
    serialize(&value,sizeof(value));
    serialize(&power,sizeof(power));
    if (send_command(CMD_ONEWIRE_WRITE) == RETURN_OK) {
      log_message(str(format("pin %d, value=%d, power=%d") % pin % value %
        power).c_str(), function_name);
    }
  }
}

void /* HOST */ RemoteObject::i2c_write(uint8_t address,
                                        std::vector<uint8_t> data) {
  const char* function_name = "i2c_write()";
  log_separator();
  log_message("send command", function_name);
  serialize(&address,sizeof(address));
  serialize(&data[0],data.size()*sizeof(uint8_t));
  if (send_command(CMD_I2C_WRITE) == RETURN_OK) {
    log_message(str(format("address %d") % address).c_str(), function_name);
    for (uint8_t i=0; i<data.size(); i++) {
      log_message(str(format("data[%d]=%d") % i % data[i]).c_str(),
        function_name);
    }
  }
}

std::vector<uint8_t> /* HOST */ RemoteObject::i2c_scan() {
  const char* function_name = "i2c_scan()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_I2C_SCAN) == RETURN_OK) {
    std::vector<uint8_t> received_data;
    for (uint8_t i = 0; i < payload_length(); i++) {
      received_data.push_back(read<uint8_t>());
      log_message(str(format("received_data[%d]=%d") % i %
        received_data[i]).c_str(), function_name);
    }
    return received_data;
  }
  return std::vector<uint8_t>();
}

std::vector<uint8_t> /* HOST */ RemoteObject::i2c_read(uint8_t address,
                                                       uint8_t
                                                       n_bytes_to_read) {
  const char* function_name = "i2c_read()";
  log_separator();
  log_message("send command", function_name);
  serialize(&address,sizeof(address));
  serialize(&n_bytes_to_read,sizeof(n_bytes_to_read));
  if (send_command(CMD_I2C_READ) == RETURN_OK) {
    log_message(str(format("address %d") % address).c_str(), function_name);
    std::vector<uint8_t> received_data;
    for (uint8_t i=0; i<n_bytes_to_read; i++) {
      received_data.push_back(read<uint8_t>());
      log_message(str(format("received_data[%d]=%d") % i %
        received_data[i]).c_str(), function_name);
    }
    return received_data;
  }
  return std::vector<uint8_t>();
}

std::vector<uint8_t> /* HOST */ RemoteObject::i2c_send_command(uint8_t address,
                                                               uint8_t cmd,
                                                               std::vector
                                                               <uint8_t> data,
                                                               uint8_t
                                                               delay_ms) {
  const char* function_name = "i2c_send_command()";
  data.insert(data.begin(), cmd);
  i2c_write(address, data);
  boost::this_thread::sleep(boost::posix_time::milliseconds(delay_ms));
  uint8_t n_bytes = i2c_read(address, 1)[0];
  if (n_bytes == 0) {
    throw runtime_error(str(format("Error sending command 0x%0X (%d). "
      "No return code provided.") % (int)cmd % (int)cmd).c_str());
  }
  std::vector<uint8_t> out = i2c_read(address, n_bytes);
  uint8_t return_code = out.back();
  log_message(str(format("Return code=%d") % (int)return_code).c_str(),
             function_name);
  out.pop_back();
  if (return_code != RETURN_OK) {
    throw runtime_error(str(format("Error sending command 0x%0X (%d). "
      "Return code=%d.") % (int)cmd % (int)cmd % (int)return_code).c_str());
  }
  return out;
}

void /* HOST */ RemoteObject::spi_set_bit_order(bool order) {
    send_set_command(CMD_SPI_SET_BIT_ORDER, "spi_set_bit_order()", order);
}

void /* HOST */ RemoteObject::spi_set_clock_divider(uint8_t divider) {
    send_set_command(CMD_SPI_SET_CLOCK_DIVIDER, "spi_set_clock_divider()",
                     divider);
}

void /* HOST */ RemoteObject::spi_set_data_mode(uint8_t mode) {
    send_set_command(CMD_SPI_SET_DATA_MODE, "spi_set_data_mode()", mode);
}

uint8_t /* HOST */ RemoteObject::spi_transfer(uint8_t value) {
    const char* function_name = "spi_transfer()";
    send_set_command(CMD_SPI_TRANSFER, function_name, value);
    uint8_t data = read<uint8_t>();
    log_message(str(format("sent: %d, received: %d") % value % data).c_str(),
               function_name);
    return data;
}

std::vector<uint8_t> /* HOST */ RemoteObject::debug_buffer() {
  const char* function_name = "debug_buffer()";
  log_separator();
  log_message("send command", function_name);
  if (send_command(CMD_GET_DEBUG_BUFFER) == RETURN_OK) {
    std::vector<uint8_t> buffer;
    for (uint16_t i=0; i<payload_length(); i++) {
      buffer.push_back(read<uint8_t>());
    }
    return buffer;
  }
  return std::vector<uint8_t>();
}

float /* HOST */ RemoteObject::sampling_rate() {
  return send_read_command<float>(CMD_GET_SAMPLING_RATE,
                                  "sampling_rate()");
}

uint8_t /* HOST */ RemoteObject::set_sampling_rate(const float sampling_rate) {
  return send_set_command(CMD_SET_SAMPLING_RATE, "set_sampling_rate()",
                          sampling_rate);
}

uint16_t /* HOST */ RemoteObject::adc_prescaler() {
  return send_read_command<uint16_t>(CMD_GET_ADC_PRESCALER, "prescaler()");
}

uint8_t /* HOST */ RemoteObject::set_adc_prescaler(const uint16_t prescaler) {
  return send_set_command(CMD_SET_ADC_PRESCALER, "set_adc_prescaler()",
                          prescaler);
}

float /* HOST */ RemoteObject::aref() {
  return send_read_command<float>(CMD_GET_AREF, "aref()");
}

#endif