<commit_before>///////////////////////////////////////////////////////////////////////////////
// FILE:          SpectralInterface.cpp
// PROJECT:       Micro-Manager
// SUBSYSTEM:     DeviceAdapters
//-----------------------------------------------------------------------------
// DESCRIPTION:   Interface for the Spectral LMM5
//
// COPYRIGHT:     University of California, San Francisco, 2009
//
// LICENSE:       This file is distributed under the "Lesser GPL" (LGPL) license.
//                License text is included with the source distribution.
//
//                This file 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.
//
//                IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//                CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//                INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES.
// AUTHOR:        Nico Stuurman (nico@cmp.ucf.edu), 2/7/2008
//
#include "SpectralLMM5Interface.h"
#include "SpectralLMM5.h"

#ifdef WIN32
#include <winsock.h>
#else
#include <netinet/in.h>
#endif

SpectralLMM5Interface::SpectralLMM5Interface(std::string port, MM::PortType portType) :
   laserLinesDetected_ (false),
   nrLines_ (5),
   readWriteSame_(false)
{
   port_ = port;
   portType_ = portType;
   initialized_ = true;
}

SpectralLMM5Interface::~SpectralLMM5Interface(){};

/*
 * The Spectral LMM5 has a silly difference between USB and serial communication:
 * Commands can be sent straight to USB.  Commands to the serial port need to converted in some kind of weird ASCI:  The command "0x1A0xFF0x000x12<CR>" becomes "1AFF0012<CR>".  Presumably, the same weird conversion takes place on the way back.  We handle this translation in this function
 */
int SpectralLMM5Interface::ExecuteCommand(MM::Device& device, MM::Core& core, unsigned char* buf, unsigned long bufLen, unsigned char* answer, unsigned long answerLen, unsigned long& read)
{
   int ret;
   if (portType_ == MM::SerialPort)
   {
      std::string serialCommand;
      char tmp[3];
      tmp[2] = 0;
      for (unsigned long i=0; i<bufLen; i++) {
         sprintf(tmp, "%.2x", buf[i]);
         serialCommand += tmp;
      }
      ret = core.SetSerialCommand(&device, port_.c_str(), serialCommand.c_str(), "\r");
   } else  // check for USB port
   {
      unsigned char c[2];
      c[0]=0x01;
      c[1]=0x02;
      ret = core.WriteToSerial(&device, port_.c_str(), c, 2);
      //ret = core.WriteToSerial(&device, port_.c_str(), buf, bufLen);
   }

   if (ret != DEVICE_OK)
      return ret;

   if (portType_ == MM::SerialPort)
   {
      char strAnswer[128];
      read = 0;
      ret = core.GetSerialAnswer(&device, port_.c_str(), 128, strAnswer, "\r");
      if (ret != DEVICE_OK)
         return ret;
      std::ostringstream os;
      os << "LMM5 answered: " << strAnswer << " Port status: " << ret;
      core.LogMessage(&device, os.str().c_str(), true);
      // 'translate' back into numbers:
      std::string tmp = strAnswer;
      for (unsigned int i=0; i < tmp.length()/2; i++) {
         char * end;
         long j = strtol(tmp.substr(i*2,2).c_str(), &end, 16);
         answer[i] = (unsigned char) j;
         // printf("c:%x i:%u j:%ld\n", answer[i], i, j);
         read++;
      }
   } else // TODO: check that we have a USB port
   {
      // The USB port will attempt to read up to answerLen characters
      ret = core.ReadFromSerial(&device, port_.c_str(), answer, answerLen, read);
      if (ret != DEVICE_OK)
         return ret;
      std::ostringstream os;
      os << "LMM5 answered: ";
      for (unsigned int i=0; i < read; i++)
         os << std::hex << answer[i];
      os << std::endl;
      core.LogMessage(&device, os.str().c_str(), true);
   }
   return DEVICE_OK;
}

int SpectralLMM5Interface::DetectLaserLines(MM::Device& device, MM::Core& core) {
   if (laserLinesDetected_)
      return DEVICE_OK;
   const unsigned long bufLen = 1;
   unsigned char buf[bufLen];
   buf[0]=0x08;
   const unsigned long answerLen = 11;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   if (read < 8) {
      return ERR_UNEXPECTED_ANSWER;
   }

   uint16_t* lineP = (uint16_t*) (answer + 1);
   nrLines_ = (read-1)/2;
   printf("NrLines: %d\n", nrLines_);
   for (int i=0; i<nrLines_; i++)
   {
      laserLines_[i].lineNr = i;
      laserLines_[i].waveLength = ntohs(*(lineP+i)) / 10;
      if (*(lineP+i) == 0) {
         laserLines_[i].present = false;
      } else {
         laserLines_[i].present = true;
         std::ostringstream os;
         os << laserLines_[i].waveLength << "nm-" << i + 1;
         laserLines_[i].name = os.str();
      }
      // printf ("Line: %d %f %d %s\n", i, laserLines_[i].waveLength, laserLines_[i].present, laserLines_[i].name.c_str());
   }
   laserLinesDetected_ = true;
   return DEVICE_OK;
}

int SpectralLMM5Interface::SetTransmission(MM::Device& device, MM::Core& core, long laserLine, double transmission)
{
   const unsigned long bufLen = 4;
   unsigned char buf[bufLen];
   buf[0]=0x04;
   buf[1]=(unsigned char) laserLine;
   int16_t tr = (int16_t) (10*transmission);
   tr = htons(tr);
   memcpy(buf+2, &tr, 2);
   const unsigned long answerLen = 1;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x04)
      return ERR_UNEXPECTED_ANSWER;

   return DEVICE_OK;
}

int SpectralLMM5Interface::GetTransmission(MM::Device& device, MM::Core& core, long laserLine, double& transmission) {
   const unsigned long bufLen = 2;
   unsigned char buf[bufLen];
   buf[0]=0x05;
   buf[1]= (unsigned char) laserLine;
   const unsigned long answerLen = 3;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   if (read < 3) {
      return ERR_UNEXPECTED_ANSWER;
   }

   // See if the controller acknowledged our command
   if (answer[0] != 0x05) {
      return ERR_UNEXPECTED_ANSWER;
   }

   int16_t tr = 0;
   memcpy(&tr, answer + 1, 2);
   tr = ntohs(tr);
   transmission = tr/10;
   std::ostringstream os;
   os << "Transmission for line" << laserLine << " is: " << transmission;
   printf("%s tr: %d\n", os.str().c_str(), tr);

   return DEVICE_OK;
}

int SpectralLMM5Interface::SetShutterState(MM::Device& device, MM::Core& core, int state)
{
   const unsigned long bufLen = 2;
   unsigned char buf[bufLen];
   buf[0]=0x01;
   buf[1]=(unsigned char) state;
   const unsigned long answerLen = 1;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x01)
      return ERR_UNEXPECTED_ANSWER;

   return DEVICE_OK;
}

int SpectralLMM5Interface::GetShutterState(MM::Device& device, MM::Core& core, int& state)
{
   const unsigned long bufLen = 1;
   unsigned char buf[bufLen];
   buf[0]=0x02;
   const unsigned long answerLen = 4;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   if (read < 2) {
      return ERR_UNEXPECTED_ANSWER;
   }

   // See if the controller acknowledged our command
   if (answer[0] != 0x02)
      return ERR_UNEXPECTED_ANSWER;

   state = (int) answer[1];

   return DEVICE_OK;
}

int SpectralLMM5Interface::SetExposureConfig(MM::Device& device, MM::Core& core, std::string config) {
   unsigned char* buf;
   int length = (int) config.size()/2;
   unsigned long bufLen = length +1;
   unsigned long read = 0;
   buf = (unsigned char*) malloc(bufLen);
   buf[0]=0x21;
   for (int i=0; i<length; i++) {
      char * end;
      long j = strtol(config.substr(i*2,2).c_str(), &end, 16);
      buf[i+1] = (unsigned char) j;
   }

   const unsigned long answerLen = 1;
   unsigned char answer[answerLen];
   printf ("Set Exposure confign \n");
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x21)
      return ERR_UNEXPECTED_ANSWER;

   return DEVICE_OK;
}

int SpectralLMM5Interface::GetExposureConfig(MM::Device& device, MM::Core& core, std::string& config)
{
   const unsigned long bufLen = 1;
   unsigned char buf[bufLen];
   if (readWriteSame_)
      buf[0]=0x021;
   else
      buf[0]=0x027;
   const unsigned long answerLen = 70;
   unsigned char answer[answerLen];
   unsigned long read;
   printf ("Detecting Exposure Config: \n");
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x27)
      return ERR_UNEXPECTED_ANSWER;

   config = "";
   for (unsigned int i=1; i < read; i++)
      config += buf[i];

   return DEVICE_OK;
}

int SpectralLMM5Interface::SetTriggerOutConfig(MM::Device& device, MM::Core& core, unsigned char * config)
{
   const unsigned long bufLen = 5;
   unsigned char buf[bufLen];
   unsigned long read = 0;
   buf[0]=0x23;
   memcpy(buf + 1, config, 4);

   const unsigned long answerLen = 10;//1; Why does 1 cause a runtime exception? 'Stack around the variable "answer" was corrupted.'
   unsigned char answer[answerLen];
   printf ("Set Trigger Out \n");
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x23)
      return ERR_UNEXPECTED_ANSWER;

   return DEVICE_OK;
}

int SpectralLMM5Interface::GetTriggerOutConfig(MM::Device& device, MM::Core& core, unsigned char * config)
{
   const unsigned long bufLen = 1;
   unsigned char buf[bufLen];
   if (readWriteSame_)
      buf[0]=0x023;
   else
      buf[0]=0x026;
   const unsigned long answerLen = 10;//6;
   unsigned char answer[answerLen];
   unsigned long read;
   printf ("Detecting Trigger out Config: \n");
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x23)
      return ERR_UNEXPECTED_ANSWER;

   memcpy(config, answer + 1, 4);

   return DEVICE_OK;
}

<commit_msg>Made Spectral adapter work with HID ports<commit_after>///////////////////////////////////////////////////////////////////////////////
// FILE:          SpectralInterface.cpp
// PROJECT:       Micro-Manager
// SUBSYSTEM:     DeviceAdapters
//-----------------------------------------------------------------------------
// DESCRIPTION:   Interface for the Spectral LMM5
//
// COPYRIGHT:     University of California, San Francisco, 2009
//
// LICENSE:       This file is distributed under the "Lesser GPL" (LGPL) license.
//                License text is included with the source distribution.
//
//                This file 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.
//
//                IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//                CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//                INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES.
// AUTHOR:        Nico Stuurman (nico@cmp.ucf.edu), 2/7/2008
//
#include "SpectralLMM5Interface.h"
#include "SpectralLMM5.h"

#ifdef WIN32
#include <winsock.h>
#else
#include <netinet/in.h>
#endif

SpectralLMM5Interface::SpectralLMM5Interface(std::string port, MM::PortType portType) :
   laserLinesDetected_ (false),
   nrLines_ (5),
   readWriteSame_(false)
{
   port_ = port;
   portType_ = portType;
   initialized_ = true;
}

SpectralLMM5Interface::~SpectralLMM5Interface(){};

/*
 * The Spectral LMM5 has a silly difference between USB and serial communication:
 * Commands can be sent straight to USB.  Commands to the serial port need to converted in some kind of weird ASCI:  The command "0x1A0xFF0x000x12<CR>" becomes "1AFF0012<CR>".  Presumably, the same weird conversion takes place on the way back.  We handle this translation in this function
 */
int SpectralLMM5Interface::ExecuteCommand(MM::Device& device, MM::Core& core, unsigned char* buf, unsigned long bufLen, unsigned char* answer, unsigned long answerLen, unsigned long& read)
{
   int ret;
   if (portType_ == MM::SerialPort)
   {
      std::string serialCommand;
      char tmp[3];
      tmp[2] = 0;
      for (unsigned long i=0; i<bufLen; i++) {
         sprintf(tmp, "%.2x", buf[i]);
         serialCommand += tmp;
      }
      ret = core.SetSerialCommand(&device, port_.c_str(), serialCommand.c_str(), "\r");
   } else  // check for USB port
   {
      ret = core.WriteToSerial(&device, port_.c_str(), buf, bufLen);
   }

   if (ret != DEVICE_OK)
      return ret;

   if (portType_ == MM::SerialPort)
   {
      char strAnswer[128];
      read = 0;
      ret = core.GetSerialAnswer(&device, port_.c_str(), 128, strAnswer, "\r");
      if (ret != DEVICE_OK)
         return ret;

      std::ostringstream os;
      os << "LMM5 answered: " << strAnswer << " Port status: " << ret;
      core.LogMessage(&device, os.str().c_str(), true);

      // 'translate' back into numbers:
      std::string tmp = strAnswer;
      for (unsigned int i=0; i < tmp.length()/2; i++) {
         char * end;
         long j = strtol(tmp.substr(i*2,2).c_str(), &end, 16);
         answer[i] = (unsigned char) j;
         read++;
      }
   } else if (portType_ == MM::HIDPort)
   {
      // The USB port will attempt to read up to answerLen characters
      ret = core.ReadFromSerial(&device, port_.c_str(), answer, answerLen, read);
      if (ret != DEVICE_OK)
         return ret;

      /*
       // Uncomment for debugging (although port should give the same info)
      std::ostringstream os;
      os << "LMM5 answered: " << std::hex << std::setfill('0');
      for (unsigned int i=0; i < read; i++)
         os << std::setw(2) << (unsigned int) answer[i] << " ";
      core.LogMessage(&device, os.str().c_str(), true);
      */
   }
   return DEVICE_OK;
}

int SpectralLMM5Interface::DetectLaserLines(MM::Device& device, MM::Core& core) {
   if (laserLinesDetected_)
      return DEVICE_OK;
   const unsigned long bufLen = 1;
   unsigned char buf[bufLen];
   buf[0]=0x08;
   const unsigned long answerLen = 11;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   if (read < 8) {
      return ERR_UNEXPECTED_ANSWER;
   }

   uint16_t* lineP = (uint16_t*) (answer + 1);
   nrLines_ = (read-1)/2;
   printf("NrLines: %d\n", nrLines_);
   for (int i=0; i<nrLines_; i++)
   {
      laserLines_[i].lineNr = i;
      laserLines_[i].waveLength = ntohs(*(lineP+i)) / 10;
      if (*(lineP+i) == 0) {
         laserLines_[i].present = false;
      } else {
         laserLines_[i].present = true;
         std::ostringstream os;
         os << laserLines_[i].waveLength << "nm-" << i + 1;
         laserLines_[i].name = os.str();
      }
      // printf ("Line: %d %f %d %s\n", i, laserLines_[i].waveLength, laserLines_[i].present, laserLines_[i].name.c_str());
   }
   laserLinesDetected_ = true;
   return DEVICE_OK;
}

int SpectralLMM5Interface::SetTransmission(MM::Device& device, MM::Core& core, long laserLine, double transmission)
{
   const unsigned long bufLen = 4;
   unsigned char buf[bufLen];
   buf[0]=0x04;
   buf[1]=(unsigned char) laserLine;
   int16_t tr = (int16_t) (10*transmission);
   tr = htons(tr);
   memcpy(buf+2, &tr, 2);
   const unsigned long answerLen = 1;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x04)
      return ERR_UNEXPECTED_ANSWER;

   return DEVICE_OK;
}

int SpectralLMM5Interface::GetTransmission(MM::Device& device, MM::Core& core, long laserLine, double& transmission) {
   const unsigned long bufLen = 2;
   unsigned char buf[bufLen];
   buf[0]=0x05;
   buf[1]= (unsigned char) laserLine;
   const unsigned long answerLen = 3;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   if (read < 3) {
      return ERR_UNEXPECTED_ANSWER;
   }

   // See if the controller acknowledged our command
   if (answer[0] != 0x05) {
      return ERR_UNEXPECTED_ANSWER;
   }

   int16_t tr = 0;
   memcpy(&tr, answer + 1, 2);
   tr = ntohs(tr);
   transmission = tr/10;
   std::ostringstream os;
   os << "Transmission for line" << laserLine << " is: " << transmission;
   printf("%s tr: %d\n", os.str().c_str(), tr);

   return DEVICE_OK;
}

int SpectralLMM5Interface::SetShutterState(MM::Device& device, MM::Core& core, int state)
{
   const unsigned long bufLen = 2;
   unsigned char buf[bufLen];
   buf[0]=0x01;
   buf[1]=(unsigned char) state;
   const unsigned long answerLen = 1;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x01)
      return ERR_UNEXPECTED_ANSWER;

   return DEVICE_OK;
}

int SpectralLMM5Interface::GetShutterState(MM::Device& device, MM::Core& core, int& state)
{
   const unsigned long bufLen = 1;
   unsigned char buf[bufLen];
   buf[0]=0x02;
   const unsigned long answerLen = 4;
   unsigned char answer[answerLen];
   unsigned long read;
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   if (read < 2) {
      return ERR_UNEXPECTED_ANSWER;
   }

   // See if the controller acknowledged our command
   if (answer[0] != 0x02)
      return ERR_UNEXPECTED_ANSWER;

   state = (int) answer[1];

   return DEVICE_OK;
}

int SpectralLMM5Interface::SetExposureConfig(MM::Device& device, MM::Core& core, std::string config) {
   unsigned char* buf;
   int length = (int) config.size()/2;
   unsigned long bufLen = length +1;
   unsigned long read = 0;
   buf = (unsigned char*) malloc(bufLen);
   buf[0]=0x21;
   for (int i=0; i<length; i++) {
      char * end;
      long j = strtol(config.substr(i*2,2).c_str(), &end, 16);
      buf[i+1] = (unsigned char) j;
   }

   const unsigned long answerLen = 1;
   unsigned char answer[answerLen];
   printf ("Set Exposure confign \n");
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x21)
      return ERR_UNEXPECTED_ANSWER;

   return DEVICE_OK;
}

int SpectralLMM5Interface::GetExposureConfig(MM::Device& device, MM::Core& core, std::string& config)
{
   const unsigned long bufLen = 1;
   unsigned char buf[bufLen];
   if (readWriteSame_)
      buf[0]=0x021;
   else
      buf[0]=0x027;
   const unsigned long answerLen = 70;
   unsigned char answer[answerLen];
   unsigned long read;
   printf ("Detecting Exposure Config: \n");
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x27)
      return ERR_UNEXPECTED_ANSWER;

   config = "";
   for (unsigned int i=1; i < read; i++)
      config += buf[i];

   return DEVICE_OK;
}

int SpectralLMM5Interface::SetTriggerOutConfig(MM::Device& device, MM::Core& core, unsigned char * config)
{
   const unsigned long bufLen = 5;
   unsigned char buf[bufLen];
   unsigned long read = 0;
   buf[0]=0x23;
   memcpy(buf + 1, config, 4);

   const unsigned long answerLen = 10;//1; Why does 1 cause a runtime exception? 'Stack around the variable "answer" was corrupted.'
   unsigned char answer[answerLen];
   printf ("Set Trigger Out \n");
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x23)
      return ERR_UNEXPECTED_ANSWER;

   return DEVICE_OK;
}

int SpectralLMM5Interface::GetTriggerOutConfig(MM::Device& device, MM::Core& core, unsigned char * config)
{
   const unsigned long bufLen = 1;
   unsigned char buf[bufLen];
   if (readWriteSame_)
      buf[0]=0x023;
   else
      buf[0]=0x026;
   const unsigned long answerLen = 10;//6;
   unsigned char answer[answerLen];
   unsigned long read;
   printf ("Detecting Trigger out Config: \n");
   int ret = ExecuteCommand(device, core, buf, bufLen, answer, answerLen, read);
   if (ret != DEVICE_OK)
      return ret;

   // See if the controller acknowledged our command
   if (answer[0] != 0x23)
      return ERR_UNEXPECTED_ANSWER;

   memcpy(config, answer + 1, 4);

   return DEVICE_OK;
}

<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. 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 "modules/planning/planning.h"

#include <algorithm>
#include <vector>

#include "google/protobuf/repeated_field.h"

#include "modules/common/adapters/adapter_manager.h"
#include "modules/common/time/time.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/map/hdmap/hdmap_util.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/common/trajectory/trajectory_stitcher.h"
#include "modules/planning/planner/em/em_planner.h"
#include "modules/planning/planner/rtk/rtk_replay_planner.h"
#include "modules/planning/reference_line/reference_line_provider.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;
using apollo::common::TrajectoryPoint;
using apollo::common::VehicleStateProvider;
using apollo::common::VehicleState;
using apollo::common::adapter::AdapterManager;
using apollo::common::time::Clock;

std::string Planning::Name() const { return "planning"; }

void Planning::RegisterPlanners() {
  planner_factory_.Register(
      PlanningConfig::RTK, []() -> Planner* { return new RTKReplayPlanner(); });
  planner_factory_.Register(PlanningConfig::EM,
                            []() -> Planner* { return new EMPlanner(); });
}

Status Planning::InitFrame(const uint32_t sequence_num,
                           const TrajectoryPoint& planning_start_point,
                           const VehicleState& vehicle_state) {
  frame_.reset(new Frame(sequence_num, planning_start_point, vehicle_state));
  if (FLAGS_enable_prediction && !AdapterManager::GetPrediction()->Empty()) {
    const auto& prediction =
        AdapterManager::GetPrediction()->GetLatestObserved();
    frame_->SetPrediction(prediction);
    ADEBUG << "Get prediction: " << prediction.DebugString();
  }
  auto status = frame_->Init();
  if (!status.ok()) {
    AERROR << "failed to init frame";
    return Status(ErrorCode::PLANNING_ERROR, "init frame failed");
  }
  return Status::OK();
}

Status Planning::Init() {
  hdmap_ = apollo::hdmap::HDMapUtil::BaseMapPtr();
  CHECK(hdmap_) << "Failed to load map file:" << apollo::hdmap::BaseMapFile();

  CHECK(apollo::common::util::GetProtoFromFile(FLAGS_planning_config_file,
                                               &config_))
      << "failed to load planning config file " << FLAGS_planning_config_file;
  if (!AdapterManager::Initialized()) {
    AdapterManager::Init(FLAGS_planning_adapter_config_filename);
  }
  if (AdapterManager::GetLocalization() == nullptr) {
    std::string error_msg("Localization is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (AdapterManager::GetChassis() == nullptr) {
    std::string error_msg("Chassis is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (AdapterManager::GetRoutingResponse() == nullptr) {
    std::string error_msg("RoutingResponse is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (AdapterManager::GetRoutingRequest() == nullptr) {
    std::string error_msg("RoutingRequest is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (FLAGS_enable_prediction && AdapterManager::GetPrediction() == nullptr) {
    std::string error_msg("Prediction is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (FLAGS_enable_traffic_light &&
      AdapterManager::GetTrafficLightDetection() == nullptr) {
    std::string error_msg("Traffic Light Detection is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  ReferenceLineProvider::instance()->Init(
      hdmap_, config_.qp_spline_reference_line_smoother_config());

  RegisterPlanners();
  planner_ = planner_factory_.CreateObject(config_.planner_type());
  if (!planner_) {
    return Status(
        ErrorCode::PLANNING_ERROR,
        "planning is not initialized with config : " + config_.DebugString());
  }

  return planner_->Init(config_);
}

bool Planning::IsVehicleStateValid(const VehicleState& vehicle_state) {
  if (std::isnan(vehicle_state.x()) || std::isnan(vehicle_state.y()) ||
      std::isnan(vehicle_state.z()) || std::isnan(vehicle_state.heading()) ||
      std::isnan(vehicle_state.kappa()) ||
      std::isnan(vehicle_state.linear_velocity()) ||
      std::isnan(vehicle_state.linear_acceleration())) {
    return false;
  }
  return true;
}

Status Planning::Start() {
  timer_ = AdapterManager::CreateTimer(
      ros::Duration(1.0 / FLAGS_planning_loop_rate), &Planning::OnTimer, this);
  ReferenceLineProvider::instance()->Start();
  AINFO << "Planning started";
  return Status::OK();
}

void Planning::OnTimer(const ros::TimerEvent&) { RunOnce(); }

void Planning::PublishPlanningPb(ADCTrajectory* trajectory_pb,
                                 double timestamp) {
  trajectory_pb->mutable_header()->set_timestamp_sec(timestamp);
  // TODO(all): integrate reverse gear
  trajectory_pb->set_gear(canbus::Chassis::GEAR_DRIVE);
  if (AdapterManager::GetRoutingResponse() &&
      !AdapterManager::GetRoutingResponse()->Empty()) {
    trajectory_pb->mutable_routing_header()->CopyFrom(
        AdapterManager::GetRoutingResponse()->GetLatestObserved().header());
  }

  // NOTICE:
  // Since we are using the time at each cycle beginning as timestamp, the
  // relative time of each trajectory point should be modified so that we can
  // use the current timestamp in header.

  // auto* trajectory_points = trajectory_pb.mutable_trajectory_point();
  if (!FLAGS_planning_test_mode) {
    const double dt = timestamp - Clock::NowInSecond();
    for (auto& p : *trajectory_pb->mutable_trajectory_point()) {
      p.set_relative_time(p.relative_time() + dt);
    }
  }
  Publish(trajectory_pb);
}

void Planning::RunOnce() {
  const double start_timestamp = Clock::NowInSecond();

  // snapshot all coming data
  AdapterManager::Observe();

  ADCTrajectory not_ready_pb;
  auto* not_ready = not_ready_pb.mutable_decision()
                        ->mutable_main_decision()
                        ->mutable_not_ready();
  if (AdapterManager::GetLocalization()->Empty()) {
    not_ready->set_reason("localization not ready");
  } else if (AdapterManager::GetChassis()->Empty()) {
    not_ready->set_reason("chassis not ready");
  } else if (AdapterManager::GetRoutingResponse()->Empty()) {
    not_ready->set_reason("routing not ready");
  }
  if (not_ready->has_reason()) {
    AERROR << not_ready->reason() << "; skip the planning cycle.";
    PublishPlanningPb(&not_ready_pb, start_timestamp);
    return;
  }

  // localization
  const auto& localization =
      AdapterManager::GetLocalization()->GetLatestObserved();
  ADEBUG << "Get localization:" << localization.DebugString();

  // chassis
  const auto& chassis = AdapterManager::GetChassis()->GetLatestObserved();
  ADEBUG << "Get chassis:" << chassis.DebugString();

  Status status =
      VehicleStateProvider::instance()->Update(localization, chassis);
  VehicleState vehicle_state =
      VehicleStateProvider::instance()->vehicle_state();

  // estimate (x, y) at current timestamp
  if (FLAGS_estimate_current_vehicle_state) {
    auto future_xy = VehicleStateProvider::instance()->EstimateFuturePosition(
        start_timestamp - vehicle_state.timestamp());
    vehicle_state.set_x(future_xy.x());
    vehicle_state.set_y(future_xy.y());
    vehicle_state.set_timestamp(start_timestamp);
  }

  if (!status.ok() || !IsVehicleStateValid(vehicle_state)) {
    AERROR << "Update VehicleStateProvider failed.";
    not_ready->set_reason("Update VehicleStateProvider failed.");
    status.Save(not_ready_pb.mutable_header()->mutable_status());
    PublishPlanningPb(&not_ready_pb, start_timestamp);
    return;
  }

  // Update reference line provider
  if (!ReferenceLineProvider::instance()->UpdateRoutingResponse(
          AdapterManager::GetRoutingResponse()->GetLatestObserved())) {
    AERROR << "Failed to update routing in reference line provider";
    return;
  }
  ReferenceLineProvider::instance()->UpdateVehicleState(vehicle_state);

  if (FLAGS_enable_prediction && AdapterManager::GetPrediction()->Empty()) {
    not_ready->set_reason("prediction not ready");
    AERROR << not_ready->reason() << "; skip the planning cycle.";
    PublishPlanningPb(&not_ready_pb, start_timestamp);
    return;
  }

  const double planning_cycle_time = 1.0 / FLAGS_planning_loop_rate;
  bool is_replan = false;
  const auto stitching_trajectory =
      TrajectoryStitcher::ComputeStitchingTrajectory(
          vehicle_state, start_timestamp, planning_cycle_time,
          last_publishable_trajectory_.get(), &is_replan);

  const uint32_t frame_num = AdapterManager::GetPlanning()->GetSeqNum() + 1;
  status = InitFrame(frame_num, stitching_trajectory.back(), vehicle_state);
  ADCTrajectory trajectory_pb;
  if (FLAGS_enable_record_debug) {
    frame_->RecordInputDebug(trajectory_pb.mutable_debug());
  }
  trajectory_pb.mutable_latency_stats()->set_init_frame_time_ms(
      Clock::NowInSecond() - start_timestamp);
  if (!status.ok()) {
    AERROR << "Init frame failed";
    if (FLAGS_publish_estop) {
      ADCTrajectory estop;
      estop.mutable_estop();
      status.Save(estop.mutable_header()->mutable_status());
      PublishPlanningPb(&estop, start_timestamp);
    }
    if (frame_) {
      auto seq_num = frame_->SequenceNum();
      FrameHistory::instance()->Add(seq_num, std::move(frame_));
    }
    return;
  }

  status = Plan(start_timestamp, stitching_trajectory, &trajectory_pb);

  const auto time_diff_ms = (Clock::NowInSecond() - start_timestamp) * 1000;
  ADEBUG << "total planning time spend: " << time_diff_ms << " ms.";

  trajectory_pb.mutable_latency_stats()->set_total_time_ms(time_diff_ms);
  ADEBUG << "Planning latency: " << trajectory_pb.latency_stats().DebugString();

  if (!status.ok()) {
    status.Save(trajectory_pb.mutable_header()->mutable_status());
    AERROR << "Planning failed:" << status.ToString();
    if (FLAGS_publish_estop) {
      AERROR << "Planning failed and set estop";
      trajectory_pb.mutable_estop();
    }
  }

  trajectory_pb.set_is_replan(is_replan);
  PublishPlanningPb(&trajectory_pb, start_timestamp);
  ADEBUG << "Planning pb:" << trajectory_pb.header().DebugString();

  if (frame_) {
    auto seq_num = frame_->SequenceNum();
    FrameHistory::instance()->Add(seq_num, std::move(frame_));
  }
}

void Planning::Stop() {
  AERROR << "Planning Stop is called";
  ReferenceLineProvider::instance()->Stop();
  last_publishable_trajectory_.reset(nullptr);
  frame_.reset(nullptr);
  planner_.reset(nullptr);
}

void Planning::SetLastPublishableTrajectory(
    const ADCTrajectory& adc_trajectory) {
  last_publishable_trajectory_.reset(new PublishableTrajectory(adc_trajectory));
}

Status Planning::Plan(const double current_time_stamp,
                      const std::vector<TrajectoryPoint>& stitching_trajectory,
                      ADCTrajectory* trajectory_pb) {
  auto* ptr_debug = trajectory_pb->mutable_debug();
  if (FLAGS_enable_record_debug) {
    ptr_debug->mutable_planning_data()->mutable_init_point()->CopyFrom(
        stitching_trajectory.back());
  }
  auto status = Status::OK();
  for (auto& reference_line_info : frame_->reference_line_info()) {
    status = planner_->Plan(stitching_trajectory.back(), frame_.get(),
                            &reference_line_info);
    if (status == Status::OK()) {
      if (FLAGS_prioritize_change_lane && reference_line_info.IsDrivable() &&
          reference_line_info.IsChangeLanePath()) {
        ADEBUG << "Found change lane line, skip other reference line";
        break;
      }
    } else {
      AERROR << "planner failed to make a driving plan for: "
             << reference_line_info.Lanes().Id();
    }
  }
  const auto* best_reference_line = frame_->FindDriveReferenceLineInfo();
  if (!best_reference_line) {
    std::string msg(
        "planner failed to make a driving plan because NO valid reference line "
        "info.");
    AERROR << msg;
    if (last_publishable_trajectory_) {
      last_publishable_trajectory_->Clear();
    }
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
  ptr_debug->MergeFrom(best_reference_line->debug());
  trajectory_pb->mutable_latency_stats()->MergeFrom(
      best_reference_line->latency_stats());

  best_reference_line->ExportDecision(trajectory_pb->mutable_decision());

  // Add debug information.
  if (FLAGS_enable_record_debug) {
    auto* reference_line = ptr_debug->mutable_planning_data()->add_path();
    reference_line->set_name("planning_reference_line");
    const auto& reference_points =
        best_reference_line->reference_line().reference_points();
    for (const auto& reference_point : reference_points) {
      auto* path_point = reference_line->add_path_point();
      path_point->set_x(reference_point.x());
      path_point->set_y(reference_point.y());
      path_point->set_theta(reference_point.heading());
      path_point->set_kappa(reference_point.kappa());
      path_point->set_dkappa(reference_point.dkappa());
    }
  }

  last_publishable_trajectory_.reset(new PublishableTrajectory(
      current_time_stamp, best_reference_line->trajectory()));

  ADEBUG << "current_time_stamp: " << std::to_string(current_time_stamp);

  last_publishable_trajectory_->PrependTrajectoryPoints(
      stitching_trajectory.begin(), stitching_trajectory.end() - 1);

  for (size_t i = 0; i < last_publishable_trajectory_->NumOfPoints(); ++i) {
    if (last_publishable_trajectory_->TrajectoryPointAt(i).relative_time() >
        FLAGS_trajectory_time_high_density_period) {
      break;
    }
    ADEBUG << last_publishable_trajectory_->TrajectoryPointAt(i)
                  .ShortDebugString();
  }

  last_publishable_trajectory_->PopulateTrajectoryProtobuf(trajectory_pb);

  return status;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>Planning: only estimate current vehicle state if the time difference is small. (#1410)<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. 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 "modules/planning/planning.h"

#include <algorithm>
#include <vector>

#include "google/protobuf/repeated_field.h"

#include "modules/common/adapters/adapter_manager.h"
#include "modules/common/time/time.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/map/hdmap/hdmap_util.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/common/trajectory/trajectory_stitcher.h"
#include "modules/planning/planner/em/em_planner.h"
#include "modules/planning/planner/rtk/rtk_replay_planner.h"
#include "modules/planning/reference_line/reference_line_provider.h"

namespace apollo {
namespace planning {

using apollo::common::ErrorCode;
using apollo::common::Status;
using apollo::common::TrajectoryPoint;
using apollo::common::VehicleStateProvider;
using apollo::common::VehicleState;
using apollo::common::adapter::AdapterManager;
using apollo::common::time::Clock;

std::string Planning::Name() const { return "planning"; }

void Planning::RegisterPlanners() {
  planner_factory_.Register(
      PlanningConfig::RTK, []() -> Planner* { return new RTKReplayPlanner(); });
  planner_factory_.Register(PlanningConfig::EM,
                            []() -> Planner* { return new EMPlanner(); });
}

Status Planning::InitFrame(const uint32_t sequence_num,
                           const TrajectoryPoint& planning_start_point,
                           const VehicleState& vehicle_state) {
  frame_.reset(new Frame(sequence_num, planning_start_point, vehicle_state));
  if (FLAGS_enable_prediction && !AdapterManager::GetPrediction()->Empty()) {
    const auto& prediction =
        AdapterManager::GetPrediction()->GetLatestObserved();
    frame_->SetPrediction(prediction);
    ADEBUG << "Get prediction: " << prediction.DebugString();
  }
  auto status = frame_->Init();
  if (!status.ok()) {
    AERROR << "failed to init frame";
    return Status(ErrorCode::PLANNING_ERROR, "init frame failed");
  }
  return Status::OK();
}

Status Planning::Init() {
  hdmap_ = apollo::hdmap::HDMapUtil::BaseMapPtr();
  CHECK(hdmap_) << "Failed to load map file:" << apollo::hdmap::BaseMapFile();

  CHECK(apollo::common::util::GetProtoFromFile(FLAGS_planning_config_file,
                                               &config_))
      << "failed to load planning config file " << FLAGS_planning_config_file;
  if (!AdapterManager::Initialized()) {
    AdapterManager::Init(FLAGS_planning_adapter_config_filename);
  }
  if (AdapterManager::GetLocalization() == nullptr) {
    std::string error_msg("Localization is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (AdapterManager::GetChassis() == nullptr) {
    std::string error_msg("Chassis is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (AdapterManager::GetRoutingResponse() == nullptr) {
    std::string error_msg("RoutingResponse is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (AdapterManager::GetRoutingRequest() == nullptr) {
    std::string error_msg("RoutingRequest is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (FLAGS_enable_prediction && AdapterManager::GetPrediction() == nullptr) {
    std::string error_msg("Prediction is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  if (FLAGS_enable_traffic_light &&
      AdapterManager::GetTrafficLightDetection() == nullptr) {
    std::string error_msg("Traffic Light Detection is not registered");
    AERROR << error_msg;
    return Status(ErrorCode::PLANNING_ERROR, error_msg);
  }
  ReferenceLineProvider::instance()->Init(
      hdmap_, config_.qp_spline_reference_line_smoother_config());

  RegisterPlanners();
  planner_ = planner_factory_.CreateObject(config_.planner_type());
  if (!planner_) {
    return Status(
        ErrorCode::PLANNING_ERROR,
        "planning is not initialized with config : " + config_.DebugString());
  }

  return planner_->Init(config_);
}

bool Planning::IsVehicleStateValid(const VehicleState& vehicle_state) {
  if (std::isnan(vehicle_state.x()) || std::isnan(vehicle_state.y()) ||
      std::isnan(vehicle_state.z()) || std::isnan(vehicle_state.heading()) ||
      std::isnan(vehicle_state.kappa()) ||
      std::isnan(vehicle_state.linear_velocity()) ||
      std::isnan(vehicle_state.linear_acceleration())) {
    return false;
  }
  return true;
}

Status Planning::Start() {
  timer_ = AdapterManager::CreateTimer(
      ros::Duration(1.0 / FLAGS_planning_loop_rate), &Planning::OnTimer, this);
  ReferenceLineProvider::instance()->Start();
  AINFO << "Planning started";
  return Status::OK();
}

void Planning::OnTimer(const ros::TimerEvent&) { RunOnce(); }

void Planning::PublishPlanningPb(ADCTrajectory* trajectory_pb,
                                 double timestamp) {
  trajectory_pb->mutable_header()->set_timestamp_sec(timestamp);
  // TODO(all): integrate reverse gear
  trajectory_pb->set_gear(canbus::Chassis::GEAR_DRIVE);
  if (AdapterManager::GetRoutingResponse() &&
      !AdapterManager::GetRoutingResponse()->Empty()) {
    trajectory_pb->mutable_routing_header()->CopyFrom(
        AdapterManager::GetRoutingResponse()->GetLatestObserved().header());
  }

  // NOTICE:
  // Since we are using the time at each cycle beginning as timestamp, the
  // relative time of each trajectory point should be modified so that we can
  // use the current timestamp in header.

  // auto* trajectory_points = trajectory_pb.mutable_trajectory_point();
  if (!FLAGS_planning_test_mode) {
    const double dt = timestamp - Clock::NowInSecond();
    for (auto& p : *trajectory_pb->mutable_trajectory_point()) {
      p.set_relative_time(p.relative_time() + dt);
    }
  }
  Publish(trajectory_pb);
}

void Planning::RunOnce() {
  const double start_timestamp = Clock::NowInSecond();

  // snapshot all coming data
  AdapterManager::Observe();

  ADCTrajectory not_ready_pb;
  auto* not_ready = not_ready_pb.mutable_decision()
                        ->mutable_main_decision()
                        ->mutable_not_ready();
  if (AdapterManager::GetLocalization()->Empty()) {
    not_ready->set_reason("localization not ready");
  } else if (AdapterManager::GetChassis()->Empty()) {
    not_ready->set_reason("chassis not ready");
  } else if (AdapterManager::GetRoutingResponse()->Empty()) {
    not_ready->set_reason("routing not ready");
  }
  if (not_ready->has_reason()) {
    AERROR << not_ready->reason() << "; skip the planning cycle.";
    PublishPlanningPb(&not_ready_pb, start_timestamp);
    return;
  }

  // localization
  const auto& localization =
      AdapterManager::GetLocalization()->GetLatestObserved();
  ADEBUG << "Get localization:" << localization.DebugString();

  // chassis
  const auto& chassis = AdapterManager::GetChassis()->GetLatestObserved();
  ADEBUG << "Get chassis:" << chassis.DebugString();

  Status status =
      VehicleStateProvider::instance()->Update(localization, chassis);
  VehicleState vehicle_state =
      VehicleStateProvider::instance()->vehicle_state();

  // estimate (x, y) at current timestamp
  // This estimate is only valid if the current time and vehicle state timestamp
  // differs only a small amount (20ms). When the different is too large, the
  // estimation is invalid.
  DCHECK_GT(start_timestamp, vehicle_state.timestamp());
  if (FLAGS_estimate_current_vehicle_state &&
      start_timestamp - vehicle_state.timestamp() < 0.020) {
    auto future_xy = VehicleStateProvider::instance()->EstimateFuturePosition(
        start_timestamp - vehicle_state.timestamp());
    vehicle_state.set_x(future_xy.x());
    vehicle_state.set_y(future_xy.y());
    vehicle_state.set_timestamp(start_timestamp);
  }

  if (!status.ok() || !IsVehicleStateValid(vehicle_state)) {
    AERROR << "Update VehicleStateProvider failed.";
    not_ready->set_reason("Update VehicleStateProvider failed.");
    status.Save(not_ready_pb.mutable_header()->mutable_status());
    PublishPlanningPb(&not_ready_pb, start_timestamp);
    return;
  }

  // Update reference line provider
  if (!ReferenceLineProvider::instance()->UpdateRoutingResponse(
          AdapterManager::GetRoutingResponse()->GetLatestObserved())) {
    AERROR << "Failed to update routing in reference line provider";
    return;
  }
  ReferenceLineProvider::instance()->UpdateVehicleState(vehicle_state);

  if (FLAGS_enable_prediction && AdapterManager::GetPrediction()->Empty()) {
    not_ready->set_reason("prediction not ready");
    AERROR << not_ready->reason() << "; skip the planning cycle.";
    PublishPlanningPb(&not_ready_pb, start_timestamp);
    return;
  }

  const double planning_cycle_time = 1.0 / FLAGS_planning_loop_rate;
  bool is_replan = false;
  const auto stitching_trajectory =
      TrajectoryStitcher::ComputeStitchingTrajectory(
          vehicle_state, start_timestamp, planning_cycle_time,
          last_publishable_trajectory_.get(), &is_replan);

  const uint32_t frame_num = AdapterManager::GetPlanning()->GetSeqNum() + 1;
  status = InitFrame(frame_num, stitching_trajectory.back(), vehicle_state);
  ADCTrajectory trajectory_pb;
  if (FLAGS_enable_record_debug) {
    frame_->RecordInputDebug(trajectory_pb.mutable_debug());
  }
  trajectory_pb.mutable_latency_stats()->set_init_frame_time_ms(
      Clock::NowInSecond() - start_timestamp);
  if (!status.ok()) {
    AERROR << "Init frame failed";
    if (FLAGS_publish_estop) {
      ADCTrajectory estop;
      estop.mutable_estop();
      status.Save(estop.mutable_header()->mutable_status());
      PublishPlanningPb(&estop, start_timestamp);
    }
    if (frame_) {
      auto seq_num = frame_->SequenceNum();
      FrameHistory::instance()->Add(seq_num, std::move(frame_));
    }
    return;
  }

  status = Plan(start_timestamp, stitching_trajectory, &trajectory_pb);

  const auto time_diff_ms = (Clock::NowInSecond() - start_timestamp) * 1000;
  ADEBUG << "total planning time spend: " << time_diff_ms << " ms.";

  trajectory_pb.mutable_latency_stats()->set_total_time_ms(time_diff_ms);
  ADEBUG << "Planning latency: " << trajectory_pb.latency_stats().DebugString();

  if (!status.ok()) {
    status.Save(trajectory_pb.mutable_header()->mutable_status());
    AERROR << "Planning failed:" << status.ToString();
    if (FLAGS_publish_estop) {
      AERROR << "Planning failed and set estop";
      trajectory_pb.mutable_estop();
    }
  }

  trajectory_pb.set_is_replan(is_replan);
  PublishPlanningPb(&trajectory_pb, start_timestamp);
  ADEBUG << "Planning pb:" << trajectory_pb.header().DebugString();

  if (frame_) {
    auto seq_num = frame_->SequenceNum();
    FrameHistory::instance()->Add(seq_num, std::move(frame_));
  }
}

void Planning::Stop() {
  AERROR << "Planning Stop is called";
  ReferenceLineProvider::instance()->Stop();
  last_publishable_trajectory_.reset(nullptr);
  frame_.reset(nullptr);
  planner_.reset(nullptr);
}

void Planning::SetLastPublishableTrajectory(
    const ADCTrajectory& adc_trajectory) {
  last_publishable_trajectory_.reset(new PublishableTrajectory(adc_trajectory));
}

Status Planning::Plan(const double current_time_stamp,
                      const std::vector<TrajectoryPoint>& stitching_trajectory,
                      ADCTrajectory* trajectory_pb) {
  auto* ptr_debug = trajectory_pb->mutable_debug();
  if (FLAGS_enable_record_debug) {
    ptr_debug->mutable_planning_data()->mutable_init_point()->CopyFrom(
        stitching_trajectory.back());
  }
  auto status = Status::OK();
  for (auto& reference_line_info : frame_->reference_line_info()) {
    status = planner_->Plan(stitching_trajectory.back(), frame_.get(),
                            &reference_line_info);
    if (status == Status::OK()) {
      if (FLAGS_prioritize_change_lane && reference_line_info.IsDrivable() &&
          reference_line_info.IsChangeLanePath()) {
        ADEBUG << "Found change lane line, skip other reference line";
        break;
      }
    } else {
      AERROR << "planner failed to make a driving plan for: "
             << reference_line_info.Lanes().Id();
    }
  }
  const auto* best_reference_line = frame_->FindDriveReferenceLineInfo();
  if (!best_reference_line) {
    std::string msg(
        "planner failed to make a driving plan because NO valid reference line "
        "info.");
    AERROR << msg;
    if (last_publishable_trajectory_) {
      last_publishable_trajectory_->Clear();
    }
    return Status(ErrorCode::PLANNING_ERROR, msg);
  }
  ptr_debug->MergeFrom(best_reference_line->debug());
  trajectory_pb->mutable_latency_stats()->MergeFrom(
      best_reference_line->latency_stats());

  best_reference_line->ExportDecision(trajectory_pb->mutable_decision());

  // Add debug information.
  if (FLAGS_enable_record_debug) {
    auto* reference_line = ptr_debug->mutable_planning_data()->add_path();
    reference_line->set_name("planning_reference_line");
    const auto& reference_points =
        best_reference_line->reference_line().reference_points();
    for (const auto& reference_point : reference_points) {
      auto* path_point = reference_line->add_path_point();
      path_point->set_x(reference_point.x());
      path_point->set_y(reference_point.y());
      path_point->set_theta(reference_point.heading());
      path_point->set_kappa(reference_point.kappa());
      path_point->set_dkappa(reference_point.dkappa());
    }
  }

  last_publishable_trajectory_.reset(new PublishableTrajectory(
      current_time_stamp, best_reference_line->trajectory()));

  ADEBUG << "current_time_stamp: " << std::to_string(current_time_stamp);

  last_publishable_trajectory_->PrependTrajectoryPoints(
      stitching_trajectory.begin(), stitching_trajectory.end() - 1);

  for (size_t i = 0; i < last_publishable_trajectory_->NumOfPoints(); ++i) {
    if (last_publishable_trajectory_->TrajectoryPointAt(i).relative_time() >
        FLAGS_trajectory_time_high_density_period) {
      break;
    }
    ADEBUG << last_publishable_trajectory_->TrajectoryPointAt(i)
                  .ShortDebugString();
  }

  last_publishable_trajectory_->PopulateTrajectoryProtobuf(trajectory_pb);

  return status;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>// Copyright 2015 Vladimir Ivan

/*
 - Designer will publish:
 http://docs.ros.org/indigo/api/trajectory_msgs/html/msg/JointTrajectory.html
 - Designer will receive: (with root link as 0,0,0)
 http://docs.ros.org/indigo/api/sensor_msgs/html/msg/JointState.html
 */
#include <cstdlib>
#include <string>
#include <ros/ros.h>
#include <lcm/lcm-cpp.hpp>

#include "lcmtypes/drc/robot_plan_t.hpp"
#include "lcmtypes/drc/plan_control_t.hpp"
#include "lcmtypes/drc/affordance_collection_t.hpp"
#include "lcmtypes/drc/robot_state_t.hpp"
#include "lcmtypes/drc/exotica_planner_request_t.hpp"
#include "lcmtypes/drc/map_octree_t.hpp"
#include <trajectory_msgs/JointTrajectory.h>
#include <ipab_msgs/PlannerRequest.h>
#include <octomap_msgs/Octomap.h>
#include <std_srvs/Empty.h>
#include <std_msgs/String.h>

class LCM2ROS
{
public:
  LCM2ROS(boost::shared_ptr<lcm::LCM> &lcm_in, ros::NodeHandle &nh_in);
  ~LCM2ROS()
  {
  }

private:
  boost::shared_ptr<lcm::LCM> lcm_;
  ros::NodeHandle nh_;

  ros::Publisher planner_request_pub_;
  ros::Publisher ik_request_pub_;
  ros::Publisher octomap_pub_;

  void plannerRequestHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                             const drc::exotica_planner_request_t* msg);
  void ikRequestHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                        const drc::exotica_planner_request_t* msg);
  void octreeHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                        const drc::map_octree_t* msg);
};

LCM2ROS::LCM2ROS(boost::shared_ptr<lcm::LCM> &lcm_in, ros::NodeHandle &nh_in) : lcm_(lcm_in), nh_(nh_in)
{
  lcm_->subscribe("PLANNER_REQUEST", &LCM2ROS::plannerRequestHandler, this);
  planner_request_pub_ = nh_.advertise<ipab_msgs::PlannerRequest>("/exotica/planner_request", 10);

  lcm_->subscribe("IK_REQUEST", &LCM2ROS::ikRequestHandler, this);
  ik_request_pub_ = nh_.advertise<ipab_msgs::PlannerRequest>("/exotica/ik_request", 10);

  lcm_->subscribe("MAP_OCTREE", &LCM2ROS::octreeHandler, this);
  octomap_pub_ = nh_.advertise<octomap_msgs::Octomap>("/octomap_binary", 1);
}

void translatePlannerRequest(const drc::exotica_planner_request_t* msg, ipab_msgs::PlannerRequest& m)
{
  m.header.stamp = ros::Time().fromSec(msg->utime * 1E-6);
  m.poses = msg->poses;
  m.constraints = msg->constraints;
  m.affordances = msg->affordances;
  m.seed_pose = msg->seed_pose;
  m.nominal_pose = msg->nominal_pose;
  m.end_pose = msg->end_pose;
  m.joint_names = msg->joint_names;
  m.options = msg->options;
}

void LCM2ROS::plannerRequestHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                                    const drc::exotica_planner_request_t* msg)
{
  ROS_ERROR("LCM2ROS got PLANNER_REQUEST");
  ipab_msgs::PlannerRequest m;
  translatePlannerRequest(msg, m);
  planner_request_pub_.publish(m);
}

void LCM2ROS::ikRequestHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                               const drc::exotica_planner_request_t* msg)
{
  ROS_ERROR("LCM2ROS got IK_REQUEST");
  ipab_msgs::PlannerRequest m;
  translatePlannerRequest(msg, m);
  ik_request_pub_.publish(m);
}

void LCM2ROS::octreeHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                               const drc::map_octree_t* msg)
{
  octomap_msgs::Octomap m;
  m.header.frame_id = "/world_frame";
  m.header.stamp = ros::Time().fromSec(msg->utime * 1E-6);

  // hard coded because the incoming message has no resolution
  // A better solution might be to also check the view_id if there are
  // multiple octrees being published
  m.id = "OcTree";
  m.resolution = 0.01;
  m.binary = true;
  m.data.resize(msg->num_bytes);
  memcpy(&m.data[0], msg->data.data(), msg->num_bytes);

  octomap_pub_.publish(m);
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "lcm2ros", ros::init_options::NoSigintHandler);
  boost::shared_ptr<lcm::LCM> lcm(new lcm::LCM);
  if (!lcm->good())
  {
    std::cerr << "ERROR: lcm is not good()" << std::endl;
  }
  ros::NodeHandle nh;

  LCM2ROS handlerObject(lcm, nh);
  ROS_INFO_STREAM("lcm2ros translator ready");
  ROS_ERROR_STREAM("LCM2ROS Translator Ready");

  while (0 == lcm->handle())
  {
  }

  return 0;
}
<commit_msg>debug output<commit_after>// Copyright 2015 Vladimir Ivan

/*
 - Designer will publish:
 http://docs.ros.org/indigo/api/trajectory_msgs/html/msg/JointTrajectory.html
 - Designer will receive: (with root link as 0,0,0)
 http://docs.ros.org/indigo/api/sensor_msgs/html/msg/JointState.html
 */
#include <cstdlib>
#include <string>
#include <ros/ros.h>
#include <lcm/lcm-cpp.hpp>

#include "lcmtypes/drc/robot_plan_t.hpp"
#include "lcmtypes/drc/plan_control_t.hpp"
#include "lcmtypes/drc/affordance_collection_t.hpp"
#include "lcmtypes/drc/robot_state_t.hpp"
#include "lcmtypes/drc/exotica_planner_request_t.hpp"
#include "lcmtypes/drc/map_octree_t.hpp"
#include <trajectory_msgs/JointTrajectory.h>
#include <ipab_msgs/PlannerRequest.h>
#include <octomap_msgs/Octomap.h>
#include <std_srvs/Empty.h>
#include <std_msgs/String.h>

class LCM2ROS
{
public:
  LCM2ROS(boost::shared_ptr<lcm::LCM> &lcm_in, ros::NodeHandle &nh_in);
  ~LCM2ROS()
  {
  }

private:
  boost::shared_ptr<lcm::LCM> lcm_;
  ros::NodeHandle nh_;

  ros::Publisher planner_request_pub_;
  ros::Publisher ik_request_pub_;
  ros::Publisher octomap_pub_;

  void plannerRequestHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                             const drc::exotica_planner_request_t* msg);
  void ikRequestHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                        const drc::exotica_planner_request_t* msg);
  void octreeHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                        const drc::map_octree_t* msg);
};

LCM2ROS::LCM2ROS(boost::shared_ptr<lcm::LCM> &lcm_in, ros::NodeHandle &nh_in) : lcm_(lcm_in), nh_(nh_in)
{
  lcm_->subscribe("PLANNER_REQUEST", &LCM2ROS::plannerRequestHandler, this);
  planner_request_pub_ = nh_.advertise<ipab_msgs::PlannerRequest>("/exotica/planner_request", 10);

  lcm_->subscribe("IK_REQUEST", &LCM2ROS::ikRequestHandler, this);
  ik_request_pub_ = nh_.advertise<ipab_msgs::PlannerRequest>("/exotica/ik_request", 10);

  lcm_->subscribe("MAP_OCTREE", &LCM2ROS::octreeHandler, this);
  octomap_pub_ = nh_.advertise<octomap_msgs::Octomap>("/octomap_binary", 1);
}

void translatePlannerRequest(const drc::exotica_planner_request_t* msg, ipab_msgs::PlannerRequest& m)
{
  m.header.stamp = ros::Time().fromSec(msg->utime * 1E-6);
  m.poses = msg->poses;
  m.constraints = msg->constraints;
  m.affordances = msg->affordances;
  m.seed_pose = msg->seed_pose;
  m.nominal_pose = msg->nominal_pose;
  m.end_pose = msg->end_pose;
  m.joint_names = msg->joint_names;
  m.options = msg->options;
}

void LCM2ROS::plannerRequestHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                                    const drc::exotica_planner_request_t* msg)
{
  ROS_ERROR("LCM2ROS got PLANNER_REQUEST");
  ipab_msgs::PlannerRequest m;
  translatePlannerRequest(msg, m);
  planner_request_pub_.publish(m);
}

void LCM2ROS::ikRequestHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                               const drc::exotica_planner_request_t* msg)
{
  ROS_ERROR("LCM2ROS got IK_REQUEST");
  ipab_msgs::PlannerRequest m;
  translatePlannerRequest(msg, m);
  ik_request_pub_.publish(m);
}

void LCM2ROS::octreeHandler(const lcm::ReceiveBuffer* rbuf, const std::string &channel,
                               const drc::map_octree_t* msg)
{
  octomap_msgs::Octomap m;
  m.header.frame_id = "/world_frame";
  m.header.stamp = ros::Time().fromSec(msg->utime * 1E-6);

  // hard coded because the incoming message has no resolution
  // A better solution might be to also check the view_id if there are
  // multiple octrees being published
  m.id = "OcTree";
  m.resolution = 0.01;
  m.binary = true;
  m.data.resize(msg->num_bytes);
  memcpy(&m.data[0], msg->data.data(), msg->num_bytes);

  octomap_pub_.publish(m);
  ROS_ERROR("Publishing OCTOMAP");
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "lcm2ros", ros::init_options::NoSigintHandler);
  boost::shared_ptr<lcm::LCM> lcm(new lcm::LCM);
  if (!lcm->good())
  {
    std::cerr << "ERROR: lcm is not good()" << std::endl;
  }
  ros::NodeHandle nh;

  LCM2ROS handlerObject(lcm, nh);
  ROS_INFO_STREAM("lcm2ros translator ready");
  ROS_ERROR_STREAM("LCM2ROS Translator Ready");

  while (0 == lcm->handle())
  {
  }

  return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: sfxhelp.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: pb $ $Date: 2000-12-07 18:04:54 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "sfxhelp.hxx"

#pragma hdrstop

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_FRAME_XFRAME_HPP_
#include <com/sun/star/frame/XFrame.hpp>
#endif
#ifndef _UNOTOOLS_PROCESSFACTORY_HXX
#include <comphelper/processfactory.hxx>
#endif
#ifndef _COM_SUN_STAR_AWT_XWINDOW_HPP_
#include <com/sun/star/awt/XWindow.hpp>
#endif
#ifndef _COM_SUN_STAR_AWT_POSSIZE_HPP_
#include <com/sun/star/awt/PosSize.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XTASK_HPP_
#include <com/sun/star/frame/XTask.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XTASKSSUPPLIER_HPP_
#include <com/sun/star/frame/XTasksSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
#include <com/sun/star/util/XURLTransformer.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XDISPATCH_HPP_
#include <com/sun/star/frame/XDispatch.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDER_HPP_
#include <com/sun/star/frame/XDispatchProvider.hpp>
#endif
#include <com/sun/star/frame/FrameSearchFlag.hpp>
#include <toolkit/helper/vclunohelper.hxx>

#include "sfxsids.hrc"
#include "app.hxx"
#include "viewfrm.hxx"
#include "msgpool.hxx"
#include "newhelp.hxx"
#include "objsh.hxx"
#include "docfac.hxx"
#include "sfxresid.hxx"
#include "app.hrc"

using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;

SfxHelp_Impl::SfxHelp_Impl()
{
}

SfxHelp_Impl::~SfxHelp_Impl()
{
}

String SfxHelp_Impl::GetHelpModuleName( ULONG nHelpId )
{
    String aModuleName;
    SfxViewFrame *pViewFrame = SfxViewFrame::Current();
    if ( pViewFrame )
    {
        // Wenn es ein Slot ist, kann es sein, da\s internes InPlace vorliegt
        // und eine Container-SlotId gefragt ist
        if (nHelpId >= (ULONG) SID_SFX_START && nHelpId <= (ULONG) SHRT_MAX)
        {
            if ( pViewFrame->GetParentViewFrame_Impl() )
            {
                // Ist es ein ContainerSlot ?
                const SfxSlot* pSlot = SFX_APP()->GetSlotPool(pViewFrame).GetSlot( (USHORT) nHelpId );
                if ( !pSlot || pSlot->IsMode( SFX_SLOT_CONTAINER ) )
                    pViewFrame = pViewFrame->GetParentViewFrame_Impl();
            }
        }

        if( pViewFrame->GetObjectShell() )
            aModuleName = String::CreateFromAscii( pViewFrame->GetObjectShell()->GetFactory().GetShortName() );
    }

    return aModuleName;
}

BOOL SfxHelp_Impl::Start( ULONG nHelpId )
{
    Reference < XTasksSupplier > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
                DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );

    Reference < XTask > xActiveTask = xDesktop->getActiveTask();
    if ( !xActiveTask.is() )
        return FALSE;

    // build up the help URL
    String aHelpModuleName = GetHelpModuleName( nHelpId );
    String aHelpURL(String::CreateFromAscii("vnd.sun.star.help://") );
    aHelpURL += aHelpModuleName;
    aHelpURL += String( DEFINE_CONST_UNICODE("/start") );
//! aHelpURL += '/';
//! aHelpURL += String::CreateFromInt32( nHelpId );

    // try to find the help frame
    Reference < XDispatchProvider > xFrame(
        xActiveTask->findFrame( ::rtl::OUString::createFromAscii( "OFFICE_HELP" ),
        FrameSearchFlag::GLOBAL ), UNO_QUERY );
    ::com::sun::star::util::URL aURL;
    aURL.Complete = aHelpURL;
    Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance(
            DEFINE_CONST_UNICODE("com.sun.star.util.URLTransformer" )), UNO_QUERY );
    xTrans->parseStrict( aURL );

    Sequence < PropertyValue > aProps;
    sal_Int32 nFlag = FrameSearchFlag::GLOBAL;
    if ( aTicket.Len() )
    {
        // if there is a ticket, we are inside a plugin, so a request including the URL must be posted
        if ( !xFrame.is() )
            // must be created on dispatch
            nFlag |= FrameSearchFlag::CREATE;
    }
    else
    {
        // otherwise the URL can be dispatched to the help frame
        if ( !xFrame.is() )
        {
            Reference < XFrame > xTask = xActiveTask->findFrame( DEFINE_CONST_UNICODE( "_blank" ), 0 );
            xFrame = Reference < XDispatchProvider >( xTask, UNO_QUERY );
            Window* pWin = VCLUnoHelper::GetWindow( xTask->getContainerWindow() );
            pWin->SetText( String( SfxResId( STR_HELP_WINDOW_TITLE ) ) );
            SfxHelpWindow_Impl* pHlpWin = new SfxHelpWindow_Impl( xTask, pWin, WB_DOCKBORDER );
            pHlpWin->Show();
            Reference< ::com::sun::star::awt::XWindow > xWindow = VCLUnoHelper::GetInterface( pHlpWin );
            xWindow->setPosSize( 50, 50, 300, 200, ::com::sun::star::awt::PosSize::SIZE );
            if ( !xTask->setComponent( xWindow, Reference < XController >() ) )
                return FALSE;
            else
            {
                pHlpWin->setContainerWindow( xTask->getContainerWindow() );
                pHlpWin->SetFactory( aHelpModuleName );
                xTask->getContainerWindow()->setVisible( sal_True );
            }
        }
    }

    Reference < XDispatch > xDispatch = xFrame->queryDispatch( aURL,
                            DEFINE_CONST_UNICODE("OFFICE_HELP"), FrameSearchFlag::ALL );
    if ( xDispatch.is() )
    {
        xDispatch->dispatch( aURL, aProps );
    }

    return TRUE;
}

/*-----------------22.11.2000 10:59-----------------
 * old code
BOOL SfxHelp_Impl::ImplStart( ULONG nHelpId, BOOL bCheckHelpFile, BOOL bChangeHelpFile, BOOL bHelpAgent )
{
    static BOOL bInHelpRequest = FALSE;
    if ( bInHelpRequest || !nHelpId || ( nHelpId == SID_EXTENDEDHELP ) )
    {
        if ( bInHelpRequest )
            Sound::Beep();
        return FALSE;
    }

    if ( Help::IsRightHelp() )
    {
        if( ImplGetHelpMode() & HELPTEXTMODE_NOHELPAGENT )
            return FALSE;

        if ( ( nHelpId == HELP_INDEX ) || !CheckHelpFile( TRUE ) )
            return FALSE;

        bInHelpRequest = TRUE;
        SetCurrentHelpFile( nHelpId );
        StartHelpPI( nHelpId, FALSE, FALSE );
        bInHelpRequest = FALSE;
        return TRUE;
    }

    bInHelpRequest = TRUE;

    if( ImplGetHelpMode() & HELPTEXTMODE_NOCONTEXTHELP )
    {
        if( nHelpId < 20000 || nHelpId > 20006 )
            nHelpId = HELP_INDEX;
    }

    if ( bChangeHelpFile )
        SetCurrentHelpFile( nHelpId );

    BOOL bDone = FALSE;
    if ( !bCheckHelpFile || CheckHelpFile( TRUE ) )
    {
        SfxViewFrame* pFrame = SfxViewFrame::Current();
        if ( !bHelpAgent || ( nHelpId == HELP_INDEX ) )
//              !Application::IsInModalMode() &&
//              Application::GetAppWindow()->IsEnabled() &&
//              !SearchFocusWindowParent() &&   // kein Dialog aktiv
//              ( !pFrame || !pFrame->GetObjectShell()->IsInModalMode() ) )
        {
            SfxHelpViewShell* pViewShell = GetHelpViewShell( TRUE );
            if ( pViewShell )
                bDone = pViewShell->ShowHelp( GetHelpFile(), nHelpId );
        }
        else
        {
            StartHelpPI( nHelpId, TRUE, FALSE );
            SfxHelpPI* pHelpPI= SFX_APP()->GetHelpPI();
            if ( pHelpPI )
            {
                if ( !pHelpPI->IsFloatingMode() )
                {
                    pHelpPI->SetFloatingMode( TRUE );
                    bForcedFloatingPI = TRUE;
                }
                if ( pHelpPI->GetFloatingWindow() )
                    pHelpPI->GetFloatingWindow()->ToTop();
                CheckPIPosition();
                bDone = TRUE;
            }
        }
    }
    bInHelpRequest = FALSE;
    return bDone;
    return FALSE;
}
*/

struct HelpFileInfo;
class SfxHelp
{
public:
    static  BOOL            ShowHelp( ULONG nId, BOOL bShowInHelpAgent, const char* pFileName = 0, BOOL bQuiet = FALSE );
    static  BOOL            ShowHelp( const String& rKeyword, BOOL bShowInHelpAgent, const char* pFileName = 0 );
    static  void            ShowHint( ULONG nId );
    static  void            SetCustomHelpFile( const String& rName );
    static  USHORT          GetHelpFileInfoCount();
    static  HelpFileInfo*   GetHelpFileInfo( USHORT n );
};

BOOL SfxHelp::ShowHelp( ULONG nId, BOOL bShowInHelpAgent, const char* pFileName, BOOL bQuiet )
{
    return FALSE;
}

BOOL SfxHelp::ShowHelp( const String& rKeyword, BOOL bShowInHelpAgent, const char* pFileName )
{
    return FALSE;
}

void SfxHelp::ShowHint( ULONG nId )
{
}

void SfxHelp::SetCustomHelpFile( const String& rName )
{
}

USHORT SfxHelp::GetHelpFileInfoCount()
{
    return 0;
}

HelpFileInfo* SfxHelp::GetHelpFileInfo( USHORT n )
{
    return NULL;
}

class SfxHelpPI
{
public:
    void            LoadTopic( const String& rFileName, ULONG nId );
    void            LoadTopic( ULONG nId );
    void            LoadTopic( const String& rKeyword );
    void            ResetTopic();
    BOOL            Close();
//    BOOL            IsConstructed() const { return ( pHelpPI != 0 ); }
    String          GetExtraInfo() const;
//    HelpPI*         GetHelpPI() const { return pHelpPI; }
//    virtual void    FillInfo( SfxChildWinInfo& ) const;
    void            SetTip( ULONG nId );
    void            SetTipText( const String& rText );
//    BOOL            IsInShowMe() const { return bInShowMe; }
//    BOOL            IsTopicJustRequested() const { return aTopicJustRequestedTimer.IsActive(); }
//    void            SetTopicJustRequested( BOOL bOn ) { if( bOn )
//                                                            aTopicJustRequestedTimer.Start();
//                                                        else
//                                                            aTopicJustRequestedTimer.Stop(); }
};

void SfxHelpPI::LoadTopic( const String& rFileName, ULONG nId ) {}
void SfxHelpPI::LoadTopic( ULONG nId ) {}
void SfxHelpPI::LoadTopic( const String& rKeyword ) {}
void SfxHelpPI::ResetTopic() {}
//    BOOL            IsConstructed() const { return ( pHelpPI != 0 ); }
//    HelpPI*         GetHelpPI() const { return pHelpPI; }
//    virtual void    FillInfo( SfxChildWinInfo& ) const;
void SfxHelpPI::SetTip( ULONG nId ) {}
void SfxHelpPI::SetTipText( const String& rText ) {}

class SfxHelpPIWrapper
{
public:
    static USHORT GetChildWindowId();
};

USHORT SfxHelpPIWrapper::GetChildWindowId()
{
    return 0;
}

class SfxHelpTipsWrapper
{
public:
    static USHORT GetChildWindowId();
};

USHORT SfxHelpTipsWrapper::GetChildWindowId()
{
    return 0;
}
<commit_msg>fix: #81307# 0 == nHelpId starts the help-start-page<commit_after>/*************************************************************************
 *
 *  $RCSfile: sfxhelp.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: pb $ $Date: 2000-12-08 10:18:04 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "sfxhelp.hxx"

#pragma hdrstop

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_FRAME_XFRAME_HPP_
#include <com/sun/star/frame/XFrame.hpp>
#endif
#ifndef _UNOTOOLS_PROCESSFACTORY_HXX
#include <comphelper/processfactory.hxx>
#endif
#ifndef _COM_SUN_STAR_AWT_XWINDOW_HPP_
#include <com/sun/star/awt/XWindow.hpp>
#endif
#ifndef _COM_SUN_STAR_AWT_POSSIZE_HPP_
#include <com/sun/star/awt/PosSize.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XTASK_HPP_
#include <com/sun/star/frame/XTask.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XTASKSSUPPLIER_HPP_
#include <com/sun/star/frame/XTasksSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
#include <com/sun/star/util/XURLTransformer.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XDISPATCH_HPP_
#include <com/sun/star/frame/XDispatch.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDER_HPP_
#include <com/sun/star/frame/XDispatchProvider.hpp>
#endif
#include <com/sun/star/frame/FrameSearchFlag.hpp>
#include <toolkit/helper/vclunohelper.hxx>

#include "sfxsids.hrc"
#include "app.hxx"
#include "viewfrm.hxx"
#include "msgpool.hxx"
#include "newhelp.hxx"
#include "objsh.hxx"
#include "docfac.hxx"
#include "sfxresid.hxx"
#include "app.hrc"

using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;

SfxHelp_Impl::SfxHelp_Impl()
{
}

SfxHelp_Impl::~SfxHelp_Impl()
{
}

String SfxHelp_Impl::GetHelpModuleName( ULONG nHelpId )
{
    String aModuleName;
    SfxViewFrame *pViewFrame = SfxViewFrame::Current();
    if ( pViewFrame )
    {
        // Wenn es ein Slot ist, kann es sein, da\s internes InPlace vorliegt
        // und eine Container-SlotId gefragt ist
        if (nHelpId >= (ULONG) SID_SFX_START && nHelpId <= (ULONG) SHRT_MAX)
        {
            if ( pViewFrame->GetParentViewFrame_Impl() )
            {
                // Ist es ein ContainerSlot ?
                const SfxSlot* pSlot = SFX_APP()->GetSlotPool(pViewFrame).GetSlot( (USHORT) nHelpId );
                if ( !pSlot || pSlot->IsMode( SFX_SLOT_CONTAINER ) )
                    pViewFrame = pViewFrame->GetParentViewFrame_Impl();
            }
        }

        if( pViewFrame->GetObjectShell() )
            aModuleName = String::CreateFromAscii( pViewFrame->GetObjectShell()->GetFactory().GetShortName() );
    }

    return aModuleName;
}

BOOL SfxHelp_Impl::Start( ULONG nHelpId )
{
    Reference < XTasksSupplier > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
                DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );

    Reference < XTask > xActiveTask = xDesktop->getActiveTask();
    if ( !xActiveTask.is() )
        return FALSE;

    // build up the help URL
    String aHelpModuleName = GetHelpModuleName( nHelpId );
    String aHelpURL(String::CreateFromAscii("vnd.sun.star.help://") );
    aHelpURL += aHelpModuleName;
    if ( !nHelpId )
        aHelpURL += String( DEFINE_CONST_UNICODE("/start") );
    else
    {
        aHelpURL += '/';
        aHelpURL += String::CreateFromInt32( nHelpId );
    }

    // try to find the help frame
    Reference < XDispatchProvider > xFrame(
        xActiveTask->findFrame( ::rtl::OUString::createFromAscii( "OFFICE_HELP" ),
        FrameSearchFlag::GLOBAL ), UNO_QUERY );
    ::com::sun::star::util::URL aURL;
    aURL.Complete = aHelpURL;
    Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance(
            DEFINE_CONST_UNICODE("com.sun.star.util.URLTransformer" )), UNO_QUERY );
    xTrans->parseStrict( aURL );

    Sequence < PropertyValue > aProps;
    sal_Int32 nFlag = FrameSearchFlag::GLOBAL;
    if ( aTicket.Len() )
    {
        // if there is a ticket, we are inside a plugin, so a request including the URL must be posted
        if ( !xFrame.is() )
            // must be created on dispatch
            nFlag |= FrameSearchFlag::CREATE;
    }
    else
    {
        // otherwise the URL can be dispatched to the help frame
        if ( !xFrame.is() )
        {
            Reference < XFrame > xTask = xActiveTask->findFrame( DEFINE_CONST_UNICODE( "_blank" ), 0 );
            xFrame = Reference < XDispatchProvider >( xTask, UNO_QUERY );
            Window* pWin = VCLUnoHelper::GetWindow( xTask->getContainerWindow() );
            pWin->SetText( String( SfxResId( STR_HELP_WINDOW_TITLE ) ) );
            SfxHelpWindow_Impl* pHlpWin = new SfxHelpWindow_Impl( xTask, pWin, WB_DOCKBORDER );
            pHlpWin->Show();
            Reference< ::com::sun::star::awt::XWindow > xWindow = VCLUnoHelper::GetInterface( pHlpWin );
            xWindow->setPosSize( 50, 50, 300, 200, ::com::sun::star::awt::PosSize::SIZE );
            if ( !xTask->setComponent( xWindow, Reference < XController >() ) )
                return FALSE;
            else
            {
                pHlpWin->setContainerWindow( xTask->getContainerWindow() );
                pHlpWin->SetFactory( aHelpModuleName );
                xTask->getContainerWindow()->setVisible( sal_True );
            }
        }
    }

    Reference < XDispatch > xDispatch = xFrame->queryDispatch( aURL,
                            DEFINE_CONST_UNICODE("OFFICE_HELP"), FrameSearchFlag::ALL );
    if ( xDispatch.is() )
    {
        xDispatch->dispatch( aURL, aProps );
    }

    return TRUE;
}

/*-----------------22.11.2000 10:59-----------------
 * old code
BOOL SfxHelp_Impl::ImplStart( ULONG nHelpId, BOOL bCheckHelpFile, BOOL bChangeHelpFile, BOOL bHelpAgent )
{
    static BOOL bInHelpRequest = FALSE;
    if ( bInHelpRequest || !nHelpId || ( nHelpId == SID_EXTENDEDHELP ) )
    {
        if ( bInHelpRequest )
            Sound::Beep();
        return FALSE;
    }

    if ( Help::IsRightHelp() )
    {
        if( ImplGetHelpMode() & HELPTEXTMODE_NOHELPAGENT )
            return FALSE;

        if ( ( nHelpId == HELP_INDEX ) || !CheckHelpFile( TRUE ) )
            return FALSE;

        bInHelpRequest = TRUE;
        SetCurrentHelpFile( nHelpId );
        StartHelpPI( nHelpId, FALSE, FALSE );
        bInHelpRequest = FALSE;
        return TRUE;
    }

    bInHelpRequest = TRUE;

    if( ImplGetHelpMode() & HELPTEXTMODE_NOCONTEXTHELP )
    {
        if( nHelpId < 20000 || nHelpId > 20006 )
            nHelpId = HELP_INDEX;
    }

    if ( bChangeHelpFile )
        SetCurrentHelpFile( nHelpId );

    BOOL bDone = FALSE;
    if ( !bCheckHelpFile || CheckHelpFile( TRUE ) )
    {
        SfxViewFrame* pFrame = SfxViewFrame::Current();
        if ( !bHelpAgent || ( nHelpId == HELP_INDEX ) )
//              !Application::IsInModalMode() &&
//              Application::GetAppWindow()->IsEnabled() &&
//              !SearchFocusWindowParent() &&   // kein Dialog aktiv
//              ( !pFrame || !pFrame->GetObjectShell()->IsInModalMode() ) )
        {
            SfxHelpViewShell* pViewShell = GetHelpViewShell( TRUE );
            if ( pViewShell )
                bDone = pViewShell->ShowHelp( GetHelpFile(), nHelpId );
        }
        else
        {
            StartHelpPI( nHelpId, TRUE, FALSE );
            SfxHelpPI* pHelpPI= SFX_APP()->GetHelpPI();
            if ( pHelpPI )
            {
                if ( !pHelpPI->IsFloatingMode() )
                {
                    pHelpPI->SetFloatingMode( TRUE );
                    bForcedFloatingPI = TRUE;
                }
                if ( pHelpPI->GetFloatingWindow() )
                    pHelpPI->GetFloatingWindow()->ToTop();
                CheckPIPosition();
                bDone = TRUE;
            }
        }
    }
    bInHelpRequest = FALSE;
    return bDone;
    return FALSE;
}
*/

struct HelpFileInfo;
class SfxHelp
{
public:
    static  BOOL            ShowHelp( ULONG nId, BOOL bShowInHelpAgent, const char* pFileName = 0, BOOL bQuiet = FALSE );
    static  BOOL            ShowHelp( const String& rKeyword, BOOL bShowInHelpAgent, const char* pFileName = 0 );
    static  void            ShowHint( ULONG nId );
    static  void            SetCustomHelpFile( const String& rName );
    static  USHORT          GetHelpFileInfoCount();
    static  HelpFileInfo*   GetHelpFileInfo( USHORT n );
};

BOOL SfxHelp::ShowHelp( ULONG nId, BOOL bShowInHelpAgent, const char* pFileName, BOOL bQuiet )
{
    return FALSE;
}

BOOL SfxHelp::ShowHelp( const String& rKeyword, BOOL bShowInHelpAgent, const char* pFileName )
{
    return FALSE;
}

void SfxHelp::ShowHint( ULONG nId )
{
}

void SfxHelp::SetCustomHelpFile( const String& rName )
{
}

USHORT SfxHelp::GetHelpFileInfoCount()
{
    return 0;
}

HelpFileInfo* SfxHelp::GetHelpFileInfo( USHORT n )
{
    return NULL;
}

class SfxHelpPI
{
public:
    void            LoadTopic( const String& rFileName, ULONG nId );
    void            LoadTopic( ULONG nId );
    void            LoadTopic( const String& rKeyword );
    void            ResetTopic();
    BOOL            Close();
//    BOOL            IsConstructed() const { return ( pHelpPI != 0 ); }
    String          GetExtraInfo() const;
//    HelpPI*         GetHelpPI() const { return pHelpPI; }
//    virtual void    FillInfo( SfxChildWinInfo& ) const;
    void            SetTip( ULONG nId );
    void            SetTipText( const String& rText );
//    BOOL            IsInShowMe() const { return bInShowMe; }
//    BOOL            IsTopicJustRequested() const { return aTopicJustRequestedTimer.IsActive(); }
//    void            SetTopicJustRequested( BOOL bOn ) { if( bOn )
//                                                            aTopicJustRequestedTimer.Start();
//                                                        else
//                                                            aTopicJustRequestedTimer.Stop(); }
};

void SfxHelpPI::LoadTopic( const String& rFileName, ULONG nId ) {}
void SfxHelpPI::LoadTopic( ULONG nId ) {}
void SfxHelpPI::LoadTopic( const String& rKeyword ) {}
void SfxHelpPI::ResetTopic() {}
//    BOOL            IsConstructed() const { return ( pHelpPI != 0 ); }
//    HelpPI*         GetHelpPI() const { return pHelpPI; }
//    virtual void    FillInfo( SfxChildWinInfo& ) const;
void SfxHelpPI::SetTip( ULONG nId ) {}
void SfxHelpPI::SetTipText( const String& rText ) {}

class SfxHelpPIWrapper
{
public:
    static USHORT GetChildWindowId();
};

USHORT SfxHelpPIWrapper::GetChildWindowId()
{
    return 0;
}

class SfxHelpTipsWrapper
{
public:
    static USHORT GetChildWindowId();
};

USHORT SfxHelpTipsWrapper::GetChildWindowId()
{
    return 0;
}
<|endoftext|>


<commit_before>
#include "tinfra/json.h" // we test this
#include "tinfra/test.h"

SUITE(tinfra) {

using tinfra::variant;

const char* json_sample1 =
    "[ { \"name\": \"Moby Dick\","
    "    \"author\": \"Verne\" },"
    "  { \"name\": \"Solaris\","
    "    \"author\": \"Lem\"} ]";
TEST(json_sample1)
{
    tinfra::variant r = tinfra::json_parse(json_sample1);

    CHECK(r.is_array());
    CHECK(r[0].is_dict());
    CHECK(r[1].is_dict());

    std::string  written = tinfra::json_write(r);
    tinfra::variant reparsed = tinfra::json_parse(written);

    CHECK( reparsed == r );
}

TEST(json_integer_basic)
{
    using tinfra::variant;
    using tinfra::json_parse;
    CHECK_EQUAL(variant(0), json_parse("0"));
    CHECK_EQUAL(variant(-1), json_parse("-1"));
    CHECK_EQUAL(variant(256), json_parse("256"));
    CHECK_EQUAL(variant(-2147483648), json_parse("-2147483648"));
    CHECK_EQUAL(variant(2147483647), json_parse("2147483647"));

    CHECK_EQUAL(variant(-2147483648), json_parse("-2147483648"));
    CHECK_EQUAL(variant(2147483647), json_parse("2147483647"));
    //CHECK_EQUAL(variant(-9223372036854775807), json_parse("-9223372036854775807"));
    //CHECK_EQUAL(variant(9223372036854775807), json_parse("9223372036854775807"));
}

TEST(json_string_basic)
{
    using tinfra::variant;
    using tinfra::json_parse;
    CHECK_EQUAL(variant(""), json_parse("\"\""));
    CHECK_EQUAL(variant("foo"), json_parse("\"foo\""));
    CHECK_EQUAL(variant("foo\\\"bar\""), json_parse("\"foo\\\\\\\"bar\\\"\""));
    CHECK_EQUAL(variant("foo\r\nbar\t\b"), json_parse("\"foo\\r\\nbar\\t\\b\""));
}

TEST(json_string_errors)
{
    using tinfra::json_parse;

    CHECK_THROW( json_parse("\"fooo"), std::runtime_error);   // not finished string
    CHECK_THROW( json_parse("\"fooo\\"), std::runtime_error); // stray at end of not finished string
    CHECK_THROW( json_parse("\"fooo\\\""), std::runtime_error); // not finished again
    CHECK_THROW( json_parse("\"foo\\X"), std::runtime_error); // unkown escape character
}
TEST(json_parse_errors)
{
    using tinfra::json_parse;

    CHECK_THROW( json_parse("{"), std::runtime_error); // not finished
    CHECK_THROW( json_parse("{ XXX: 12 }"), std::runtime_error); // expecting string
    CHECK_THROW( json_parse("{ \"YYY\" 12 }"), std::runtime_error); // expecting colon
}
} // end suite tinfra
<commit_msg>json_test: test more<commit_after>
#include "tinfra/json.h" // we test this
#include "tinfra/test.h"

SUITE(tinfra) {

using tinfra::variant;

const char* json_sample1 =
    "[ { \"name\": \"Moby Dick\","
    "    \"author\": \"Verne\" },"
    "  { \"name\": \"Solaris\","
    "    \"author\": \"Lem\"} ]";
TEST(json_sample1)
{
    tinfra::variant r = tinfra::json_parse(json_sample1);

    CHECK(r.is_array());
    CHECK(r[0].is_dict());
    CHECK(r[1].is_dict());

    CHECK_EQUAL("Moby Dick", r[0]["name"]);
    CHECK_EQUAL("Verne", r[0]["author"]);

    CHECK_EQUAL("Solaris", r[1]["name"]);
    CHECK_EQUAL("Lem", r[1]["author"]);

    std::string  written = tinfra::json_write(r);
    tinfra::variant reparsed = tinfra::json_parse(written);

    CHECK( reparsed == r );
}

TEST(json_integer_basic)
{
    using tinfra::variant;
    using tinfra::json_parse;
    CHECK_EQUAL(variant(0), json_parse("0"));
    CHECK_EQUAL(variant(-1), json_parse("-1"));
    CHECK_EQUAL(variant(256), json_parse("256"));
    CHECK_EQUAL(variant(-2147483648), json_parse("-2147483648"));
    CHECK_EQUAL(variant(2147483647), json_parse("2147483647"));

    CHECK_EQUAL(variant(-2147483648), json_parse("-2147483648"));
    CHECK_EQUAL(variant(2147483647), json_parse("2147483647"));
    //CHECK_EQUAL(variant(-9223372036854775807), json_parse("-9223372036854775807"));
    //CHECK_EQUAL(variant(9223372036854775807), json_parse("9223372036854775807"));
}

TEST(json_string_basic)
{
    using tinfra::variant;
    using tinfra::json_parse;
    CHECK_EQUAL(variant(""), json_parse("\"\""));
    CHECK_EQUAL(variant("foo"), json_parse("\"foo\""));
    CHECK_EQUAL(variant("foo\\\"bar\""), json_parse("\"foo\\\\\\\"bar\\\"\""));
    CHECK_EQUAL(variant("foo\r\nbar\t\b"), json_parse("\"foo\\r\\nbar\\t\\b\""));
}

TEST(json_string_errors)
{
    using tinfra::json_parse;

    CHECK_THROW( json_parse("\"fooo"), std::runtime_error);   // not finished string
    CHECK_THROW( json_parse("\"fooo\\"), std::runtime_error); // stray at end of not finished string
    CHECK_THROW( json_parse("\"fooo\\\""), std::runtime_error); // not finished again
    CHECK_THROW( json_parse("\"foo\\X"), std::runtime_error); // unkown escape character
}
TEST(json_parse_errors)
{
    using tinfra::json_parse;

    CHECK_THROW( json_parse("{"), std::runtime_error); // not finished
    CHECK_THROW( json_parse("{ XXX: 12 }"), std::runtime_error); // expecting string
    CHECK_THROW( json_parse("{ \"YYY\" 12 }"), std::runtime_error); // expecting colon
}
} // end suite tinfra
<|endoftext|>