<commit_before>// Copyright 2017 Per Grön. All Rights Reserved.
//
// Licensed 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.

#include <stdio.h>

#include <thread>

#include <grpc++/grpc++.h>

#include <shk-cache/shkcache_generated.h>
#include <shk-cache/shkcache.grpc.fb.h>

using namespace ShkCache;

namespace shk {

class ConfigService final : public ShkCache::Config::Service {
  grpc::Status Get(
      grpc::ServerContext* context,
      const flatbuffers::BufferRef<ConfigGetRequest>* request,
      flatbuffers::BufferRef<ConfigGetResponse>* response) override {
    // Create a response from the incoming request name.
    _builder.Clear();

    auto store_config = CreateStoreConfig(
        _builder,
        /*soft_store_entry_size_limit:*/1,
        /*hard_store_entry_size_limit:*/2);
    auto config_get_response = CreateConfigGetResponse(
        _builder,
        store_config);

    _builder.Finish(config_get_response);

    // Since we keep reusing the same FlatBufferBuilder, the memory it owns
    // remains valid until the next call (this BufferRef doesn't own the
    // memory it points to).
    *response = flatbuffers::BufferRef<ConfigGetResponse>(
        _builder.GetBufferPointer(),
        _builder.GetSize());
    return grpc::Status::OK;
  }

 private:
  flatbuffers::FlatBufferBuilder _builder;
};

// Track the server instance, so we can terminate it later.
grpc::Server *server_instance = nullptr;
// Mutex to protec this variable.
std::mutex wait_for_server;
std::condition_variable server_instance_cv;

// This function implements the server thread.
void RunServer() {
  auto server_address = "0.0.0.0:50051";

  ConfigService config_service;
  grpc::ServerBuilder builder;
  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
  builder.RegisterService(&config_service);

  // Start the server. Lock to change the variable we're changing.
  wait_for_server.lock();
  server_instance = builder.BuildAndStart().release();
  wait_for_server.unlock();
  server_instance_cv.notify_one();

  std::cout << "Server listening on " << server_address << std::endl;
  // This will block the thread and serve requests.
  server_instance->Wait();
}

int main(int /*argc*/, const char * /*argv*/[]) {
  // Launch server.
  std::thread server_thread(RunServer);

  // wait for server to spin up.
  std::unique_lock<std::mutex> lock(wait_for_server);
  while (!server_instance) {
    server_instance_cv.wait(lock);
  }

  // Now connect the client.
  auto channel = grpc::CreateChannel(
      "localhost:50051",
      grpc::InsecureChannelCredentials());
  auto stub = ShkCache::Config::NewStub(channel);

  flatbuffers::FlatBufferBuilder fbb;
  {
    grpc::ClientContext context;
    auto config_get_request = ShkCache::CreateConfigGetRequest(fbb);
    fbb.Finish(config_get_request);
    auto request = flatbuffers::BufferRef<ShkCache::ConfigGetRequest>(
        fbb.GetBufferPointer(), fbb.GetSize());
    flatbuffers::BufferRef<ShkCache::ConfigGetResponse> response;

    // The actual RPC.
    auto status = stub->Get(&context, request, &response);

    if (status.ok()) {
      if (!response.Verify()) {
        std::cout << "Verification failed!" << std::endl;
      } else {
        auto root = response.GetRoot();
        if (auto config = root->config()) {
          std::cout <<
              "RPC response: " << config->soft_store_entry_size_limit() <<
              ", " << config->hard_store_entry_size_limit() << std::endl;
        } else {
          std::cout << "RPC response: [no config]" << std::endl;
        }
      }
    } else {
      std::cout << "RPC failed" << std::endl;
    }
  }

  server_instance->Shutdown();

  server_thread.join();

  delete server_instance;

  return 0;
}

}  // namespace shk

int main(int argc, const char *argv[]) {
  return shk::main(argc, argv);
}
<commit_msg>Switch to an async gRPC client (very basic)<commit_after>// Copyright 2017 Per Grön. All Rights Reserved.
//
// Licensed 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.

#include <stdio.h>

#include <thread>

#include <grpc++/grpc++.h>

#include <shk-cache/shkcache_generated.h>
#include <shk-cache/shkcache.grpc.fb.h>

using namespace ShkCache;

namespace shk {

class ConfigService final : public ShkCache::Config::Service {
  grpc::Status Get(
      grpc::ServerContext* context,
      const flatbuffers::BufferRef<ConfigGetRequest>* request,
      flatbuffers::BufferRef<ConfigGetResponse>* response) override {
    // Create a response from the incoming request name.
    _builder.Clear();

    auto store_config = CreateStoreConfig(
        _builder,
        /*soft_store_entry_size_limit:*/1,
        /*hard_store_entry_size_limit:*/2);
    auto config_get_response = CreateConfigGetResponse(
        _builder,
        store_config);

    _builder.Finish(config_get_response);

    // Since we keep reusing the same FlatBufferBuilder, the memory it owns
    // remains valid until the next call (this BufferRef doesn't own the
    // memory it points to).
    *response = flatbuffers::BufferRef<ConfigGetResponse>(
        _builder.GetBufferPointer(),
        _builder.GetSize());
    return grpc::Status::OK;
  }

 private:
  flatbuffers::FlatBufferBuilder _builder;
};

// Track the server instance, so we can terminate it later.
grpc::Server *server_instance = nullptr;
// Mutex to protec this variable.
std::mutex wait_for_server;
std::condition_variable server_instance_cv;

// This function implements the server thread.
void RunServer() {
  auto server_address = "0.0.0.0:50051";

  ConfigService config_service;
  grpc::ServerBuilder builder;
  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
  builder.RegisterService(&config_service);

  // Start the server. Lock to change the variable we're changing.
  wait_for_server.lock();
  server_instance = builder.BuildAndStart().release();
  wait_for_server.unlock();
  server_instance_cv.notify_one();

  std::cout << "Server listening on " << server_address << std::endl;
  // This will block the thread and serve requests.
  server_instance->Wait();
}

int main(int /*argc*/, const char * /*argv*/[]) {
  // Launch server.
  std::thread server_thread(RunServer);

  // wait for server to spin up.
  std::unique_lock<std::mutex> lock(wait_for_server);
  while (!server_instance) {
    server_instance_cv.wait(lock);
  }

  // Now connect the client.
  auto channel = grpc::CreateChannel(
      "localhost:50051",
      grpc::InsecureChannelCredentials());
  auto stub = ShkCache::Config::NewStub(channel);

  flatbuffers::FlatBufferBuilder fbb;
  {
    grpc::CompletionQueue cq;

    grpc::ClientContext context;
    auto config_get_request = ShkCache::CreateConfigGetRequest(fbb);
    fbb.Finish(config_get_request);
    auto request = flatbuffers::BufferRef<ShkCache::ConfigGetRequest>(
        fbb.GetBufferPointer(), fbb.GetSize());
    std::unique_ptr<grpc::ClientAsyncResponseReader<
        flatbuffers::BufferRef<ShkCache::ConfigGetResponse>>> rpc(
            stub->AsyncGet(&context, request, &cq));

    flatbuffers::BufferRef<ShkCache::ConfigGetResponse> response;
    grpc::Status status;
    rpc->Finish(&response, &status, (void *)1);

    void *got_tag;
    bool ok = false;
    cq.Next(&got_tag, &ok);
    if (ok && got_tag == (void *)1) {
      if (!response.Verify()) {
        std::cout << "Verification failed!" << std::endl;
      } else {
        auto root = response.GetRoot();
        if (auto config = root->config()) {
          std::cout <<
              "RPC response: " << config->soft_store_entry_size_limit() <<
              ", " << config->hard_store_entry_size_limit() << std::endl;
        } else {
          std::cout << "RPC response: [no config]" << std::endl;
        }
      }
    } else if (ok) {
      std::cout << "Unknown response tag" << std::endl;
    } else {
      std::cout << "Request not ok" << std::endl;
    }
  }

  server_instance->Shutdown();

  server_thread.join();

  delete server_instance;

  return 0;
}

}  // namespace shk

int main(int argc, const char *argv[]) {
  return shk::main(argc, argv);
}
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-

/*
 * Copyright (C) 2010 RobotCub Consortium, European Commission FP6 Project IST-004370
 * Author: Alessandro Scalzo
 * email: alessandro.scalzo@iit.it
 * website: www.robotcub.org
 * Permission is granted to copy, distribute, and/or modify this program
 * under the terms of the GNU General Public License, version 2 or any
 * later version published by the Free Software Foundation.
 *
 * A copy of the license can be found at
 * http://www.robotcub.org/icub/license/gpl.txt
 *
 * This program 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
*/

#include "TestMotors.h"

#include <string>

TestMotors::TestMotors(yarp::os::Property& configuration) : UnitTest(configuration)
{}

TestMotors::~TestMotors()
{
    if (m_aTargetVal) delete [] m_aTargetVal;
    if (m_aMaxErr) delete [] m_aMaxErr;
    if (m_aMinErr) delete [] m_aMinErr;
    if (m_aRefVel) delete [] m_aRefVel;
    if (m_aRefAcc) delete [] m_aRefAcc;
    if (m_aTimeout) delete [] m_aTimeout;
    if (m_aHome) delete [] m_aHome;
}

bool TestMotors::init(yarp::os::Property& configuration)
{
    m_aTargetVal=NULL;
    m_aMaxErr=NULL;
    m_aMinErr=NULL;
    m_aRefVel=NULL;
    m_aRefAcc=NULL;
    m_aTimeout=NULL;
    m_aHome=NULL;
    m_initialized=false;

    iEncoders=NULL;
    iPosition=NULL;

    if (!configuration.check("portname"))
    {
        fprintf(stderr, "Missing portname parameter, cannot open device\n");
        return false;
    }
    m_portname=configuration.find("portname").asString();

    if (!configuration.check("joints"))
    {
        fprintf(stderr, "Missing joints parameter, cannot open device\n");
        return false;
    }
    m_NumJoints=configuration.find("joints").asInt();

    if (configuration.check("target"))
    {
        yarp::os::Bottle bot=configuration.findGroup("target").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aTargetVal=new double[m_NumJoints];
        m_aHome=new double [m_NumJoints];

        for (int i=0; i<n; ++i)
        {
            m_aTargetVal[i]=bot.get(i).asDouble();
            m_aHome[i]=0.0;
        }
    }
    else
    {
        return false;
    }

    if (configuration.check("min"))
    {
        yarp::os::Bottle bot=configuration.findGroup("min").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aMinErr=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
           m_aMinErr[i]=bot.get(i).asDouble();
    }
    else
    {
        return false;
    }

    if (configuration.check("max"))
    {
        yarp::os::Bottle bot=configuration.findGroup("max").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aMaxErr=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
             m_aMaxErr[i]=bot.get(i).asDouble();
    }
    else
    {
        return false;
    }

    if (configuration.check("refvel"))
    {
        yarp::os::Bottle bot=configuration.findGroup("refvel").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aRefVel=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
            m_aRefVel[i]=bot.get(i).asDouble();
    }
    else
    {
        return false;
    }

    if (configuration.check("refacc"))
    {
        yarp::os::Bottle bot=configuration.findGroup("refacc").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aRefAcc=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
            m_aRefAcc[i]=bot.get(i).asDouble();
    }
    else
    {
        // nothing, accelerations are not mandatory
        // e.g. the simulator does not accept accelerations
    }

    if (configuration.check("timeout"))
    {
        yarp::os::Bottle bot=configuration.findGroup("timeout").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aTimeout=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
            m_aTimeout[i]=bot.get(i).asDouble();
    }
    else
    {
        return false;
    }

    return true;
}

bool TestMotors::run()
{
    yarp::os::Property options;
    options.put("device","remote_controlboard");
    options.put("local",m_portname+"/client");
    options.put("remote",m_portname);

    bool ret=m_driver.open(options);

    Logger:: checkTrue(ret, "open device");

    if (!ret)
        return false;

    m_driver.view(iEncoders);
    m_driver.view(iPosition);

    ret=iEncoders&&iPosition;
    Logger::checkTrue(ret, "interfaces acquired");

    if (!ret)
        return false;

    int nJoints=0;
    iEncoders->getAxes(&nJoints);

    Logger::checkTrue(m_NumJoints==nJoints, "expected number of joints is consistent");

    /////// check individual joints
    Logger::report("Checking individual joints...\n");
    for (int joint=0; joint<m_NumJoints; ++joint)
    {
        Logger::report("Checking joint %d\n", joint);
        if (m_aRefAcc!=NULL)
            Logger::checkTrue(iPosition->setRefAcceleration(joint, m_aRefAcc[joint]),
                "setting reference acceleration on joint %d", joint);

        Logger::checkTrue(iPosition->setRefSpeed(joint, m_aRefVel[joint]),
            "setting reference speed on joint %d", joint);

        // wait some time
        double timeStart=yarp::os::Time::now();
        double timeNow=timeStart;
        bool read=false;

        printf("Checking encoders");
        while(timeNow<timeStart+m_aTimeout[joint] && !read)
        {
            // read encoders
            read=iEncoders->getEncoder(joint,m_aHome+joint);
            yarp::os::Time::delay(0.1);
            printf(".");
        }
        printf("\n");
        Logger::checkTrue(read, "read encoder");

        Logger::checkTrue(iPosition->positionMove(joint, m_aTargetVal[joint]),
            "moving joint %d to %.2lf", joint, m_aTargetVal[joint]);

        printf("Waiting timeout %.2lf", m_aTimeout[joint]);
        bool reached=false;
        while(timeNow<timeStart+m_aTimeout[joint] && !reached)
        {
            double pos;
            iEncoders->getEncoder(joint,&pos);

            reached=isApproxEqual(pos, m_aTargetVal[joint], m_aMinErr[joint], m_aMaxErr[joint]);

            printf(".");
            timeNow=yarp::os::Time::now();
            yarp::os::Time::delay(0.1);
        }
        printf("\n");
        Logger::checkTrue(reached, "reached position");
    }

    //////// check multiple joints
    Logger::report("Checking multiple joints...\n");
    if (m_aRefAcc!=NULL)
        Logger::checkTrue(iPosition->setRefAccelerations(m_aRefAcc),
                "setting reference acceleration on all joints");

    Logger::checkTrue(iPosition->setRefSpeeds(m_aRefVel),
            "setting reference speed on all joints");

    Logger::checkTrue(iPosition->positionMove(m_aHome),
            "moving all joints to home");

    // wait some time
    double timeStart=yarp::os::Time::now();
    double timeNow=timeStart;

    double timeout=m_aTimeout[0];
    for(int j=0; j<m_NumJoints; j++)
    {
        if (timeout<m_aTimeout[j])
            timeout=m_aTimeout[j];
    }

    printf("Waiting timeout %.2lf", timeout);
    bool reached=false;
    double *encoders;
    encoders=new double [m_NumJoints];
    while(timeNow<timeStart+m_aTimeout[0] && !reached)
        {
            iEncoders->getEncoders(encoders);

            reached=isApproxEqual(encoders, m_aTargetVal, m_aMinErr, m_aMaxErr, m_NumJoints);

            printf(".");
            timeNow=yarp::os::Time::now();
            yarp::os::Time::delay(0.1);
        }
    delete [] encoders;

    printf("\n");
    Logger::checkTrue(reached, "reached position");

    if (reached)
    {
        bool *done=new bool [m_NumJoints];
        bool ret=iPosition->checkMotionDone(done);

        bool ok=isTrue(done, m_NumJoints);

        Logger::checkTrue(ok&&ret, "checking checkMotionDone");

        delete [] done;
    }

    return true;
}

bool TestMotors::release()
{
    Logger::report("Homing robot\n");

    iPosition->positionMove(m_aHome);
    double *encoders;
    bool *done;
    encoders=new double [m_NumJoints];
    done = new bool [m_NumJoints];

    bool reached=false;
    double timeStart=yarp::os::Time::now();
    double timeNow=timeStart;
    while(timeNow<timeStart+m_aTimeout[0] && !reached)
    {
        iEncoders->getEncoders(encoders);

        iPosition->checkMotionDone(done);

        reached=isTrue(done, m_NumJoints);

        printf(".");
        timeNow=yarp::os::Time::now();
        yarp::os::Time::delay(0.1);
    }

    printf("\n");
    delete [] encoders;
    delete [] done;

    return true;
}<commit_msg>fixed potential glitch in checkmotiondone<commit_after>// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-

/*
 * Copyright (C) 2010 RobotCub Consortium, European Commission FP6 Project IST-004370
 * Author: Alessandro Scalzo
 * email: alessandro.scalzo@iit.it
 * website: www.robotcub.org
 * Permission is granted to copy, distribute, and/or modify this program
 * under the terms of the GNU General Public License, version 2 or any
 * later version published by the Free Software Foundation.
 *
 * A copy of the license can be found at
 * http://www.robotcub.org/icub/license/gpl.txt
 *
 * This program 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
*/

#include "TestMotors.h"

#include <string>

TestMotors::TestMotors(yarp::os::Property& configuration) : UnitTest(configuration)
{}

TestMotors::~TestMotors()
{
    if (m_aTargetVal) delete [] m_aTargetVal;
    if (m_aMaxErr) delete [] m_aMaxErr;
    if (m_aMinErr) delete [] m_aMinErr;
    if (m_aRefVel) delete [] m_aRefVel;
    if (m_aRefAcc) delete [] m_aRefAcc;
    if (m_aTimeout) delete [] m_aTimeout;
    if (m_aHome) delete [] m_aHome;
}

bool TestMotors::init(yarp::os::Property& configuration)
{
    m_aTargetVal=NULL;
    m_aMaxErr=NULL;
    m_aMinErr=NULL;
    m_aRefVel=NULL;
    m_aRefAcc=NULL;
    m_aTimeout=NULL;
    m_aHome=NULL;
    m_initialized=false;

    iEncoders=NULL;
    iPosition=NULL;

    if (!configuration.check("portname"))
    {
        fprintf(stderr, "Missing portname parameter, cannot open device\n");
        return false;
    }
    m_portname=configuration.find("portname").asString();

    if (!configuration.check("joints"))
    {
        fprintf(stderr, "Missing joints parameter, cannot open device\n");
        return false;
    }
    m_NumJoints=configuration.find("joints").asInt();

    if (configuration.check("target"))
    {
        yarp::os::Bottle bot=configuration.findGroup("target").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aTargetVal=new double[m_NumJoints];
        m_aHome=new double [m_NumJoints];

        for (int i=0; i<n; ++i)
        {
            m_aTargetVal[i]=bot.get(i).asDouble();
            m_aHome[i]=0.0;
        }
    }
    else
    {
        return false;
    }

    if (configuration.check("min"))
    {
        yarp::os::Bottle bot=configuration.findGroup("min").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aMinErr=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
           m_aMinErr[i]=bot.get(i).asDouble();
    }
    else
    {
        return false;
    }

    if (configuration.check("max"))
    {
        yarp::os::Bottle bot=configuration.findGroup("max").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aMaxErr=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
             m_aMaxErr[i]=bot.get(i).asDouble();
    }
    else
    {
        return false;
    }

    if (configuration.check("refvel"))
    {
        yarp::os::Bottle bot=configuration.findGroup("refvel").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aRefVel=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
            m_aRefVel[i]=bot.get(i).asDouble();
    }
    else
    {
        return false;
    }

    if (configuration.check("refacc"))
    {
        yarp::os::Bottle bot=configuration.findGroup("refacc").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aRefAcc=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
            m_aRefAcc[i]=bot.get(i).asDouble();
    }
    else
    {
        // nothing, accelerations are not mandatory
        // e.g. the simulator does not accept accelerations
    }

    if (configuration.check("timeout"))
    {
        yarp::os::Bottle bot=configuration.findGroup("timeout").tail();

        int n=m_NumJoints<bot.size()?m_NumJoints:bot.size();

        m_aTimeout=new double[m_NumJoints];

        for (int i=0; i<n; ++i)
            m_aTimeout[i]=bot.get(i).asDouble();
    }
    else
    {
        return false;
    }

    return true;
}

bool TestMotors::run()
{
    yarp::os::Property options;
    options.put("device","remote_controlboard");
    options.put("local",m_portname+"/client");
    options.put("remote",m_portname);

    bool ret=m_driver.open(options);

    Logger:: checkTrue(ret, "open device");

    if (!ret)
        return false;

    m_driver.view(iEncoders);
    m_driver.view(iPosition);

    ret=iEncoders&&iPosition;
    Logger::checkTrue(ret, "interfaces acquired");

    if (!ret)
        return false;

    int nJoints=0;
    iEncoders->getAxes(&nJoints);

    Logger::checkTrue(m_NumJoints==nJoints, "expected number of joints is consistent");

    /////// check individual joints
    Logger::report("Checking individual joints...\n");
    for (int joint=0; joint<m_NumJoints; ++joint)
    {
        Logger::report("Checking joint %d\n", joint);
        if (m_aRefAcc!=NULL)
            Logger::checkTrue(iPosition->setRefAcceleration(joint, m_aRefAcc[joint]),
                "setting reference acceleration on joint %d", joint);

        Logger::checkTrue(iPosition->setRefSpeed(joint, m_aRefVel[joint]),
            "setting reference speed on joint %d", joint);

        // wait some time
        double timeStart=yarp::os::Time::now();
        double timeNow=timeStart;
        bool read=false;

        printf("Checking encoders");
        while(timeNow<timeStart+m_aTimeout[joint] && !read)
        {
            // read encoders
            read=iEncoders->getEncoder(joint,m_aHome+joint);
            yarp::os::Time::delay(0.1);
            printf(".");
        }
        printf("\n");
        Logger::checkTrue(read, "read encoder");

        Logger::checkTrue(iPosition->positionMove(joint, m_aTargetVal[joint]),
            "moving joint %d to %.2lf", joint, m_aTargetVal[joint]);

        printf("Waiting timeout %.2lf", m_aTimeout[joint]);
        bool reached=false;
        while(timeNow<timeStart+m_aTimeout[joint] && !reached)
        {
            double pos;
            iEncoders->getEncoder(joint,&pos);

            reached=isApproxEqual(pos, m_aTargetVal[joint], m_aMinErr[joint], m_aMaxErr[joint]);

            printf(".");
            timeNow=yarp::os::Time::now();
            yarp::os::Time::delay(0.1);
        }
        printf("\n");
        Logger::checkTrue(reached, "reached position");
    }

    //////// check multiple joints
    Logger::report("Checking multiple joints...\n");
    if (m_aRefAcc!=NULL)
        Logger::checkTrue(iPosition->setRefAccelerations(m_aRefAcc),
                "setting reference acceleration on all joints");

    Logger::checkTrue(iPosition->setRefSpeeds(m_aRefVel),
            "setting reference speed on all joints");

    Logger::checkTrue(iPosition->positionMove(m_aHome),
            "moving all joints to home");

    // wait some time
    double timeStart=yarp::os::Time::now();
    double timeNow=timeStart;

    double timeout=m_aTimeout[0];
    for(int j=0; j<m_NumJoints; j++)
    {
        if (timeout<m_aTimeout[j])
            timeout=m_aTimeout[j];
    }

    printf("Waiting timeout %.2lf", timeout);
    bool reached=false;
    double *encoders;
    encoders=new double [m_NumJoints];
    while(timeNow<timeStart+m_aTimeout[0] && !reached)
        {
            iEncoders->getEncoders(encoders);

            reached=isApproxEqual(encoders, m_aTargetVal, m_aMinErr, m_aMaxErr, m_NumJoints);

            printf(".");
            timeNow=yarp::os::Time::now();
            yarp::os::Time::delay(0.1);
        }
    delete [] encoders;

    printf("\n");
    Logger::checkTrue(reached, "reached position");

    if (reached)
    {
        bool *done_vector=new bool [m_NumJoints];

        // check checkMotionDone.
        // because the previous movement was approximate, the robot
        // could still be moving so we need to iterate a few times

        int times=10;
        bool doneAll=false;
        bool ret=false;

        while(times>0 && !doneAll)
        {
            ret=iPosition->checkMotionDone(done_vector);
            doneAll=isTrue(done_vector, m_NumJoints);
            if (!doneAll)
                yarp::os::Time::delay(0.1);
        }

        Logger::checkTrue(doneAll&&ret, "checking checkMotionDone");

        delete [] done_vector;
    }

    return true;
}

bool TestMotors::release()
{
    Logger::report("Homing robot\n");

    iPosition->positionMove(m_aHome);
    double *encoders;
    bool *done;
    encoders=new double [m_NumJoints];
    done = new bool [m_NumJoints];

    bool reached=false;
    double timeStart=yarp::os::Time::now();
    double timeNow=timeStart;
    while(timeNow<timeStart+m_aTimeout[0] && !reached)
    {
        iEncoders->getEncoders(encoders);

        iPosition->checkMotionDone(done);

        reached=isTrue(done, m_NumJoints);

        printf(".");
        timeNow=yarp::os::Time::now();
        yarp::os::Time::delay(0.1);
    }

    printf("\n");
    delete [] encoders;
    delete [] done;

    return true;
}<|endoftext|>


<commit_before>
#include <SDL.h>
#include <SDL_audio.h>
#include <akAudioMixer.h>
#include <assert.h>
#include <signal.h>
#include <iostream>
#include <akPGTA.h>
#include <public/akPGTATypes.h>
#include "utils.h"
#include "FileUtils.h"

class SDLWav
{
public:
    SDLWav(const char* filename) :
        m_audioBuf(nullptr),
        m_audioLen(0),
        m_spec()
    {
        SDL_LoadWAV(filename, &m_spec, &m_audioBuf, &m_audioLen);
        assert(m_spec.freq == 44100);
        assert(m_spec.format == AUDIO_S16);
        assert(m_spec.channels == 1);
        std::cout << filename << " has " << (m_audioLen >> 1) << " samples\n";
    }

    ~SDLWav()
    {
        if (m_audioBuf)
        {
            SDL_FreeWAV(m_audioBuf);
        }
    }

    explicit operator bool() const
    {
        return (m_audioBuf != nullptr && m_audioLen > 0);
    }

    const SDL_AudioSpec& GetSpec() const
    {
        return m_spec;
    }

    const int16_t* GetSamplePtr() const
    {
        return reinterpret_cast<const int16_t*>(m_audioBuf);
    }

    uint32_t GetNumSamples() const
    {
        assert((m_audioLen % 2) == 0);
        return (m_audioLen >> 1);
    }

private:
    Uint8* m_audioBuf;
    Uint32 m_audioLen;
    SDL_AudioSpec m_spec;
};

int pgtaMain(SDL_AudioDeviceID audioDevice)
{
    PGTA::PGTADevice pgtaDevice;
    if (!pgtaDevice.Initialize())
    {
        return -1;
    }

    // load track data to memory
    // "tracks/demo.track"
    std::string trackSource;
    if (!ReadBinaryFileToString("tracks/test.track", trackSource))
    {
        return -1;
    }

    HPGTATrack demoTrack = nullptr;
    const char* source = trackSource.data();
    const size_t length = trackSource.length();
    if (pgtaDevice.CreateTracks(1, &source, &length, &demoTrack) <= 0 || !demoTrack)
    {
        return -1;
    }

    auto trackData = pgtaGetTrackData(demoTrack);
    int numSamples = trackData.numSamples;
    std::vector<int16_t*> audioData(numSamples);
    for (int i = 0; i < numSamples; ++i)
    {
        auto& data = audioData[i];
        int16_t id = trackData.samples[i].id;
        const char* file = trackData.samples[i].defaultFile;
        SDLWav audio(file);
        uint32_t audioLength = audio.GetNumSamples();
        data = new int16_t[audioLength];
        memcpy(data, audio.GetSamplePtr() , audioLength * sizeof data[0]);

        pgtaBindTrackSample(demoTrack, id, audioData[i], audioLength);
    }

    PGTAConfig config;
    config.audioDesc.samplesPerSecond = 44100;
    config.audioDesc.bytesPerSample = 2;
    config.audioDesc.channels = 1;
    config.mixAhead = 0.1f;
    PGTA::PGTAContext pgtaContext(pgtaDevice.CreateContext(config));

    pgtaContext.BindTrack(demoTrack);

    utils::RunLoop(0.01f, [&](double /*absoluteTime*/, float delta)
    {
        const PGTABuffer output = pgtaContext.Update(delta);
        SDL_QueueAudio(audioDevice, output.samples, static_cast<Uint32>(output.numSamples * 2));
        return (output.samples != nullptr) && (output.numSamples > 0);
    });

    for (auto& i : audioData)
    {
        delete[] i;
    }
    return 0;
}

int main()
{
    SDL_Init(SDL_INIT_EVERYTHING);

    SDL_AudioSpec audioSpec;
    SDL_zero(audioSpec);
    audioSpec.freq = 44100;
    audioSpec.format = AUDIO_S16;
    audioSpec.channels = 1;
    audioSpec.samples = 4096;
    SDL_AudioDeviceID audioDevice = SDL_OpenAudioDevice(nullptr, false, &audioSpec, nullptr, 0);

    int ret = 0;
    if (audioDevice > 1)
    {
        SDL_PauseAudioDevice(audioDevice, 0);
        ret = pgtaMain(audioDevice);
        SDL_CloseAudioDevice(audioDevice);
    }

    SDL_Quit();
    return ret;
}
<commit_msg>Cleaned up EngineTest and fixed working directory when running through a debugger<commit_after>
#include <SDL.h>
#include <SDL_audio.h>
#include <akAudioMixer.h>
#include <assert.h>
#include <signal.h>
#include <iostream>
#include <akPGTA.h>
#include <public/akPGTATypes.h>
#include "utils.h"
#include "FileUtils.h"

class SDLWav
{
public:
    SDLWav(const char* filename) :
        m_audioBuf(nullptr),
        m_audioLen(0),
        m_spec()
    {
        SDL_LoadWAV(filename, &m_spec, &m_audioBuf, &m_audioLen);
        assert(m_spec.freq == 44100);
        assert(m_spec.format == AUDIO_S16);
        assert(m_spec.channels == 1);
        std::cout << filename << " has " << (m_audioLen >> 1) << " samples\n";
    }

    ~SDLWav()
    {
        if (m_audioBuf)
        {
            SDL_FreeWAV(m_audioBuf);
        }
    }

    explicit operator bool() const
    {
        return (m_audioBuf != nullptr && m_audioLen > 0);
    }

    const SDL_AudioSpec& GetSpec() const
    {
        return m_spec;
    }

    const int16_t* GetSamplePtr() const
    {
        return reinterpret_cast<const int16_t*>(m_audioBuf);
    }

    uint32_t GetNumSamples() const
    {
        assert((m_audioLen % 2) == 0);
        return (m_audioLen >> 1);
    }

private:
    Uint8* m_audioBuf;
    Uint32 m_audioLen;
    SDL_AudioSpec m_spec;
};

int pgtaMain(SDL_AudioDeviceID audioDevice)
{
    PGTA::PGTADevice pgtaDevice;
    if (!pgtaDevice.Initialize())
    {
        return -1;
    }

    // load track data to memory
    // "tracks/demo.track"
    std::string trackSource;
    if (!ReadBinaryFileToString("tracks/test.track", trackSource))
    {
        return -1;
    }

    HPGTATrack demoTrack = nullptr;
    const char* source = trackSource.data();
    const size_t length = trackSource.length();
    if (pgtaDevice.CreateTracks(1, &source, &length, &demoTrack) <= 0 || !demoTrack)
    {
        return -1;
    }

    const PGTATrackData trackData = pgtaGetTrackData(demoTrack);
    const int numSamples = trackData.numSamples;

    std::vector<SDLWav> audioFiles;
    audioFiles.reserve(numSamples);
    for (int i = 0; i < numSamples; ++i)
    {
        const PGTASampleData* sampleData = (trackData.samples + i);
        audioFiles.emplace_back(sampleData->defaultFile);
        pgtaBindTrackSample(demoTrack, sampleData->id,
                            audioFiles[i].GetSamplePtr(),
                            audioFiles[i].GetNumSamples());
    }

    PGTAConfig config;
    config.audioDesc.samplesPerSecond = 44100;
    config.audioDesc.bytesPerSample = 2;
    config.audioDesc.channels = 1;
    config.mixAhead = 0.1f;
    PGTA::PGTAContext pgtaContext(pgtaDevice.CreateContext(config));

    pgtaContext.BindTrack(demoTrack);
    utils::RunLoop(0.01f, [&](double /*absoluteTime*/, float delta)
    {
        const PGTABuffer output = pgtaContext.Update(delta);
        SDL_QueueAudio(audioDevice, output.samples, static_cast<Uint32>(output.numSamples * 2));
        return (output.samples != nullptr) && (output.numSamples > 0);
    });
    return 0;
}

int main()
{
    utils::FixWorkingDirectory();
    SDL_Init(SDL_INIT_EVERYTHING);

    SDL_AudioSpec audioSpec;
    SDL_zero(audioSpec);
    audioSpec.freq = 44100;
    audioSpec.format = AUDIO_S16;
    audioSpec.channels = 1;
    audioSpec.samples = 4096;
    SDL_AudioDeviceID audioDevice = SDL_OpenAudioDevice(nullptr, false, &audioSpec, nullptr, 0);

    int ret = 0;
    if (audioDevice > 1)
    {
        SDL_PauseAudioDevice(audioDevice, 0);
        ret = pgtaMain(audioDevice);
        SDL_CloseAudioDevice(audioDevice);
    }

    SDL_Quit();
    return ret;
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "config.h"

TEST(Config, TestDefault) {
  EXPECT_NO_FATAL_FAILURE(Core::Config::getInstance("test.ini"));
}

TEST(Config, TestDatabase) {
  Core::Config &config = Core::Config::getInstance();
  const ::configFile::Database &dbb = config.database();
  EXPECT_EQ("localhost", dbb.host());
  EXPECT_EQ("osirose", dbb.database());
  EXPECT_EQ("root", dbb.user());
  EXPECT_EQ("", dbb.password());
  EXPECT_EQ(3306, dbb.port());
}

TEST(Config, TestServer) {
  Core::Config &config = Core::Config::getInstance();
  const ::configFile::Server &sd = config.serverdata();
  EXPECT_EQ(0, sd.id());
  EXPECT_EQ("127.0.0.1", sd.ip());
  EXPECT_EQ(100, sd.accesslevel());
  EXPECT_EQ(0, sd.parentid());
  EXPECT_EQ(100, sd.maxconnections());
  EXPECT_EQ(true, sd.usethreads());
  EXPECT_EQ(0, sd.mode());
}
<commit_msg>Adapted current tests to conform to the changed defaults<commit_after>#include "gtest/gtest.h"
#include "config.h"

TEST(Config, TestDefault) {
  EXPECT_NO_FATAL_FAILURE(Core::Config::getInstance("test.ini"));
}

TEST(Config, TestDatabase) {
  Core::Config &config = Core::Config::getInstance();
  const ::configFile::Database &dbb = config.database();
  EXPECT_EQ("localhost", dbb.host());
  EXPECT_EQ("osirose", dbb.database());
  EXPECT_EQ("root", dbb.user());
  EXPECT_EQ("", dbb.password());
  EXPECT_EQ(3306, dbb.port());
}

TEST(Config, TestServer) {
  Core::Config &config = Core::Config::getInstance();
  const ::configFile::Server &sd = config.serverdata();
  EXPECT_EQ(0, sd.id());
  EXPECT_EQ("127.0.0.1", sd.ip());
  EXPECT_EQ(100, sd.accesslevel());
  EXPECT_EQ(0, sd.parentid());
  EXPECT_EQ(0, sd.maxconnections());
  EXPECT_EQ(true, sd.usethreads());
  EXPECT_EQ(0, sd.mode());
}
<|endoftext|>


<commit_before>/**
 * Copyright © 2019 IBM Corporation
 *
 * Licensed 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.
 */
#include "pel.hpp"

#include "bcd_time.hpp"
#include "extended_user_header.hpp"
#include "failing_mtms.hpp"
#include "json_utils.hpp"
#include "log_id.hpp"
#include "pel_rules.hpp"
#include "pel_values.hpp"
#include "section_factory.hpp"
#include "src.hpp"
#include "stream.hpp"
#include "user_data_formats.hpp"

#include <iostream>
#include <phosphor-logging/log.hpp>

namespace openpower
{
namespace pels
{
namespace message = openpower::pels::message;
namespace pv = openpower::pels::pel_values;

constexpr auto unknownValue = "Unknown";

PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp,
         phosphor::logging::Entry::Level severity,
         const AdditionalData& additionalData,
         const DataInterfaceBase& dataIface)
{
    _ph = std::make_unique<PrivateHeader>(entry.componentID, obmcLogID,
                                          timestamp);
    _uh = std::make_unique<UserHeader>(entry, severity);

    auto src = std::make_unique<SRC>(entry, additionalData, dataIface);

    auto euh = std::make_unique<ExtendedUserHeader>(dataIface, entry, *src);

    _optionalSections.push_back(std::move(src));
    _optionalSections.push_back(std::move(euh));

    auto mtms = std::make_unique<FailingMTMS>(dataIface);
    _optionalSections.push_back(std::move(mtms));

    auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
    _optionalSections.push_back(std::move(ud));

    if (!additionalData.empty())
    {
        ud = util::makeADUserDataSection(additionalData);

        // To be safe, check there isn't too much data
        if (size() + ud->header().size <= _maxPELSize)
        {
            _optionalSections.push_back(std::move(ud));
        }
    }

    _ph->setSectionCount(2 + _optionalSections.size());

    checkRulesAndFix();
}

PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
{
}

PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
{
    populateFromRawData(data, obmcLogID);
}

void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
{
    Stream pelData{data};
    _ph = std::make_unique<PrivateHeader>(pelData);
    if (obmcLogID != 0)
    {
        _ph->setOBMCLogID(obmcLogID);
    }

    _uh = std::make_unique<UserHeader>(pelData);

    // Use the section factory to create the rest of the objects
    for (size_t i = 2; i < _ph->sectionCount(); i++)
    {
        auto section = section_factory::create(pelData);
        _optionalSections.push_back(std::move(section));
    }
}

bool PEL::valid() const
{
    bool valid = _ph->valid();

    if (valid)
    {
        valid = _uh->valid();
    }

    if (valid)
    {
        if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
                         [](const auto& section) { return section->valid(); }))
        {
            valid = false;
        }
    }

    return valid;
}

void PEL::setCommitTime()
{
    auto now = std::chrono::system_clock::now();
    _ph->setCommitTimestamp(getBCDTime(now));
}

void PEL::assignID()
{
    _ph->setID(generatePELID());
}

void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
{
    Stream pelData{pelBuffer};

    if (!valid())
    {
        using namespace phosphor::logging;
        log<level::WARNING>("Unflattening an invalid PEL");
    }

    _ph->flatten(pelData);
    _uh->flatten(pelData);

    for (auto& section : _optionalSections)
    {
        section->flatten(pelData);
    }
}

std::vector<uint8_t> PEL::data() const
{
    std::vector<uint8_t> pelData;
    flatten(pelData);
    return pelData;
}

size_t PEL::size() const
{
    size_t size = 0;

    if (_ph)
    {
        size += _ph->header().size;
    }

    if (_uh)
    {
        size += _uh->header().size;
    }

    for (const auto& section : _optionalSections)
    {
        size += section->header().size;
    }

    return size;
}

std::optional<SRC*> PEL::primarySRC() const
{
    auto src = std::find_if(
        _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
            return section->header().id ==
                   static_cast<uint16_t>(SectionID::primarySRC);
        });
    if (src != _optionalSections.end())
    {
        return static_cast<SRC*>(src->get());
    }

    return std::nullopt;
}

void PEL::checkRulesAndFix()
{
    auto [actionFlags, eventType] =
        pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity());

    _uh->setActionFlags(actionFlags);
    _uh->setEventType(eventType);
}

void PEL::printSectionInJSON(const Section& section, std::string& buf,
                             std::map<uint16_t, size_t>& pluralSections,
                             message::Registry& registry) const
{
    char tmpB[5];
    uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
                    static_cast<uint8_t>(section.header().id)};
    sprintf(tmpB, "%c%c", id[0], id[1]);
    std::string sectionID(tmpB);
    std::string sectionName = pv::sectionTitles.count(sectionID)
                                  ? pv::sectionTitles.at(sectionID)
                                  : "Unknown Section";

    // Add a count if there are multiple of this type of section
    auto count = pluralSections.find(section.header().id);
    if (count != pluralSections.end())
    {
        sectionName += " " + std::to_string(count->second);
        count->second++;
    }

    if (section.valid())
    {
        auto json = (sectionID == "PS" || sectionID == "SS")
                        ? section.getJSON(registry)
                        : section.getJSON();

        buf += "\"" + sectionName + "\": {\n";

        if (json)
        {
            buf += *json + "\n},\n";
        }
        else
        {
            jsonInsert(buf, pv::sectionVer,
                       getNumberString("%d", section.header().version), 1);
            jsonInsert(buf, pv::subSection,
                       getNumberString("%d", section.header().subType), 1);
            jsonInsert(buf, pv::createdBy,
                       getNumberString("0x%X", section.header().componentID),
                       1);

            std::vector<uint8_t> data;
            Stream s{data};
            section.flatten(s);
            std::string dstr =
                dumpHex(std::data(data) + SectionHeader::flattenedSize(),
                        data.size(), 2);

            std::string jsonIndent(indentLevel, 0x20);
            buf += jsonIndent + "\"Data\": [\n";
            buf += dstr;
            buf += jsonIndent + "]\n";
            buf += "},\n";
        }
    }
    else
    {
        buf += "\n\"Invalid Section\": [\n    \"invalid\"\n],\n";
    }
}

std::map<uint16_t, size_t> PEL::getPluralSections() const
{
    std::map<uint16_t, size_t> sectionCounts;

    for (const auto& section : optionalSections())
    {
        if (sectionCounts.find(section->header().id) == sectionCounts.end())
        {
            sectionCounts[section->header().id] = 1;
        }
        else
        {
            sectionCounts[section->header().id]++;
        }
    }

    std::map<uint16_t, size_t> sections;
    for (const auto& [id, count] : sectionCounts)
    {
        if (count > 1)
        {
            // Start with 0 here and printSectionInJSON()
            // will increment it as it goes.
            sections.emplace(id, 0);
        }
    }

    return sections;
}

void PEL::toJSON(message::Registry& registry) const
{
    auto sections = getPluralSections();

    std::string buf = "{\n";
    printSectionInJSON(*(_ph.get()), buf, sections, registry);
    printSectionInJSON(*(_uh.get()), buf, sections, registry);
    for (auto& section : this->optionalSections())
    {
        printSectionInJSON(*(section.get()), buf, sections, registry);
    }
    buf += "}";
    std::size_t found = buf.rfind(",");
    if (found != std::string::npos)
        buf.replace(found, 1, "");
    std::cout << buf << std::endl;
}

namespace util
{

std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
{
    auto jsonString = json.dump();
    std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());

    // Pad to a 4 byte boundary
    while ((jsonData.size() % 4) != 0)
    {
        jsonData.push_back(0);
    }

    return std::make_unique<UserData>(
        static_cast<uint16_t>(ComponentID::phosphorLogging),
        static_cast<uint8_t>(UserDataFormat::json),
        static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
}

std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
{
    assert(!ad.empty());
    nlohmann::json json;

    // Remove the 'ESEL' entry, as it contains a full PEL in the value.
    if (ad.getValue("ESEL"))
    {
        auto newAD = ad;
        newAD.remove("ESEL");
        json = newAD.toJSON();
    }
    else
    {
        json = ad.toJSON();
    }

    return makeJSONUserDataSection(json);
}

void addProcessNameToJSON(nlohmann::json& json,
                          const std::optional<std::string>& pid,
                          const DataInterfaceBase& dataIface)
{
    std::string name{unknownValue};

    try
    {
        if (pid)
        {
            auto n = dataIface.getProcessName(*pid);
            if (n)
            {
                name = *n;
            }
        }
    }
    catch (std::exception& e)
    {
    }

    json["Process Name"] = std::move(name);
}

void addBMCFWVersionIDToJSON(nlohmann::json& json,
                             const DataInterfaceBase& dataIface)
{
    auto id = dataIface.getBMCFWVersionID();
    if (id.empty())
    {
        id = unknownValue;
    }

    json["BMC Version ID"] = std::move(id);
}

std::string lastSegment(char separator, std::string data)
{
    auto pos = data.find_last_of(separator);
    if (pos != std::string::npos)
    {
        data = data.substr(pos + 1);
    }

    return data;
}

void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
{
    json["BMCState"] = lastSegment('.', dataIface.getBMCState());
    json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
    json["HostState"] = lastSegment('.', dataIface.getHostState());
}

std::unique_ptr<UserData>
    makeSysInfoUserDataSection(const AdditionalData& ad,
                               const DataInterfaceBase& dataIface)
{
    nlohmann::json json;

    addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
    addBMCFWVersionIDToJSON(json, dataIface);
    addStatesToJSON(json, dataIface);

    return makeJSONUserDataSection(json);
}

} // namespace util

} // namespace pels
} // namespace openpower
<commit_msg>PEL: Change variable name in pel.cpp<commit_after>/**
 * Copyright © 2019 IBM Corporation
 *
 * Licensed 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.
 */
#include "pel.hpp"

#include "bcd_time.hpp"
#include "extended_user_header.hpp"
#include "failing_mtms.hpp"
#include "json_utils.hpp"
#include "log_id.hpp"
#include "pel_rules.hpp"
#include "pel_values.hpp"
#include "section_factory.hpp"
#include "src.hpp"
#include "stream.hpp"
#include "user_data_formats.hpp"

#include <iostream>
#include <phosphor-logging/log.hpp>

namespace openpower
{
namespace pels
{
namespace message = openpower::pels::message;
namespace pv = openpower::pels::pel_values;
using namespace phosphor::logging;

constexpr auto unknownValue = "Unknown";

PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
         phosphor::logging::Entry::Level severity,
         const AdditionalData& additionalData,
         const DataInterfaceBase& dataIface)
{
    _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
                                          timestamp);
    _uh = std::make_unique<UserHeader>(regEntry, severity);

    auto src = std::make_unique<SRC>(regEntry, additionalData, dataIface);

    auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);

    _optionalSections.push_back(std::move(src));
    _optionalSections.push_back(std::move(euh));

    auto mtms = std::make_unique<FailingMTMS>(dataIface);
    _optionalSections.push_back(std::move(mtms));

    auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
    _optionalSections.push_back(std::move(ud));

    if (!additionalData.empty())
    {
        ud = util::makeADUserDataSection(additionalData);

        // To be safe, check there isn't too much data
        if (size() + ud->header().size <= _maxPELSize)
        {
            _optionalSections.push_back(std::move(ud));
        }
    }

    _ph->setSectionCount(2 + _optionalSections.size());

    checkRulesAndFix();
}

PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
{
}

PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
{
    populateFromRawData(data, obmcLogID);
}

void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
{
    Stream pelData{data};
    _ph = std::make_unique<PrivateHeader>(pelData);
    if (obmcLogID != 0)
    {
        _ph->setOBMCLogID(obmcLogID);
    }

    _uh = std::make_unique<UserHeader>(pelData);

    // Use the section factory to create the rest of the objects
    for (size_t i = 2; i < _ph->sectionCount(); i++)
    {
        auto section = section_factory::create(pelData);
        _optionalSections.push_back(std::move(section));
    }
}

bool PEL::valid() const
{
    bool valid = _ph->valid();

    if (valid)
    {
        valid = _uh->valid();
    }

    if (valid)
    {
        if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
                         [](const auto& section) { return section->valid(); }))
        {
            valid = false;
        }
    }

    return valid;
}

void PEL::setCommitTime()
{
    auto now = std::chrono::system_clock::now();
    _ph->setCommitTimestamp(getBCDTime(now));
}

void PEL::assignID()
{
    _ph->setID(generatePELID());
}

void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
{
    Stream pelData{pelBuffer};

    if (!valid())
    {
        log<level::WARNING>("Unflattening an invalid PEL");
    }

    _ph->flatten(pelData);
    _uh->flatten(pelData);

    for (auto& section : _optionalSections)
    {
        section->flatten(pelData);
    }
}

std::vector<uint8_t> PEL::data() const
{
    std::vector<uint8_t> pelData;
    flatten(pelData);
    return pelData;
}

size_t PEL::size() const
{
    size_t size = 0;

    if (_ph)
    {
        size += _ph->header().size;
    }

    if (_uh)
    {
        size += _uh->header().size;
    }

    for (const auto& section : _optionalSections)
    {
        size += section->header().size;
    }

    return size;
}

std::optional<SRC*> PEL::primarySRC() const
{
    auto src = std::find_if(
        _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
            return section->header().id ==
                   static_cast<uint16_t>(SectionID::primarySRC);
        });
    if (src != _optionalSections.end())
    {
        return static_cast<SRC*>(src->get());
    }

    return std::nullopt;
}

void PEL::checkRulesAndFix()
{
    auto [actionFlags, eventType] =
        pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity());

    _uh->setActionFlags(actionFlags);
    _uh->setEventType(eventType);
}

void PEL::printSectionInJSON(const Section& section, std::string& buf,
                             std::map<uint16_t, size_t>& pluralSections,
                             message::Registry& registry) const
{
    char tmpB[5];
    uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
                    static_cast<uint8_t>(section.header().id)};
    sprintf(tmpB, "%c%c", id[0], id[1]);
    std::string sectionID(tmpB);
    std::string sectionName = pv::sectionTitles.count(sectionID)
                                  ? pv::sectionTitles.at(sectionID)
                                  : "Unknown Section";

    // Add a count if there are multiple of this type of section
    auto count = pluralSections.find(section.header().id);
    if (count != pluralSections.end())
    {
        sectionName += " " + std::to_string(count->second);
        count->second++;
    }

    if (section.valid())
    {
        auto json = (sectionID == "PS" || sectionID == "SS")
                        ? section.getJSON(registry)
                        : section.getJSON();

        buf += "\"" + sectionName + "\": {\n";

        if (json)
        {
            buf += *json + "\n},\n";
        }
        else
        {
            jsonInsert(buf, pv::sectionVer,
                       getNumberString("%d", section.header().version), 1);
            jsonInsert(buf, pv::subSection,
                       getNumberString("%d", section.header().subType), 1);
            jsonInsert(buf, pv::createdBy,
                       getNumberString("0x%X", section.header().componentID),
                       1);

            std::vector<uint8_t> data;
            Stream s{data};
            section.flatten(s);
            std::string dstr =
                dumpHex(std::data(data) + SectionHeader::flattenedSize(),
                        data.size(), 2);

            std::string jsonIndent(indentLevel, 0x20);
            buf += jsonIndent + "\"Data\": [\n";
            buf += dstr;
            buf += jsonIndent + "]\n";
            buf += "},\n";
        }
    }
    else
    {
        buf += "\n\"Invalid Section\": [\n    \"invalid\"\n],\n";
    }
}

std::map<uint16_t, size_t> PEL::getPluralSections() const
{
    std::map<uint16_t, size_t> sectionCounts;

    for (const auto& section : optionalSections())
    {
        if (sectionCounts.find(section->header().id) == sectionCounts.end())
        {
            sectionCounts[section->header().id] = 1;
        }
        else
        {
            sectionCounts[section->header().id]++;
        }
    }

    std::map<uint16_t, size_t> sections;
    for (const auto& [id, count] : sectionCounts)
    {
        if (count > 1)
        {
            // Start with 0 here and printSectionInJSON()
            // will increment it as it goes.
            sections.emplace(id, 0);
        }
    }

    return sections;
}

void PEL::toJSON(message::Registry& registry) const
{
    auto sections = getPluralSections();

    std::string buf = "{\n";
    printSectionInJSON(*(_ph.get()), buf, sections, registry);
    printSectionInJSON(*(_uh.get()), buf, sections, registry);
    for (auto& section : this->optionalSections())
    {
        printSectionInJSON(*(section.get()), buf, sections, registry);
    }
    buf += "}";
    std::size_t found = buf.rfind(",");
    if (found != std::string::npos)
        buf.replace(found, 1, "");
    std::cout << buf << std::endl;
}

namespace util
{

std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
{
    auto jsonString = json.dump();
    std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());

    // Pad to a 4 byte boundary
    while ((jsonData.size() % 4) != 0)
    {
        jsonData.push_back(0);
    }

    return std::make_unique<UserData>(
        static_cast<uint16_t>(ComponentID::phosphorLogging),
        static_cast<uint8_t>(UserDataFormat::json),
        static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
}

std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
{
    assert(!ad.empty());
    nlohmann::json json;

    // Remove the 'ESEL' entry, as it contains a full PEL in the value.
    if (ad.getValue("ESEL"))
    {
        auto newAD = ad;
        newAD.remove("ESEL");
        json = newAD.toJSON();
    }
    else
    {
        json = ad.toJSON();
    }

    return makeJSONUserDataSection(json);
}

void addProcessNameToJSON(nlohmann::json& json,
                          const std::optional<std::string>& pid,
                          const DataInterfaceBase& dataIface)
{
    std::string name{unknownValue};

    try
    {
        if (pid)
        {
            auto n = dataIface.getProcessName(*pid);
            if (n)
            {
                name = *n;
            }
        }
    }
    catch (std::exception& e)
    {
    }

    json["Process Name"] = std::move(name);
}

void addBMCFWVersionIDToJSON(nlohmann::json& json,
                             const DataInterfaceBase& dataIface)
{
    auto id = dataIface.getBMCFWVersionID();
    if (id.empty())
    {
        id = unknownValue;
    }

    json["BMC Version ID"] = std::move(id);
}

std::string lastSegment(char separator, std::string data)
{
    auto pos = data.find_last_of(separator);
    if (pos != std::string::npos)
    {
        data = data.substr(pos + 1);
    }

    return data;
}

void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
{
    json["BMCState"] = lastSegment('.', dataIface.getBMCState());
    json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
    json["HostState"] = lastSegment('.', dataIface.getHostState());
}

std::unique_ptr<UserData>
    makeSysInfoUserDataSection(const AdditionalData& ad,
                               const DataInterfaceBase& dataIface)
{
    nlohmann::json json;

    addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
    addBMCFWVersionIDToJSON(json, dataIface);
    addStatesToJSON(json, dataIface);

    return makeJSONUserDataSection(json);
}

} // namespace util

} // namespace pels
} // namespace openpower
<|endoftext|>


<commit_before>#include <iostream>

#include <llvm/Support/CommandLine.h>
#include <llvm/System/Signals.h>

#include "Console.h"
#include "EditLineReader.h"

using std::string;
using ccons::Console;
using ccons::EditLineReader;

static llvm::cl::opt<bool>
	DebugMode("ccons-debug", llvm::cl::desc("Print debugging information"));

int main(const int argc, char **argv)
{
	llvm::cl::ParseCommandLineOptions(argc, argv, "ccons Interactive C Console\n");
	llvm::sys::PrintStackTraceOnErrorSignal();

	if (DebugMode)
		fprintf(stderr, "NOTE: Debugging information will be displayed.\n");

	Console console(DebugMode);

	EditLineReader reader;
	const char *line = reader.readLine(console.prompt(), console.input());
	while (line) {
		console.process(line);
		line = reader.readLine(console.prompt(), console.input());
	}

	return 0;
}

<commit_msg>first stab at multi-process architecture. portability thrown out the window...<commit_after>#include <iostream>

#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>

#include <llvm/ADT/OwningPtr.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/System/Signals.h>

#include "Console.h"
#include "EditLineReader.h"

using std::string;
using ccons::Console;
using ccons::LineReader;
using ccons::EditLineReader;
using ccons::StdInLineReader;

static llvm::cl::opt<bool>
	DebugMode("ccons-debug", llvm::cl::desc("Print debugging information"));
static llvm::cl::opt<bool>
	UseStdIo("use-std-io", llvm::cl::desc("Use standard IO for input and output"));
static llvm::cl::opt<bool>
	MultiProcess("multi-process", llvm::cl::desc("Run in multi-process mode"));

static void *pipe_input(void *ptr)
{
	FILE *ps = (FILE *) ptr;
	char buf[1024];
	while (1) {
		const char *s = fgets(buf, sizeof(buf), ps);
		if (s) printf("%s", buf);
	}
	return NULL;
}

int main(const int argc, char **argv)
{
	llvm::cl::ParseCommandLineOptions(argc, argv, "ccons Interactive C Console\n");
	llvm::sys::PrintStackTraceOnErrorSignal();

	if (DebugMode)
		fprintf(stderr, "NOTE: Debugging information will be displayed.\n");

	Console console(DebugMode);
	llvm::OwningPtr<LineReader> reader;

	FILE *ps;
	pthread_t reader_thread;

	if (MultiProcess) {
		ps = popen("./ccons --use-std-io", "r+");
		assert(ps);
		fcntl(fileno(ps), F_SETFL, O_NONBLOCK);
		pthread_create(&reader_thread, NULL, pipe_input, (void *) ps);
	}

	if (UseStdIo)
		reader.reset(new StdInLineReader);
	else
		reader.reset(new EditLineReader);

	const char *line = reader->readLine(console.prompt(), console.input());
	while (line) {
		if (MultiProcess) {
			fputs(line, ps);
			usleep(100000);
		} else {
			console.process(line);
		}
		line = reader->readLine(console.prompt(), console.input());
	}

	if (MultiProcess)
		pclose(ps);

	return 0;
}

<|endoftext|>


<commit_before>#include <iostream>
#include <histedit.h>

#include "Console.h"

using std::string;
using ccons::Console;

static Console * cc;

static const char *ccons_prompt(EditLine *e)
{
	return (cc ? cc->prompt() : "??? ");
}

int main(const int argc, const char **argv)
{
	EditLine *e = el_init("ccons", stdin, stdout, stderr);
	el_set(e, EL_PROMPT, ccons_prompt);

	Console console;
	cc = &console;
	const char *line = el_gets(e, NULL);
	while (line) {
		console.process(line);
		// FIXME: el_push() is broken... the second parameter should be const char *
		el_push(e, const_cast<char*>(console.input()));
		line = el_gets(e, NULL);
	}
	el_end(e);

	return 0;
}

<commit_msg>add command history and set the default editing mode to emacs<commit_after>#include <iostream>
#include <editline/readline.h>
#include <histedit.h>

#include "Console.h"

using std::string;
using ccons::Console;

static Console * cc;

static const char *ccons_prompt(EditLine *e)
{
	return (cc ? cc->prompt() : "??? ");
}

int main(const int argc, const char **argv)
{
	HistEvent event;
	History *h = history_init();
	history(h, &event, H_SETSIZE, INT_MAX);

	EditLine *e = el_init("ccons", stdin, stdout, stderr);
	el_set(e, EL_PROMPT, ccons_prompt);
	el_set(e, EL_EDITOR, "emacs");
	el_set(e, EL_HIST, history, h);

	Console console;
	cc = &console;
	const char *line = el_gets(e, NULL);
	while (line) {
		console.process(line);
		history(h, &event, H_ENTER, line);
		// FIXME: el_push() is broken... the second parameter should be const char *
		el_push(e, const_cast<char*>(console.input()));
		line = el_gets(e, NULL);
	}
	el_end(e);
	history_end(h);

	return 0;
}

<|endoftext|>


<commit_before>#include "./constraint_updater.h"
#include <Eigen/Geometry>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/polygon/polygon.hpp>
#include <vector>
#include "../graphics/vertex_array.h"
#include "../graphics/render_data.h"
BOOST_GEOMETRY_REGISTER_POINT_2D(Eigen::Vector2i, int, cs::cartesian, x(), y())
#include "./boost_polygon_concepts.h"

namespace bg = boost::geometry;

// ccw, open polygon
typedef bg::model::polygon<Eigen::Vector2i, false, false> polygon;

ConstraintUpdater::ConstraintUpdater(
    Graphics::Gl *gl, std::shared_ptr<Graphics::ShaderManager> shaderManager,
    int width, int height)
  : gl(gl), shaderManager(shaderManager), width(width), height(height)
{
  shaderId = shaderManager->addShader(":/shader/constraint.vert",
                                      ":/shader/colorImmediate.frag");

  Eigen::Affine3f pixelToNDCTransform(
      Eigen::Translation3f(Eigen::Vector3f(-1, 1, 0)) *
      Eigen::Scaling(Eigen::Vector3f(2.0f / width, -2.0f / height, 1)));
  pixelToNDC = pixelToNDCTransform.matrix();
}

polygon createBoxPolygon(Eigen::Vector2i center, Eigen::Vector2i size)
{
  polygon p;
  p.outer().push_back(
      Eigen::Vector2i(center.x() - size.x(), center.y() - size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() + size.x(), center.y() - size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() + size.x(), center.y() + size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() - size.x(), center.y() + size.y()));

  return p;
}

boost::polygon::polygon_with_holes_data<int> minkowskiSum(const polygon &a,
                                                          const polygon &b)
{
  boost::polygon::polygon_with_holes_data<int> aPoly;
  boost::polygon::set_points(aPoly, a.outer().begin(), a.outer().end());

  boost::polygon::polygon_with_holes_data<int> bPoly;
  boost::polygon::set_points(bPoly, b.outer().begin(), b.outer().end());

  boost::polygon::polygon_set_data<int> dilated;
  boost::polygon::detail::minkowski_offset<int>::convolve_two_point_sequences(
      dilated, boost::polygon::begin_points(aPoly),
      boost::polygon::end_points(aPoly), boost::polygon::begin_points(bPoly),
      boost::polygon::end_points(bPoly));

  std::vector<boost::polygon::polygon_with_holes_data<int>> polys;
  dilated.get(polys);
  assert(polys.size() == 1);

  return polys[0];
}

void ConstraintUpdater::addLabel(Eigen::Vector2i anchorPosition,
                                 Eigen::Vector2i labelSize,
                                 Eigen::Vector2i lastAnchorPosition,
                                 Eigen::Vector2i lastLabelPosition,
                                 Eigen::Vector2i lastLabelSize)
{

  polygon oldLabel = createBoxPolygon(lastLabelPosition, lastLabelSize / 2);

  polygon oldLabelExtruded(oldLabel);
  for (auto point : oldLabel.outer())
  {
    Eigen::Vector2i p = anchorPosition + 1000 * (point - anchorPosition);
    oldLabelExtruded.outer().push_back(p);
  }

  polygon oldLabelExtrudedConvexHull;
  bg::convex_hull(oldLabelExtruded, oldLabelExtrudedConvexHull);

  int border = 2;
  polygon newLabel = createBoxPolygon(
      Eigen::Vector2i(0, 0), labelSize / 2 + Eigen::Vector2i(border, border));

  auto dilatedOldLabelExtruded =
      minkowskiSum(oldLabelExtrudedConvexHull, newLabel);
  std::vector<boost::polygon::point_data<int>> points(
      dilatedOldLabelExtruded.begin(), dilatedOldLabelExtruded.end());
  drawPolygon(points);
  drawPolygon(oldLabelExtrudedConvexHull.outer());

  polygon connectorPolygon;
  connectorPolygon.outer().push_back(lastAnchorPosition);
  Eigen::Vector2i throughLastAnchor =
      anchorPosition + 1000 * (lastAnchorPosition - anchorPosition);
  connectorPolygon.outer().push_back(throughLastAnchor);

  Eigen::Vector2i throughLastLabel =
      anchorPosition + 1000 * (lastLabelPosition - anchorPosition);
  connectorPolygon.outer().push_back(throughLastLabel);
  connectorPolygon.outer().push_back(lastLabelPosition);

  auto dilatedConnector = minkowskiSum(connectorPolygon, newLabel);
  std::vector<boost::polygon::point_data<int>> pointsConnector(
      dilatedConnector.begin(), dilatedConnector.end());
  drawPolygon(pointsConnector);
  drawPolygon(connectorPolygon.outer());
}

void ConstraintUpdater::clear()
{
  gl->glViewport(0, 0, width, height);
  gl->glClearColor(0, 0, 0, 0);
  gl->glClear(GL_COLOR_BUFFER_BIT);
}

template <class T> void ConstraintUpdater::drawPolygon(std::vector<T> polygon)
{
  std::vector<float> positions;
  if (polygon.size() > 0)
  {
    auto point = polygon[0];
    positions.push_back(point.x());
    positions.push_back(height - point.y());
    positions.push_back(0.0f);
  }
  for (auto point : polygon)
  {
    positions.push_back(point.x());
    positions.push_back(height - point.y());
    positions.push_back(0.0f);
  }

  Graphics::VertexArray *vertexArray =
      new Graphics::VertexArray(gl, GL_TRIANGLE_FAN);
  vertexArray->addStream(positions);

  RenderData renderData;
  renderData.modelMatrix = Eigen::Matrix4f::Identity();
  renderData.viewMatrix = pixelToNDC;
  renderData.projectionMatrix = Eigen::Matrix4f::Identity();
  shaderManager->bind(shaderId, renderData);
  vertexArray->draw();
}

<commit_msg>Use minkowski for two polygon sets to fix wrong result.<commit_after>#include "./constraint_updater.h"
#include <Eigen/Geometry>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/polygon/polygon.hpp>
#include <vector>
#include "../graphics/vertex_array.h"
#include "../graphics/render_data.h"
BOOST_GEOMETRY_REGISTER_POINT_2D(Eigen::Vector2i, int, cs::cartesian, x(), y())
#include "./boost_polygon_concepts.h"

namespace bg = boost::geometry;

// ccw, open polygon
typedef bg::model::polygon<Eigen::Vector2i, false, false> polygon;

ConstraintUpdater::ConstraintUpdater(
    Graphics::Gl *gl, std::shared_ptr<Graphics::ShaderManager> shaderManager,
    int width, int height)
  : gl(gl), shaderManager(shaderManager), width(width), height(height)
{
  shaderId = shaderManager->addShader(":/shader/constraint.vert",
                                      ":/shader/colorImmediate.frag");

  Eigen::Affine3f pixelToNDCTransform(
      Eigen::Translation3f(Eigen::Vector3f(-1, 1, 0)) *
      Eigen::Scaling(Eigen::Vector3f(2.0f / width, -2.0f / height, 1)));
  pixelToNDC = pixelToNDCTransform.matrix();
}

polygon createBoxPolygon(Eigen::Vector2i center, Eigen::Vector2i size)
{
  polygon p;
  p.outer().push_back(
      Eigen::Vector2i(center.x() - size.x(), center.y() - size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() + size.x(), center.y() - size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() + size.x(), center.y() + size.y()));
  p.outer().push_back(
      Eigen::Vector2i(center.x() - size.x(), center.y() + size.y()));

  return p;
}

boost::polygon::polygon_with_holes_data<int> minkowskiSum(const polygon &a,
                                                          const polygon &b)
{
  boost::polygon::polygon_with_holes_data<int> aPoly;
  boost::polygon::set_points(aPoly, a.outer().begin(), a.outer().end());

  boost::polygon::polygon_with_holes_data<int> bPoly;
  boost::polygon::set_points(bPoly, b.outer().begin(), b.outer().end());

  boost::polygon::polygon_set_data<int> dilated;
  boost::polygon::polygon_set_data<int> aPolys;
  aPolys.insert(aPoly);
  boost::polygon::polygon_set_data<int> bPolys;
  bPolys.insert(bPoly);
  boost::polygon::detail::minkowski_offset<int>::convolve_two_polygon_sets(
      dilated, aPolys, bPolys);

  std::vector<boost::polygon::polygon_with_holes_data<int>> polys;
  dilated.get(polys);
  assert(polys.size() == 1);

  return polys[0];
}

void ConstraintUpdater::addLabel(Eigen::Vector2i anchorPosition,
                                 Eigen::Vector2i labelSize,
                                 Eigen::Vector2i lastAnchorPosition,
                                 Eigen::Vector2i lastLabelPosition,
                                 Eigen::Vector2i lastLabelSize)
{

  polygon oldLabel = createBoxPolygon(lastLabelPosition, lastLabelSize / 2);

  polygon oldLabelExtruded(oldLabel);
  for (auto point : oldLabel.outer())
  {
    Eigen::Vector2i p = anchorPosition + 1000 * (point - anchorPosition);
    oldLabelExtruded.outer().push_back(p);
  }

  polygon oldLabelExtrudedConvexHull;
  bg::convex_hull(oldLabelExtruded, oldLabelExtrudedConvexHull);

  int border = 2;
  polygon newLabel = createBoxPolygon(
      Eigen::Vector2i(0, 0), labelSize / 2 + Eigen::Vector2i(border, border));

  auto dilatedOldLabelExtruded =
      minkowskiSum(oldLabelExtrudedConvexHull, newLabel);
  std::vector<boost::polygon::point_data<int>> points(
      dilatedOldLabelExtruded.begin(), dilatedOldLabelExtruded.end());
  drawPolygon(points);
  drawPolygon(oldLabelExtrudedConvexHull.outer());

  polygon connectorPolygon;
  connectorPolygon.outer().push_back(lastAnchorPosition);
  Eigen::Vector2i throughLastAnchor =
      anchorPosition + 1000 * (lastAnchorPosition - anchorPosition);
  connectorPolygon.outer().push_back(throughLastAnchor);

  Eigen::Vector2i throughLastLabel =
      anchorPosition + 1000 * (lastLabelPosition - anchorPosition);
  connectorPolygon.outer().push_back(throughLastLabel);
  connectorPolygon.outer().push_back(lastLabelPosition);

  auto dilatedConnector = minkowskiSum(connectorPolygon, newLabel);
  std::vector<boost::polygon::point_data<int>> pointsConnector(
      dilatedConnector.begin(), dilatedConnector.end());
  drawPolygon(pointsConnector);
  drawPolygon(connectorPolygon.outer());
}

void ConstraintUpdater::clear()
{
  gl->glViewport(0, 0, width, height);
  gl->glClearColor(0, 0, 0, 0);
  gl->glClear(GL_COLOR_BUFFER_BIT);
}

template <class T> void ConstraintUpdater::drawPolygon(std::vector<T> polygon)
{
  std::vector<float> positions;
  if (polygon.size() > 0)
  {
    auto point = polygon[0];
    positions.push_back(point.x());
    positions.push_back(height - point.y());
    positions.push_back(0.0f);
  }
  for (auto point : polygon)
  {
    positions.push_back(point.x());
    positions.push_back(height - point.y());
    positions.push_back(0.0f);
  }

  Graphics::VertexArray *vertexArray =
      new Graphics::VertexArray(gl, GL_TRIANGLE_FAN);
  vertexArray->addStream(positions);

  RenderData renderData;
  renderData.modelMatrix = Eigen::Matrix4f::Identity();
  renderData.viewMatrix = pixelToNDC;
  renderData.projectionMatrix = Eigen::Matrix4f::Identity();
  shaderManager->bind(shaderId, renderData);
  vertexArray->draw();
}

<|endoftext|>


<commit_before>#pragma once

#include "compiler_features.hpp"

#include <array>
#include <cstdint>
#include <limits>
#include <climits>

/* Usage:
 *
 * enum class my_flag : size_t {
 *   foo0 = 0,
 *   foo1 = 1,
 *   // ...
 *   foo10 = 10,
 *   Last = foo10,
 * };
 *
 * using my_flags = caney::flags<my_flag>;
 * CANEY_FLAGS(my_flags)
 *
 * The base enum defines the indices to look up in a bitset; you should use an enum class so there are no predefined (and wrong) bit-wise operators.
 *
 * Bit operations |, & and ^ usually work on the complete bitset; only &, when one parameter is a single flag, will simple test whether the flag is set.
 */

#define CANEY_FLAGS(Flags) \
	Flags operator|(Flags::flag_t a, Flags::flag_t b) { return Flags(a) | b; } \
	Flags operator|(Flags::flag_t a, Flags b) { return Flags(a) | b; } \
	bool operator&(Flags::flag_t a, Flags::flag_t b) = delete; \
	bool operator&(Flags::flag_t a, Flags b) { return b & a; } \
	Flags operator^(Flags::flag_t a, Flags::flag_t b) { return Flags(a) ^ b; } \
	Flags operator^(Flags::flag_t a, Flags b) { return Flags(a) ^ b; } \
	Flags operator~(Flags::flag_t a) { return ~Flags(a); }

namespace caney {
	inline namespace stdv1 {
		namespace impl_traits {
			// idea from http://stackoverflow.com/a/10724828/1478356
			template<typename Enum, bool B = std::is_enum<Enum>::value>
			struct is_scoped_enum : std::false_type {
			};

			template<typename Enum>
			struct is_scoped_enum<Enum, true>
				: std::integral_constant<
					bool,
					!std::is_convertible<Enum, std::underlying_type_t<Enum>>::value> {
			};
		}

		template<typename FlagEnum, std::size_t Size = static_cast<std::size_t>(FlagEnum::Last) + 1, typename Elem = std::uint32_t>
		class flags {
		private:
			typedef std::underlying_type_t<FlagEnum> enum_t;
		public:
			static_assert(impl_traits::is_scoped_enum<FlagEnum>::value, "Only scoped enums allowed");
			static_assert(!std::numeric_limits<enum_t>::is_signed, "Only enums with unsigned underlying types allowed");
			static_assert(std::numeric_limits<Elem>::is_integer, "Only unsigned integers allowed as underlying array elements for flags");
			static_assert(!std::numeric_limits<Elem>::is_signed, "Only unsigned integers allowed as underlying array elements for flags");

			static_assert(8 == CHAR_BIT, "byte should have exactly 8 bits");
			static constexpr std::size_t BITS_PER_ELEM = sizeof(Elem)*CHAR_BIT;

			// how many array entries are needed to store all bits
			static constexpr std::size_t ARRAY_SIZE = (Size + BITS_PER_ELEM - 1)/BITS_PER_ELEM;
			static_assert(ARRAY_SIZE > 0, "Invalid array size");

			// usable bits in the last entry
			static constexpr Elem LAST_ENTRY_MASK = (Size % BITS_PER_ELEM == 0) ? ~Elem{0} : ((Elem{1} << (Size % BITS_PER_ELEM)) - Elem{1});

			typedef std::array<Elem, ARRAY_SIZE> array_t;
			typedef FlagEnum flag_t;

			static constexpr std::size_t size() {
				return Size;
			}

			class reference {
			public:
				reference& operator=(bool value) {
					if (value) {
						set();
					} else {
						reset();
					}
					return *this;
				}

				void set() {
					*m_elem |= m_mask;
				}

				void reset() {
					*m_elem &= ~m_mask;
				}

				void flip() {
					*m_elem ^= m_mask;
				}

				bool test() const {
					return 0 != (*m_elem & m_mask);
				}

				explicit operator bool() const {
					return test();
				}

			private:
				friend class flags<FlagEnum, Size, Elem>;
				explicit reference(Elem& elem, Elem mask)
				: m_elem(&elem), m_mask(mask) {
				}

				Elem* m_elem;
				Elem m_mask;
			};

			explicit flags() = default;
			explicit flags(array_t const& raw)
			: m_array(raw) {
			}
			// implicit
			flags(flag_t flag)
			{
				set(flag);
			}

			reference operator[](flag_t flag) {
				size_t flagNdx{static_cast<enum_t>(flag)};
				Elem const mask = Elem{1} << (flagNdx % BITS_PER_ELEM);
				return reference(m_array[flagNdx / BITS_PER_ELEM], mask);
			}

			CANEY_RELAXED_CONSTEXPR bool operator[](flag_t flag) const {
				size_t flagNdx{static_cast<enum_t>(flag)};
				Elem const mask = Elem{1} << (flagNdx % BITS_PER_ELEM);
				return 0 != (m_array[flagNdx / BITS_PER_ELEM] & mask);
			}

			constexpr bool operator==(flags const& other) const {
				return m_array == other.m_array;
			}

			constexpr bool operator!=(flags const& other) const {
				return m_array != other.m_array;
			}

			void set(flag_t flag) {
				operator[](flag).set();
			}

			void reset(flag_t flag) {
				operator[](flag).reset();
			}

			void flip(flag_t flag) {
				operator[](flag).flip();
			}

			constexpr bool test(flag_t flag) const {
				return operator[](flag);
			}

			void clear() {
				m_array = array_t{};
			}

			bool operator&=(flag_t) = delete;
			constexpr bool operator&(flag_t flag) const {
				return test(flag);
			}

			flags& operator&=(flags const& other) {
				for (size_t i = 0; i < ARRAY_SIZE; ++i) {
					m_array[i] &= other.m_array[i];
				}
				return *this;
			}
			CANEY_RELAXED_CONSTEXPR flags operator&(flags const& other) const { flags tmp(*this); tmp &= other; return tmp; }

			flags& operator|=(flag_t flag) {
				set(flag);
				return *this;
			}

			flags& operator|=(flags const& other) {
				for (size_t i = 0; i < ARRAY_SIZE; ++i) {
					m_array[i] |= other.m_array[i];
				}
				return *this;
			}
			CANEY_RELAXED_CONSTEXPR flags operator|(flags const& other) const { flags tmp(*this); tmp |= other; return tmp; }

			flags& operator^=(flag_t flag) {
				flip(flag);
				return *this;
			}

			flags& operator^=(flags const& other) {
				for (size_t i = 0; i < ARRAY_SIZE; ++i) {
					m_array[i] ^= other.m_array[i];
				}
				return *this;
			}
			CANEY_RELAXED_CONSTEXPR flags operator^(flags const& other) const { flags tmp(*this); tmp ^= other; return tmp; }

			CANEY_RELAXED_CONSTEXPR flags operator~() const {
				flags tmp(*this);
				tmp.flip_all();
				return tmp;
			}

			void flip_all() {
				for (size_t i = 0; i < ARRAY_SIZE - 1; ++i) {
					m_array[i] = ~m_array[i];
				}
				m_array[ARRAY_SIZE-1] ^= LAST_ENTRY_MASK;
			}

			constexpr bool none() const {
				return m_array == array_t{};
			}

			constexpr bool any() const {
				return !none();
			}

			CANEY_RELAXED_CONSTEXPR bool all() const {
				for (size_t i = 0; i < ARRAY_SIZE - 1; ++i) {
					if (0 != ~m_array[i]) return false;
				}
				return m_array[ARRAY_SIZE-1] == LAST_ENTRY_MASK;
			}

			array_t& underlying_array() {
				return m_array;
			}

			array_t const& underlying_array() const {
				return m_array;
			}

		private:
			array_t m_array{};
		};
	}
} // namespace caney
<commit_msg>fix gcc 4.9 warning in flags<commit_after>#pragma once

#include "compiler_features.hpp"

#include <array>
#include <cstdint>
#include <limits>
#include <climits>

/* Usage:
 *
 * enum class my_flag : size_t {
 *   foo0 = 0,
 *   foo1 = 1,
 *   // ...
 *   foo10 = 10,
 *   Last = foo10,
 * };
 *
 * using my_flags = caney::flags<my_flag>;
 * CANEY_FLAGS(my_flags)
 *
 * The base enum defines the indices to look up in a bitset; you should use an enum class so there are no predefined (and wrong) bit-wise operators.
 *
 * Bit operations |, & and ^ usually work on the complete bitset; only &, when one parameter is a single flag, will simple test whether the flag is set.
 */

#define CANEY_FLAGS(Flags) \
	Flags operator|(Flags::flag_t a, Flags::flag_t b) { return Flags(a) | b; } \
	Flags operator|(Flags::flag_t a, Flags b) { return Flags(a) | b; } \
	bool operator&(Flags::flag_t a, Flags::flag_t b) = delete; \
	bool operator&(Flags::flag_t a, Flags b) { return b & a; } \
	Flags operator^(Flags::flag_t a, Flags::flag_t b) { return Flags(a) ^ b; } \
	Flags operator^(Flags::flag_t a, Flags b) { return Flags(a) ^ b; } \
	Flags operator~(Flags::flag_t a) { return ~Flags(a); }

namespace caney {
	inline namespace stdv1 {
		namespace impl_traits {
			// idea from http://stackoverflow.com/a/10724828/1478356
			template<typename Enum, bool B = std::is_enum<Enum>::value>
			struct is_scoped_enum : std::false_type {
			};

			template<typename Enum>
			struct is_scoped_enum<Enum, true>
				: std::integral_constant<
					bool,
					!std::is_convertible<Enum, std::underlying_type_t<Enum>>::value> {
			};
		}

		template<typename FlagEnum, std::size_t Size = static_cast<std::size_t>(FlagEnum::Last) + 1, typename Elem = std::uint32_t>
		class flags {
		private:
			typedef std::underlying_type_t<FlagEnum> enum_t;
		public:
			static_assert(impl_traits::is_scoped_enum<FlagEnum>::value, "Only scoped enums allowed");
			static_assert(!std::numeric_limits<enum_t>::is_signed, "Only enums with unsigned underlying types allowed");
			static_assert(std::numeric_limits<Elem>::is_integer, "Only unsigned integers allowed as underlying array elements for flags");
			static_assert(!std::numeric_limits<Elem>::is_signed, "Only unsigned integers allowed as underlying array elements for flags");

			static_assert(8 == CHAR_BIT, "byte should have exactly 8 bits");
			static constexpr std::size_t BITS_PER_ELEM = sizeof(Elem)*CHAR_BIT;

			// how many array entries are needed to store all bits
			static constexpr std::size_t ARRAY_SIZE = (Size + BITS_PER_ELEM - 1)/BITS_PER_ELEM;
			static_assert(ARRAY_SIZE > 0, "Invalid array size");

			// usable bits in the last entry
			static constexpr Elem LAST_ENTRY_MASK = (Size % BITS_PER_ELEM == 0) ? ~Elem{0} : ((Elem{1} << (Size % BITS_PER_ELEM)) - Elem{1});

			typedef std::array<Elem, ARRAY_SIZE> array_t;
			typedef FlagEnum flag_t;

			static constexpr std::size_t size() {
				return Size;
			}

			class reference {
			public:
				reference& operator=(bool value) {
					if (value) {
						set();
					} else {
						reset();
					}
					return *this;
				}

				void set() {
					*m_elem |= m_mask;
				}

				void reset() {
					*m_elem &= ~m_mask;
				}

				void flip() {
					*m_elem ^= m_mask;
				}

				bool test() const {
					return 0 != (*m_elem & m_mask);
				}

				explicit operator bool() const {
					return test();
				}

			private:
				friend class flags<FlagEnum, Size, Elem>;
				explicit reference(Elem& elem, Elem mask)
				: m_elem(&elem), m_mask(mask) {
				}

				Elem* m_elem;
				Elem m_mask;
			};

			explicit flags() = default;
			explicit flags(array_t const& raw)
			: m_array(raw) {
			}
			// implicit
			flags(flag_t flag)
			{
				set(flag);
			}

			reference operator[](flag_t flag) {
				size_t flagNdx{static_cast<enum_t>(flag)};
				Elem const mask = Elem{1} << (flagNdx % BITS_PER_ELEM);
				return reference(m_array[flagNdx / BITS_PER_ELEM], mask);
			}

			CANEY_RELAXED_CONSTEXPR bool operator[](flag_t flag) const {
				size_t flagNdx{static_cast<enum_t>(flag)};
				Elem const mask = Elem{1} << (flagNdx % BITS_PER_ELEM);
				return 0 != (m_array[flagNdx / BITS_PER_ELEM] & mask);
			}

			constexpr bool operator==(flags const& other) const {
				return m_array == other.m_array;
			}

			constexpr bool operator!=(flags const& other) const {
				return m_array != other.m_array;
			}

			void set(flag_t flag) {
				operator[](flag).set();
			}

			void reset(flag_t flag) {
				operator[](flag).reset();
			}

			void flip(flag_t flag) {
				operator[](flag).flip();
			}

			constexpr bool test(flag_t flag) const {
				return operator[](flag);
			}

			void clear() {
				m_array = array_t{{}};
			}

			bool operator&=(flag_t) = delete;
			constexpr bool operator&(flag_t flag) const {
				return test(flag);
			}

			flags& operator&=(flags const& other) {
				for (size_t i = 0; i < ARRAY_SIZE; ++i) {
					m_array[i] &= other.m_array[i];
				}
				return *this;
			}
			CANEY_RELAXED_CONSTEXPR flags operator&(flags const& other) const { flags tmp(*this); tmp &= other; return tmp; }

			flags& operator|=(flag_t flag) {
				set(flag);
				return *this;
			}

			flags& operator|=(flags const& other) {
				for (size_t i = 0; i < ARRAY_SIZE; ++i) {
					m_array[i] |= other.m_array[i];
				}
				return *this;
			}
			CANEY_RELAXED_CONSTEXPR flags operator|(flags const& other) const { flags tmp(*this); tmp |= other; return tmp; }

			flags& operator^=(flag_t flag) {
				flip(flag);
				return *this;
			}

			flags& operator^=(flags const& other) {
				for (size_t i = 0; i < ARRAY_SIZE; ++i) {
					m_array[i] ^= other.m_array[i];
				}
				return *this;
			}
			CANEY_RELAXED_CONSTEXPR flags operator^(flags const& other) const { flags tmp(*this); tmp ^= other; return tmp; }

			CANEY_RELAXED_CONSTEXPR flags operator~() const {
				flags tmp(*this);
				tmp.flip_all();
				return tmp;
			}

			void flip_all() {
				for (size_t i = 0; i < ARRAY_SIZE - 1; ++i) {
					m_array[i] = ~m_array[i];
				}
				m_array[ARRAY_SIZE-1] ^= LAST_ENTRY_MASK;
			}

			constexpr bool none() const {
				return m_array == array_t{{}};
			}

			constexpr bool any() const {
				return !none();
			}

			CANEY_RELAXED_CONSTEXPR bool all() const {
				for (size_t i = 0; i < ARRAY_SIZE - 1; ++i) {
					if (0 != ~m_array[i]) return false;
				}
				return m_array[ARRAY_SIZE-1] == LAST_ENTRY_MASK;
			}

			array_t& underlying_array() {
				return m_array;
			}

			array_t const& underlying_array() const {
				return m_array;
			}

		private:
			array_t m_array{{}};
		};
	}
} // namespace caney
<|endoftext|>


<commit_before>/***********************************************************************
 cgi_jpeg.cpp - Example code showing how to fetch JPEG data from a BLOB
 	column and send it back to a browser that requested it by ID.

	Use load_jpeg.cpp to load JPEG files into the database we query.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ 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.

 MySQL++ 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 MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include <mysql++.h>

using namespace std;
using namespace mysqlpp;

#define IMG_DATABASE	"mysql_cpp_data"
#define IMG_HOST		"localhost"
#define IMG_USER		"root"
#define IMG_PASSWORD 	"nunyabinness"

int
main(int argc, char *argv[])
{
	unsigned int img_id = 0;
	char* cgi_query = getenv("QUERY_STRING");
	if (cgi_query) {
		if ((strlen(cgi_query) < 4) || memcmp(cgi_query, "id=", 3)) {
			cout << "Content-type: text/plain" << endl << endl;
			cout << "ERROR: Bad query string" << endl;
			return 1;
		}
		else {
			img_id = atoi(cgi_query + 3);
		}
	}
	else {
		cerr << "Put this program into a web server's cgi-bin "
				"directory, then" << endl;
		cerr << "invoke it with a URL like this:" << endl;
		cerr << endl;
		cerr << "    http://server.name.com/cgi-bin/cgi_image?id=2" <<
				endl;
		cerr << endl;
		cerr << "This will retrieve the image with ID 2." << endl;
		cerr << endl;
		cerr << "You will probably have to change some of the #defines "
				"at the top of" << endl;
		cerr << "examples/cgi_image.cpp to allow the lookup to work." <<
				endl;
		return 1;
	}

	Connection con(use_exceptions);
	try {
		con.connect(IMG_DATABASE, IMG_HOST, IMG_USER, IMG_PASSWORD);
		Query query = con.query();
		query << "SELECT data FROM images WHERE id = " << img_id;
		Row row;
		Result res = query.store();
		if (res && (res.num_rows() > 0) && (row = res.at(0))) {
			unsigned long length = row.at(0).size();
			cout << "Content-type: image/jpeg" << endl;
			cout << "Content-length: " << length << endl << endl;
			fwrite(row.at(0).data(), 1, length, stdout);
		}
		else {
			cout << "Content-type: text/plain" << endl << endl;
			cout << "ERROR: No such image with ID " << img_id << endl;
		}
	}
	catch (const BadQuery& er) {
		// Handle any query errors
		cout << "Content-type: text/plain" << endl << endl;
		cout << "QUERY ERROR: " << er.what() << endl;
		return 1;
	}
	catch (const Exception& er) {
		// Catch-all for any other MySQL++ exceptions
		cout << "Content-type: text/plain" << endl << endl;
		cout << "GENERAL ERROR: " << er.what() << endl;
		return 1;
	}

	return 0;
}
<commit_msg>Reworked cgi_jpeg example's code style a bit.  Not necessarily better, just a step along the road toward making it use SSQLS.<commit_after>/***********************************************************************
 cgi_jpeg.cpp - Example code showing how to fetch JPEG data from a BLOB
 	column and send it back to a browser that requested it by ID.

	Use load_jpeg.cpp to load JPEG files into the database we query.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ 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.

 MySQL++ 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 MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include <mysql++.h>

using namespace std;
using namespace mysqlpp;

#define IMG_DATABASE	"mysql_cpp_data"
#define IMG_HOST		"localhost"
#define IMG_USER		"root"
#define IMG_PASSWORD 	"nunyabinness"

int
main()
{
	unsigned int img_id = 0;
	char* cgi_query = getenv("QUERY_STRING");
	if (cgi_query) {
		if ((strlen(cgi_query) < 4) || memcmp(cgi_query, "id=", 3)) {
			cout << "Content-type: text/plain" << endl << endl;
			cout << "ERROR: Bad query string" << endl;
			return 1;
		}
		else {
			img_id = atoi(cgi_query + 3);
		}
	}
	else {
		cerr << "Put this program into a web server's cgi-bin "
				"directory, then" << endl;
		cerr << "invoke it with a URL like this:" << endl;
		cerr << endl;
		cerr << "    http://server.name.com/cgi-bin/cgi_image?id=2" <<
				endl;
		cerr << endl;
		cerr << "This will retrieve the image with ID 2." << endl;
		cerr << endl;
		cerr << "You will probably have to change some of the #defines "
				"at the top of" << endl;
		cerr << "examples/cgi_image.cpp to allow the lookup to work." <<
				endl;
		return 1;
	}

	Connection con(use_exceptions);
	try {
		con.connect(IMG_DATABASE, IMG_HOST, IMG_USER, IMG_PASSWORD);
		Query query = con.query();
		query << "SELECT data FROM images WHERE id = " << img_id;
		ResUse res = query.use();
		if (res) {
			Row row = res.fetch_row();
			unsigned long length = row.raw_size(0);
			cout << "Content-type: image/jpeg" << endl;
			cout << "Content-length: " << length << endl << endl;
			fwrite(row.raw_data(0), 1, length, stdout);
		}
		else {
			cout << "Content-type: text/plain" << endl << endl;
			cout << "ERROR: No such image with ID " << img_id << endl;
		}
	}
	catch (const BadQuery& er) {
		// Handle any query errors
		cout << "Content-type: text/plain" << endl << endl;
		cout << "QUERY ERROR: " << er.what() << endl;
		return 1;
	}
	catch (const Exception& er) {
		// Catch-all for any other MySQL++ exceptions
		cout << "Content-type: text/plain" << endl << endl;
		cout << "GENERAL ERROR: " << er.what() << endl;
		return 1;
	}

	return 0;
}
<|endoftext|>


<commit_before>// #include <possumwood_sdk/node_implementation.h>

// #include <OpenEXR/ImathVec.h>
// #include <OpenEXR/ImathEuler.h>

// #include "maths/io/vec3.h"
// #include "datatypes/meshes.h"
// #include "cgal.h"

// namespace {

// using possumwood::Meshes;
// using possumwood::CGALPolyhedron;

// dependency_graph::InAttr<Meshes> a_inMesh;
// dependency_graph::InAttr<Imath::Vec3<float>> a_translation, a_rotation, a_scale;
// dependency_graph::OutAttr<Meshes> a_outMesh;

// dependency_graph::State compute(dependency_graph::Values& data) {
// 	const Imath::Vec3<float> tr = data.get(a_translation);
// 	const Imath::Vec3<float> rot = data.get(a_rotation);
// 	const Imath::Vec3<float> sc = data.get(a_scale);

// 	Imath::Matrix44<float> m1, m2, m3;
// 	m1 = Imath::Euler<float>(Imath::Vec3<float>(rot.x * M_PI / 180.0,
// 	                                            rot.y * M_PI / 180.0,
// 	                                            rot.z * M_PI / 180.0))
// 	         .toMatrix44();
// 	m2.setScale(sc);
// 	m3.setTranslation(tr);

// 	const Imath::Matrix44<float> matrix = m1 * m2 * m3;

// 	Meshes result;
// 	for(auto& inMesh : data.get(a_inMesh)) {
// 		std::unique_ptr<possumwood::CGALPolyhedron> newMesh(
// 		    new possumwood::CGALPolyhedron(inMesh.mesh()));

// 		for(auto it = newMesh->vertices_begin(); it != newMesh->vertices_end();
// 		    ++it) {
// 			possumwood::CGALPolyhedron::Point& pt = newMesh->point(*it);

// 			Imath::Vec3<float> p(pt[0], pt[1], pt[2]);
// 			p *= matrix;

// 			pt = possumwood::CGALKernel::Point_3(p.x, p.y, p.z);
// 		}

// 		result.addMesh(inMesh.name(), std::move(newMesh));
// 	}

// 	data.set(a_outMesh, result);

// 	return dependency_graph::State();
// }

// void init(possumwood::Metadata& meta) {
// 	meta.addAttribute(a_inMesh, "in_mesh");
// 	meta.addAttribute(a_translation, "translation",
// 	                  Imath::Vec3<float>(0, 0, 0));
// 	meta.addAttribute(a_rotation, "rotation", Imath::Vec3<float>(0, 0, 0));
// 	meta.addAttribute(a_scale, "scale", Imath::Vec3<float>(1, 1, 1));
// 	meta.addAttribute(a_outMesh, "out_mesh");

// 	meta.addInfluence(a_inMesh, a_outMesh);
// 	meta.addInfluence(a_translation, a_outMesh);
// 	meta.addInfluence(a_rotation, a_outMesh);
// 	meta.addInfluence(a_scale, a_outMesh);

// 	meta.setCompute(compute);
// }

// possumwood::NodeImplementation s_impl("cgal/transform", init);
// }
<commit_msg>Ported CGAL Transform node to use new CGAL mesh representation<commit_after>#include <possumwood_sdk/node_implementation.h>

#include <OpenEXR/ImathVec.h>
#include <OpenEXR/ImathEuler.h>

#include "maths/io/vec3.h"
#include "datatypes/meshes.h"
#include "cgal.h"

namespace {

using possumwood::Meshes;
using possumwood::CGALPolyhedron;

dependency_graph::InAttr<Meshes> a_inMesh;
dependency_graph::InAttr<Imath::Vec3<float>> a_translation, a_rotation, a_scale;
dependency_graph::OutAttr<Meshes> a_outMesh;

dependency_graph::State compute(dependency_graph::Values& data) {
	const Imath::Vec3<float> tr = data.get(a_translation);
	const Imath::Vec3<float> rot = data.get(a_rotation);
	const Imath::Vec3<float> sc = data.get(a_scale);

	Imath::Matrix44<float> m1, m2, m3;
	m1 =
	    Imath::Euler<float>(Imath::Vec3<float>(rot.x * M_PI / 180.0, rot.y * M_PI / 180.0,
	                                           rot.z * M_PI / 180.0))
	        .toMatrix44();
	m2.setScale(sc);
	m3.setTranslation(tr);

	const Imath::Matrix44<float> matrix = m1 * m2 * m3;

	Meshes result = data.get(a_inMesh);
	for(auto& mesh : result) {
		for(auto it = mesh.polyhedron().vertices_begin();
		    it != mesh.polyhedron().vertices_end(); ++it) {
			possumwood::CGALPolyhedron::Point& pt = it->point();;

			Imath::Vec3<float> p(pt[0], pt[1], pt[2]);
			p *= matrix;

			pt = possumwood::CGALKernel::Point_3(p.x, p.y, p.z);
		}
	}

	data.set(a_outMesh, result);

	return dependency_graph::State();
}

void init(possumwood::Metadata& meta) {
	meta.addAttribute(a_inMesh, "in_mesh");
	meta.addAttribute(a_translation, "translation", Imath::Vec3<float>(0, 0, 0));
	meta.addAttribute(a_rotation, "rotation", Imath::Vec3<float>(0, 0, 0));
	meta.addAttribute(a_scale, "scale", Imath::Vec3<float>(1, 1, 1));
	meta.addAttribute(a_outMesh, "out_mesh");

	meta.addInfluence(a_inMesh, a_outMesh);
	meta.addInfluence(a_translation, a_outMesh);
	meta.addInfluence(a_rotation, a_outMesh);
	meta.addInfluence(a_scale, a_outMesh);

	meta.setCompute(compute);
}

possumwood::NodeImplementation s_impl("cgal/transform", init);
}
<|endoftext|>