<commit_before>/*
 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/experiments/rate_control_settings.h"

#include <inttypes.h>
#include <stdio.h>

#include <string>

#include "absl/strings/match.h"
#include "api/transport/field_trial_based_config.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"

namespace webrtc {

namespace {

const int kDefaultAcceptedQueueMs = 250;

const int kDefaultMinPushbackTargetBitrateBps = 30000;

const char kVp8TrustedRateControllerFieldTrialName[] =
    "WebRTC-LibvpxVp8TrustedRateController";
const char kVp9TrustedRateControllerFieldTrialName[] =
    "WebRTC-LibvpxVp9TrustedRateController";

const char kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName[] =
    "WebRTC-UseBaseHeavyVP8TL3RateAllocation";

const char* kVideoHysteresisFieldTrialname =
    "WebRTC-SimulcastUpswitchHysteresisPercent";
const char* kScreenshareHysteresisFieldTrialname =
    "WebRTC-SimulcastScreenshareUpswitchHysteresisPercent";

bool IsEnabled(const WebRtcKeyValueConfig* const key_value_config,
               absl::string_view key) {
  return absl::StartsWith(key_value_config->Lookup(key), "Enabled");
}

void ParseHysteresisFactor(const WebRtcKeyValueConfig* const key_value_config,
                           absl::string_view key,
                           double* output_value) {
  std::string group_name = key_value_config->Lookup(key);
  int percent = 0;
  if (!group_name.empty() && sscanf(group_name.c_str(), "%d", &percent) == 1 &&
      percent >= 0) {
    *output_value = 1.0 + (percent / 100.0);
  }
}

}  // namespace

constexpr char CongestionWindowConfig::kKey[];

std::unique_ptr<StructParametersParser> CongestionWindowConfig::Parser() {
  return StructParametersParser::Create("QueueSize", &queue_size_ms,  //
                                        "MinBitrate", &min_bitrate_bps,
                                        "InitWin", &initial_data_window,
                                        "DropFrame", &drop_frame_only);
}

// static
CongestionWindowConfig CongestionWindowConfig::Parse(absl::string_view config) {
  CongestionWindowConfig res;
  res.Parser()->Parse(config);
  return res;
}

constexpr char VideoRateControlConfig::kKey[];

std::unique_ptr<StructParametersParser> VideoRateControlConfig::Parser() {
  // The empty comments ensures that each pair is on a separate line.
  return StructParametersParser::Create(
      "pacing_factor", &pacing_factor,                        //
      "alr_probing", &alr_probing,                            //
      "vp8_qp_max", &vp8_qp_max,                              //
      "vp8_min_pixels", &vp8_min_pixels,                      //
      "trust_vp8", &trust_vp8,                                //
      "trust_vp9", &trust_vp9,                                //
      "video_hysteresis", &video_hysteresis,                  //
      "screenshare_hysteresis", &screenshare_hysteresis,      //
      "probe_max_allocation", &probe_max_allocation,          //
      "bitrate_adjuster", &bitrate_adjuster,                  //
      "adjuster_use_headroom", &adjuster_use_headroom,        //
      "vp8_s0_boost", &vp8_s0_boost,                          //
      "vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc,  //
      "vp8_dynamic_rate", &vp8_dynamic_rate,                  //
      "vp9_dynamic_rate", &vp9_dynamic_rate);
}

RateControlSettings::RateControlSettings(
    const WebRtcKeyValueConfig* const key_value_config)
    : congestion_window_config_(CongestionWindowConfig::Parse(
          key_value_config->Lookup(CongestionWindowConfig::kKey))) {
  video_config_.trust_vp8 =
      IsEnabled(key_value_config, kVp8TrustedRateControllerFieldTrialName);
  video_config_.trust_vp9 =
      IsEnabled(key_value_config, kVp9TrustedRateControllerFieldTrialName);
  video_config_.vp8_base_heavy_tl3_alloc = IsEnabled(
      key_value_config, kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName);
  ParseHysteresisFactor(key_value_config, kVideoHysteresisFieldTrialname,
                        &video_config_.video_hysteresis);
  ParseHysteresisFactor(key_value_config, kScreenshareHysteresisFieldTrialname,
                        &video_config_.screenshare_hysteresis);
  video_config_.Parser()->Parse(
      key_value_config->Lookup(VideoRateControlConfig::kKey));
}

RateControlSettings::~RateControlSettings() = default;
RateControlSettings::RateControlSettings(RateControlSettings&&) = default;

RateControlSettings RateControlSettings::ParseFromFieldTrials() {
  FieldTrialBasedConfig field_trial_config;
  return RateControlSettings(&field_trial_config);
}

RateControlSettings RateControlSettings::ParseFromKeyValueConfig(
    const WebRtcKeyValueConfig* const key_value_config) {
  FieldTrialBasedConfig field_trial_config;
  return RateControlSettings(key_value_config ? key_value_config
                                              : &field_trial_config);
}

bool RateControlSettings::UseCongestionWindow() const {
  return static_cast<bool>(congestion_window_config_.queue_size_ms);
}

int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const {
  return congestion_window_config_.queue_size_ms.value_or(
      kDefaultAcceptedQueueMs);
}

bool RateControlSettings::UseCongestionWindowPushback() const {
  return congestion_window_config_.queue_size_ms &&
         congestion_window_config_.min_bitrate_bps;
}

bool RateControlSettings::UseCongestionWindowDropFrameOnly() const {
  return congestion_window_config_.drop_frame_only;
}

uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps()
    const {
  return congestion_window_config_.min_bitrate_bps.value_or(
      kDefaultMinPushbackTargetBitrateBps);
}

absl::optional<DataSize>
RateControlSettings::CongestionWindowInitialDataWindow() const {
  return congestion_window_config_.initial_data_window;
}

absl::optional<double> RateControlSettings::GetPacingFactor() const {
  return video_config_.pacing_factor;
}

bool RateControlSettings::UseAlrProbing() const {
  return video_config_.alr_probing;
}

absl::optional<int> RateControlSettings::LibvpxVp8QpMax() const {
  if (video_config_.vp8_qp_max &&
      (*video_config_.vp8_qp_max < 0 || *video_config_.vp8_qp_max > 63)) {
    RTC_LOG(LS_WARNING) << "Unsupported vp8_qp_max_ value, ignored.";
    return absl::nullopt;
  }
  return video_config_.vp8_qp_max;
}

absl::optional<int> RateControlSettings::LibvpxVp8MinPixels() const {
  if (video_config_.vp8_min_pixels && *video_config_.vp8_min_pixels < 1) {
    return absl::nullopt;
  }
  return video_config_.vp8_min_pixels;
}

bool RateControlSettings::LibvpxVp8TrustedRateController() const {
  return video_config_.trust_vp8;
}

bool RateControlSettings::Vp8BoostBaseLayerQuality() const {
  return video_config_.vp8_s0_boost;
}

bool RateControlSettings::Vp8DynamicRateSettings() const {
  return video_config_.vp8_dynamic_rate;
}

bool RateControlSettings::LibvpxVp9TrustedRateController() const {
  return video_config_.trust_vp9;
}

bool RateControlSettings::Vp9DynamicRateSettings() const {
  return video_config_.vp9_dynamic_rate;
}

double RateControlSettings::GetSimulcastHysteresisFactor(
    VideoCodecMode mode) const {
  if (mode == VideoCodecMode::kScreensharing) {
    return video_config_.screenshare_hysteresis;
  }
  return video_config_.video_hysteresis;
}

double RateControlSettings::GetSimulcastHysteresisFactor(
    VideoEncoderConfig::ContentType content_type) const {
  if (content_type == VideoEncoderConfig::ContentType::kScreen) {
    return video_config_.screenshare_hysteresis;
  }
  return video_config_.video_hysteresis;
}

bool RateControlSettings::Vp8BaseHeavyTl3RateAllocation() const {
  return video_config_.vp8_base_heavy_tl3_alloc;
}

bool RateControlSettings::TriggerProbeOnMaxAllocatedBitrateChange() const {
  return video_config_.probe_max_allocation;
}

bool RateControlSettings::UseEncoderBitrateAdjuster() const {
  return video_config_.bitrate_adjuster;
}

bool RateControlSettings::BitrateAdjusterCanUseNetworkHeadroom() const {
  return video_config_.adjuster_use_headroom;
}

}  // namespace webrtc
<commit_msg>Remove WebRTC-LibvpxVp{8,9}TrustedRateController.<commit_after>/*
 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/experiments/rate_control_settings.h"

#include <inttypes.h>
#include <stdio.h>

#include <string>

#include "absl/strings/match.h"
#include "api/transport/field_trial_based_config.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"

namespace webrtc {

namespace {

const int kDefaultAcceptedQueueMs = 250;

const int kDefaultMinPushbackTargetBitrateBps = 30000;

const char kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName[] =
    "WebRTC-UseBaseHeavyVP8TL3RateAllocation";

const char* kVideoHysteresisFieldTrialname =
    "WebRTC-SimulcastUpswitchHysteresisPercent";
const char* kScreenshareHysteresisFieldTrialname =
    "WebRTC-SimulcastScreenshareUpswitchHysteresisPercent";

bool IsEnabled(const WebRtcKeyValueConfig* const key_value_config,
               absl::string_view key) {
  return absl::StartsWith(key_value_config->Lookup(key), "Enabled");
}

void ParseHysteresisFactor(const WebRtcKeyValueConfig* const key_value_config,
                           absl::string_view key,
                           double* output_value) {
  std::string group_name = key_value_config->Lookup(key);
  int percent = 0;
  if (!group_name.empty() && sscanf(group_name.c_str(), "%d", &percent) == 1 &&
      percent >= 0) {
    *output_value = 1.0 + (percent / 100.0);
  }
}

}  // namespace

constexpr char CongestionWindowConfig::kKey[];

std::unique_ptr<StructParametersParser> CongestionWindowConfig::Parser() {
  return StructParametersParser::Create("QueueSize", &queue_size_ms,  //
                                        "MinBitrate", &min_bitrate_bps,
                                        "InitWin", &initial_data_window,
                                        "DropFrame", &drop_frame_only);
}

// static
CongestionWindowConfig CongestionWindowConfig::Parse(absl::string_view config) {
  CongestionWindowConfig res;
  res.Parser()->Parse(config);
  return res;
}

constexpr char VideoRateControlConfig::kKey[];

std::unique_ptr<StructParametersParser> VideoRateControlConfig::Parser() {
  // The empty comments ensures that each pair is on a separate line.
  return StructParametersParser::Create(
      "pacing_factor", &pacing_factor,                        //
      "alr_probing", &alr_probing,                            //
      "vp8_qp_max", &vp8_qp_max,                              //
      "vp8_min_pixels", &vp8_min_pixels,                      //
      "trust_vp8", &trust_vp8,                                //
      "trust_vp9", &trust_vp9,                                //
      "video_hysteresis", &video_hysteresis,                  //
      "screenshare_hysteresis", &screenshare_hysteresis,      //
      "probe_max_allocation", &probe_max_allocation,          //
      "bitrate_adjuster", &bitrate_adjuster,                  //
      "adjuster_use_headroom", &adjuster_use_headroom,        //
      "vp8_s0_boost", &vp8_s0_boost,                          //
      "vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc,  //
      "vp8_dynamic_rate", &vp8_dynamic_rate,                  //
      "vp9_dynamic_rate", &vp9_dynamic_rate);
}

RateControlSettings::RateControlSettings(
    const WebRtcKeyValueConfig* const key_value_config)
    : congestion_window_config_(CongestionWindowConfig::Parse(
          key_value_config->Lookup(CongestionWindowConfig::kKey))) {
  video_config_.vp8_base_heavy_tl3_alloc = IsEnabled(
      key_value_config, kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName);
  ParseHysteresisFactor(key_value_config, kVideoHysteresisFieldTrialname,
                        &video_config_.video_hysteresis);
  ParseHysteresisFactor(key_value_config, kScreenshareHysteresisFieldTrialname,
                        &video_config_.screenshare_hysteresis);
  video_config_.Parser()->Parse(
      key_value_config->Lookup(VideoRateControlConfig::kKey));
}

RateControlSettings::~RateControlSettings() = default;
RateControlSettings::RateControlSettings(RateControlSettings&&) = default;

RateControlSettings RateControlSettings::ParseFromFieldTrials() {
  FieldTrialBasedConfig field_trial_config;
  return RateControlSettings(&field_trial_config);
}

RateControlSettings RateControlSettings::ParseFromKeyValueConfig(
    const WebRtcKeyValueConfig* const key_value_config) {
  FieldTrialBasedConfig field_trial_config;
  return RateControlSettings(key_value_config ? key_value_config
                                              : &field_trial_config);
}

bool RateControlSettings::UseCongestionWindow() const {
  return static_cast<bool>(congestion_window_config_.queue_size_ms);
}

int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const {
  return congestion_window_config_.queue_size_ms.value_or(
      kDefaultAcceptedQueueMs);
}

bool RateControlSettings::UseCongestionWindowPushback() const {
  return congestion_window_config_.queue_size_ms &&
         congestion_window_config_.min_bitrate_bps;
}

bool RateControlSettings::UseCongestionWindowDropFrameOnly() const {
  return congestion_window_config_.drop_frame_only;
}

uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps()
    const {
  return congestion_window_config_.min_bitrate_bps.value_or(
      kDefaultMinPushbackTargetBitrateBps);
}

absl::optional<DataSize>
RateControlSettings::CongestionWindowInitialDataWindow() const {
  return congestion_window_config_.initial_data_window;
}

absl::optional<double> RateControlSettings::GetPacingFactor() const {
  return video_config_.pacing_factor;
}

bool RateControlSettings::UseAlrProbing() const {
  return video_config_.alr_probing;
}

absl::optional<int> RateControlSettings::LibvpxVp8QpMax() const {
  if (video_config_.vp8_qp_max &&
      (*video_config_.vp8_qp_max < 0 || *video_config_.vp8_qp_max > 63)) {
    RTC_LOG(LS_WARNING) << "Unsupported vp8_qp_max_ value, ignored.";
    return absl::nullopt;
  }
  return video_config_.vp8_qp_max;
}

absl::optional<int> RateControlSettings::LibvpxVp8MinPixels() const {
  if (video_config_.vp8_min_pixels && *video_config_.vp8_min_pixels < 1) {
    return absl::nullopt;
  }
  return video_config_.vp8_min_pixels;
}

bool RateControlSettings::LibvpxVp8TrustedRateController() const {
  return video_config_.trust_vp8;
}

bool RateControlSettings::Vp8BoostBaseLayerQuality() const {
  return video_config_.vp8_s0_boost;
}

bool RateControlSettings::Vp8DynamicRateSettings() const {
  return video_config_.vp8_dynamic_rate;
}

bool RateControlSettings::LibvpxVp9TrustedRateController() const {
  return video_config_.trust_vp9;
}

bool RateControlSettings::Vp9DynamicRateSettings() const {
  return video_config_.vp9_dynamic_rate;
}

double RateControlSettings::GetSimulcastHysteresisFactor(
    VideoCodecMode mode) const {
  if (mode == VideoCodecMode::kScreensharing) {
    return video_config_.screenshare_hysteresis;
  }
  return video_config_.video_hysteresis;
}

double RateControlSettings::GetSimulcastHysteresisFactor(
    VideoEncoderConfig::ContentType content_type) const {
  if (content_type == VideoEncoderConfig::ContentType::kScreen) {
    return video_config_.screenshare_hysteresis;
  }
  return video_config_.video_hysteresis;
}

bool RateControlSettings::Vp8BaseHeavyTl3RateAllocation() const {
  return video_config_.vp8_base_heavy_tl3_alloc;
}

bool RateControlSettings::TriggerProbeOnMaxAllocatedBitrateChange() const {
  return video_config_.probe_max_allocation;
}

bool RateControlSettings::UseEncoderBitrateAdjuster() const {
  return video_config_.bitrate_adjuster;
}

bool RateControlSettings::BitrateAdjusterCanUseNetworkHeadroom() const {
  return video_config_.adjuster_use_headroom;
}

}  // namespace webrtc
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkContextView.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkContextView.h"

#include "vtkContext2D.h"
#include "vtkOpenGLContextDevice2D.h"
#include "vtkContextScene.h"

#include "vtkViewport.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkInteractorStyle.h"
#include "vtkContextActor.h"

#include "vtkObjectFactory.h"

vtkStandardNewMacro(vtkContextView);

vtkCxxSetObjectMacro(vtkContextView, Context, vtkContext2D);
vtkCxxSetObjectMacro(vtkContextView, Scene, vtkContextScene);

//----------------------------------------------------------------------------
vtkContextView::vtkContextView()
{
  this->Context = vtkContext2D::New();
  vtkOpenGLContextDevice2D *pd = vtkOpenGLContextDevice2D::New();
  this->Context->Begin(pd);
  pd->Delete();

  vtkContextActor *actor = vtkContextActor::New();
  this->Renderer->AddActor(actor);
  actor->Delete();
  this->Scene = actor->GetScene(); // We keep a pointer to this for convenience
  this->Scene->Register(this);
  // Should not need to do this...
  this->Scene->SetRenderer(this->Renderer);

  // Single color background
  this->Renderer->SetBackground(1.0, 1.0, 1.0);
  this->Renderer->SetBackground2(1.0, 1.0, 1.0);
}

//----------------------------------------------------------------------------
vtkContextView::~vtkContextView()
{
  if (this->Context)
    {
    this->Context->Delete();
    this->Context = NULL;
    }
  // The scene is owned by the context actor
  if (this->Scene)
    {
    this->Scene->Delete();
    this->Scene = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkContextView::Render()
{
  this->Update();
  this->PrepareForRendering();
  this->Renderer->ResetCameraClippingRange();
  this->RenderWindow->Render();

  // Render our scene
/*  this->Context->GetDevice()->Begin(this->Renderer);
  int size[2];
  size[0] = this->Renderer->GetSize()[0];
  size[1] = this->Renderer->GetSize()[1];
  this->Scene->SetGeometry(&size[0]);
  this->Scene->Paint(this->Context);
  this->Context->GetDevice()->End(); */
}

//----------------------------------------------------------------------------
void vtkContextView::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Context: " << this->Context << "\n";
  if (this->Context)
    {
    this->Context->PrintSelf(os, indent.GetNextIndent());
    }
}
<commit_msg>BUG: Fixed interaction in 2D scenes after refactoring.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkContextView.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkContextView.h"

#include "vtkContext2D.h"
#include "vtkOpenGLContextDevice2D.h"
#include "vtkContextScene.h"

#include "vtkViewport.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkInteractorStyle.h"
#include "vtkContextActor.h"

#include "vtkObjectFactory.h"

vtkStandardNewMacro(vtkContextView);

vtkCxxSetObjectMacro(vtkContextView, Context, vtkContext2D);
vtkCxxSetObjectMacro(vtkContextView, Scene, vtkContextScene);

//----------------------------------------------------------------------------
vtkContextView::vtkContextView()
{
  this->Context = vtkContext2D::New();
  vtkOpenGLContextDevice2D *pd = vtkOpenGLContextDevice2D::New();
  this->Context->Begin(pd);
  pd->Delete();

  vtkContextActor *actor = vtkContextActor::New();
  this->Renderer->AddActor(actor);
  actor->Delete();
  this->Scene = actor->GetScene(); // We keep a pointer to this for convenience
  this->Scene->Register(this);
  // Should not need to do this...
  this->Scene->SetRenderer(this->Renderer);
  this->Scene->SetInteractorStyle(
      vtkInteractorStyle::SafeDownCast(this->RenderWindow->GetInteractor()
                                       ->GetInteractorStyle()));

  // Single color background
  this->Renderer->SetBackground(1.0, 1.0, 1.0);
}

//----------------------------------------------------------------------------
vtkContextView::~vtkContextView()
{
  if (this->Context)
    {
    this->Context->Delete();
    this->Context = NULL;
    }
  // The scene is owned by the context actor
  if (this->Scene)
    {
    this->Scene->Delete();
    this->Scene = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkContextView::Render()
{
  this->Update();
  this->PrepareForRendering();
  this->Renderer->ResetCameraClippingRange();
  this->RenderWindow->Render();

  // Render our scene
/*  this->Context->GetDevice()->Begin(this->Renderer);
  int size[2];
  size[0] = this->Renderer->GetSize()[0];
  size[1] = this->Renderer->GetSize()[1];
  this->Scene->SetGeometry(&size[0]);
  this->Scene->Paint(this->Context);
  this->Context->GetDevice()->End(); */
}

//----------------------------------------------------------------------------
void vtkContextView::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Context: " << this->Context << "\n";
  if (this->Context)
    {
    this->Context->PrintSelf(os, indent.GetNextIndent());
    }
}
<|endoftext|>


<commit_before>//
// Created by yanxq on 17/2/15.
//

#include <jni.h>
#include <string.h>
#include "smoke_base.h"
#include "smoke_jni_log.h"
#include "coffeecatch/coffeecatch.h"

static bool console_print_enable = false;

extern "C" {

//JNIEXPORT void JNICALL
//Java_com_mingyuans_smoke_DefaultFilePrinter_jniConsoleEnable(JNIEnv *env, jclass type, jboolean enable) {
//    console_print_enable = enable;
//}

static void report_error_to_java(JNIEnv *env,const char *message) {
    jclass clazz = env->FindClass("com/mingyuans/smoke/SmokeUncaughtErrorHandler");
    if (clazz) {
        jmethodID  callback_method = env->GetStaticMethodID(clazz,"onAndroidNativeCrash","(Ljava/lang/String;)V");
        if (callback_method) {
            jstring message_ = env->NewStringUTF(message);
            env->CallStaticVoidMethod(clazz,callback_method,message_);
            env->DeleteLocalRef(message_);
        } else {
            smoke_jni::console_debug(__FUNCTION__,"Couldn't find onAndroidNativeCrash method!");
        }
    } else {
        smoke_jni::console_debug(__FUNCTION__,"Couldn't find com/mingyuans/smoke/SmokeUncaughtErrorHandler!");
    }
}

JNIEXPORT void JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniPrintln(JNIEnv *env, jobject instance, jint level, jstring tag_,
                                          jobjectArray message_) {
    const char *tag = env->GetStringUTFChars(tag_, 0);

    int array_length = env->GetArrayLength(message_);
    const char *message_array[array_length];
    for (int i = 0; i < array_length; ++i) {
        jstring one_msg = (jstring) env->GetObjectArrayElement(message_, i);
        const char *message = env->GetStringUTFChars(one_msg, 0);
        message_array[i] = message;
    }

    if (console_print_enable) {
        for (int i = 0; i < array_length; ++i) {
            smoke::_console_println(level, tag, message_array[i]);
        }
    }

    COFFEE_TRY() {
        smoke::_write_log_array(level, tag, message_array,array_length);
    } COFFEE_CATCH() {
        const char* message = coffeecatch_get_message();
        report_error_to_java(env,message);
    } COFFEE_END();

    env->ReleaseStringUTFChars(tag_, tag);
    for (int i = 0; i < array_length; ++i) {
        jstring one_msg = (jstring) env->GetObjectArrayElement(message_, i);
        env->ReleaseStringUTFChars(one_msg,message_array[i]);
    }
}

JNIEXPORT void JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniOpen(JNIEnv *env, jobject instance, jint append_mode_,jstring file_dir_,
                                          jstring cache_dir_, jstring name_prefix_, jstring suffix_) {

    const char *file_dir = env->GetStringUTFChars(file_dir_, 0);
    const char *cache_dir = env->GetStringUTFChars(cache_dir_, 0);
    const char *name_prefix = env->GetStringUTFChars(name_prefix_, 0);
    const char *file_suffix = env->GetStringUTFChars(suffix_,0);

    COFFEE_TRY() {
        smoke::_open(append_mode_,file_dir,cache_dir,name_prefix,file_suffix);
    } COFFEE_CATCH() {
        const char* message = coffeecatch_get_message();
        report_error_to_java(env,message);
    } COFFEE_END();

    env->ReleaseStringUTFChars(file_dir_, file_dir);
    env->ReleaseStringUTFChars(cache_dir_, cache_dir);
    env->ReleaseStringUTFChars(name_prefix_, name_prefix);
}

JNIEXPORT void JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniClose(JNIEnv *env, jobject instance) {
    smoke::_close();
}

JNIEXPORT jstring JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniGetLogDirPath(JNIEnv *env, jobject instance) {
    const char * log_dir = smoke::_get_log_dir();
    const char * log_dir_temp = strdup(log_dir);
    return env->NewStringUTF(log_dir_temp);
}

JNIEXPORT jstring JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniCurrentLogFilePath(JNIEnv *env, jobject instance) {
    const char * log_file_path = smoke::_get_current_file_path();
    const char * log_file_path_temp = strdup(log_file_path);
    return env->NewStringUTF(log_file_path_temp);
}

JNIEXPORT jstring JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_flush(JNIEnv *env, jobject instance) {
    smoke::_flush();
}

JNIEXPORT jstring JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_flushSync(JNIEnv *env, jobject instance) {
    smoke::_flush_sync();
}

JNIEXPORT jobjectArray JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniGetLogFilesFromTimespan(JNIEnv *env, jobject instance,jint timespan_,jstring name_prefix_) {
    const char *_name_prefix = env->GetStringUTFChars(name_prefix_, 0);
    std::vector<std::string> _log_files = std::vector<std::string>();
    smoke::_get_logs_from_timespan(timespan_,_name_prefix,_log_files);
    env->ReleaseStringUTFChars(name_prefix_,_name_prefix);
    jclass stringClazz = env->FindClass("java/lang/String");
    jobjectArray  _log_file_array = env->NewObjectArray(_log_files.size(),stringClazz,NULL);
    for (int i = 0,size=_log_files.size(); i < size; ++i) {
        std::string _log_file = _log_files.at(i);
        jstring child_str = env->NewStringUTF(_log_file.c_str());
        env->SetObjectArrayElement(_log_file_array,i,child_str);
    }
    return _log_file_array;
}

}
<commit_msg>fix JNI 方法未返回编译警告<commit_after>//
// Created by yanxq on 17/2/15.
//

#include <jni.h>
#include <string.h>
#include "smoke_base.h"
#include "smoke_jni_log.h"
#include "coffeecatch/coffeecatch.h"

static bool console_print_enable = false;

extern "C" {

//JNIEXPORT void JNICALL
//Java_com_mingyuans_smoke_DefaultFilePrinter_jniConsoleEnable(JNIEnv *env, jclass type, jboolean enable) {
//    console_print_enable = enable;
//}

static void report_error_to_java(JNIEnv *env,const char *message) {
    jclass clazz = env->FindClass("com/mingyuans/smoke/SmokeUncaughtErrorHandler");
    if (clazz) {
        jmethodID  callback_method = env->GetStaticMethodID(clazz,"onAndroidNativeCrash","(Ljava/lang/String;)V");
        if (callback_method) {
            jstring message_ = env->NewStringUTF(message);
            env->CallStaticVoidMethod(clazz,callback_method,message_);
            env->DeleteLocalRef(message_);
        } else {
            smoke_jni::console_debug(__FUNCTION__,"Couldn't find onAndroidNativeCrash method!");
        }
    } else {
        smoke_jni::console_debug(__FUNCTION__,"Couldn't find com/mingyuans/smoke/SmokeUncaughtErrorHandler!");
    }
}

JNIEXPORT void JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniPrintln(JNIEnv *env, jobject instance, jint level, jstring tag_,
                                          jobjectArray message_) {
    const char *tag = env->GetStringUTFChars(tag_, 0);

    int array_length = env->GetArrayLength(message_);
    const char *message_array[array_length];
    for (int i = 0; i < array_length; ++i) {
        jstring one_msg = (jstring) env->GetObjectArrayElement(message_, i);
        const char *message = env->GetStringUTFChars(one_msg, 0);
        message_array[i] = message;
    }

    if (console_print_enable) {
        for (int i = 0; i < array_length; ++i) {
            smoke::_console_println(level, tag, message_array[i]);
        }
    }

    COFFEE_TRY() {
        smoke::_write_log_array(level, tag, message_array,array_length);
    } COFFEE_CATCH() {
        const char* message = coffeecatch_get_message();
        report_error_to_java(env,message);
    } COFFEE_END();

    env->ReleaseStringUTFChars(tag_, tag);
    for (int i = 0; i < array_length; ++i) {
        jstring one_msg = (jstring) env->GetObjectArrayElement(message_, i);
        env->ReleaseStringUTFChars(one_msg,message_array[i]);
    }
}

JNIEXPORT void JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniOpen(JNIEnv *env, jobject instance, jint append_mode_,jstring file_dir_,
                                          jstring cache_dir_, jstring name_prefix_, jstring suffix_) {

    const char *file_dir = env->GetStringUTFChars(file_dir_, 0);
    const char *cache_dir = env->GetStringUTFChars(cache_dir_, 0);
    const char *name_prefix = env->GetStringUTFChars(name_prefix_, 0);
    const char *file_suffix = env->GetStringUTFChars(suffix_,0);

    COFFEE_TRY() {
        smoke::_open(append_mode_,file_dir,cache_dir,name_prefix,file_suffix);
    } COFFEE_CATCH() {
        const char* message = coffeecatch_get_message();
        report_error_to_java(env,message);
    } COFFEE_END();

    env->ReleaseStringUTFChars(file_dir_, file_dir);
    env->ReleaseStringUTFChars(cache_dir_, cache_dir);
    env->ReleaseStringUTFChars(name_prefix_, name_prefix);
}

JNIEXPORT void JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniClose(JNIEnv *env, jobject instance) {
    smoke::_close();
}

JNIEXPORT jstring JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniGetLogDirPath(JNIEnv *env, jobject instance) {
    const char * log_dir = smoke::_get_log_dir();
    const char * log_dir_temp = strdup(log_dir);
    return env->NewStringUTF(log_dir_temp);
}

JNIEXPORT jstring JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniCurrentLogFilePath(JNIEnv *env, jobject instance) {
    const char * log_file_path = smoke::_get_current_file_path();
    const char * log_file_path_temp = strdup(log_file_path);
    return env->NewStringUTF(log_file_path_temp);
}

JNIEXPORT void JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_flush(JNIEnv *env, jobject instance) {
    smoke::_flush();
}

JNIEXPORT void JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_flushSync(JNIEnv *env, jobject instance) {
    smoke::_flush_sync();
}

JNIEXPORT jobjectArray JNICALL
Java_com_mingyuans_smoke_android_file_AndroidFilePrinter_jniGetLogFilesFromTimespan(JNIEnv *env, jobject instance,jint timespan_,jstring name_prefix_) {
    const char *_name_prefix = env->GetStringUTFChars(name_prefix_, 0);
    std::vector<std::string> _log_files = std::vector<std::string>();
    smoke::_get_logs_from_timespan(timespan_,_name_prefix,_log_files);
    env->ReleaseStringUTFChars(name_prefix_,_name_prefix);
    jclass stringClazz = env->FindClass("java/lang/String");
    jobjectArray  _log_file_array = env->NewObjectArray(_log_files.size(),stringClazz,NULL);
    for (int i = 0,size=_log_files.size(); i < size; ++i) {
        std::string _log_file = _log_files.at(i);
        jstring child_str = env->NewStringUTF(_log_file.c_str());
        env->SetObjectArrayElement(_log_file_array,i,child_str);
    }
    return _log_file_array;
}

}
<|endoftext|>


<commit_before>//
// Urho3D Engine
// Copyright (c) 2008-2011 Lasse rni
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "Precompiled.h"
#include "Thread.h"
#include "Timer.h"
#include "WorkQueue.h"

/// Worker thread managed by the work queue.
class WorkerThread : public Thread, public RefCounted
{
public:
    /// Construct.
    WorkerThread(WorkQueue* owner, unsigned index) :
        owner_(owner),
        index_(index)
    {
    }

    /// Process work items until stopped.
    virtual void ThreadFunction() { owner_->ProcessItems(index_); }

    /// Return thread index.
    unsigned GetIndex() const { return index_; }

private:
    /// Work queue.
    WorkQueue* owner_;
    /// Thread index.
    unsigned index_;
};

OBJECTTYPESTATIC(WorkQueue);

WorkQueue::WorkQueue(Context* context) :
    Object(context),
    numActive_(0),
    shutDown_(false),
    paused_(false)
{
}

WorkQueue::~WorkQueue()
{
    // Stop the worker threads. First make sure they are not waiting for work items
    shutDown_ = true;
    if (paused_)
    {
        queueMutex_.Release();
        paused_ = false;
    }

    for (unsigned i = 0; i < threads_.Size(); ++i)
        threads_[i]->Stop();
}

void WorkQueue::CreateThreads(unsigned numThreads)
{
    // Other subsystems may initialize themselves according to the number of threads.
    // Therefore allow creating the threads only once, after which the amount is fixed
    if (!threads_.Empty())
        return;

    // Start threads in paused mode
    Pause();

    for (unsigned i = 0; i < numThreads; ++i)
    {
        SharedPtr<WorkerThread> thread(new WorkerThread(this, i + 1));
        thread->Start();
        threads_.Push(thread);
    }
}

void WorkQueue::AddWorkItem(const WorkItem& item)
{
    if (threads_.Size())
    {
        if (paused_)
        {
            queue_.Push(item);
            queueMutex_.Release();
            paused_ = false;
        }
        else
        {
            queueMutex_.Acquire();
            queue_.Push(item);
            queueMutex_.Release();
        }
    }
    else
        item.workFunction_(&item, 0);
}

void WorkQueue::Pause()
{
    if (!paused_)
    {
        queueMutex_.Acquire();
        paused_ = true;
    }
}

void WorkQueue::Resume()
{
    if (paused_)
    {
        queueMutex_.Release();
        paused_ = false;
    }
}

void WorkQueue::Complete()
{
    if (threads_.Size())
    {
        Resume();

        for (;;)
        {
            queueMutex_.Acquire();
            if (!queue_.Empty())
            {
                WorkItem item = queue_.Front();
                queue_.PopFront();
                queueMutex_.Release();
                item.workFunction_(&item, 0);
            }
            else
            {
                if (numActive_)
                    queueMutex_.Release();
                else
                {
                    // All work items are done. Leave the mutex locked and re-enter pause mode
                    paused_ = true;
                    return;
                }
            }
        }
    }
}

bool WorkQueue::IsCompleted()
{
    if (threads_.Size())
        return !numActive_ && queue_.Empty();
    else
        return true;
}

void WorkQueue::ProcessItems(unsigned threadIndex)
{
    bool wasActive = false;

    for (;;)
    {
        if (shutDown_)
            return;

        queueMutex_.Acquire();
        if (!queue_.Empty())
        {
            if (!wasActive)
            {
                ++numActive_;
                wasActive = true;
            }
            WorkItem item = queue_.Front();
            queue_.PopFront();
            queueMutex_.Release();
            item.workFunction_(&item, threadIndex);
        }
        else
        {
            if (wasActive)
            {
                --numActive_;
                wasActive = false;
            }
            queueMutex_.Release();
            // When transitioning from working to waiting, give up the time slice so that it is easier
            // for the main thread to re-lock the mutex
            Time::Sleep(0);
        }
    }
}
<commit_msg>Repositioned the sleep in the worker thread for improved performance in starting work.<commit_after>//
// Urho3D Engine
// Copyright (c) 2008-2011 Lasse rni
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "Precompiled.h"
#include "Thread.h"
#include "Timer.h"
#include "WorkQueue.h"

/// Worker thread managed by the work queue.
class WorkerThread : public Thread, public RefCounted
{
public:
    /// Construct.
    WorkerThread(WorkQueue* owner, unsigned index) :
        owner_(owner),
        index_(index)
    {
    }

    /// Process work items until stopped.
    virtual void ThreadFunction() { owner_->ProcessItems(index_); }

    /// Return thread index.
    unsigned GetIndex() const { return index_; }

private:
    /// Work queue.
    WorkQueue* owner_;
    /// Thread index.
    unsigned index_;
};

OBJECTTYPESTATIC(WorkQueue);

WorkQueue::WorkQueue(Context* context) :
    Object(context),
    numActive_(0),
    shutDown_(false),
    paused_(false)
{
}

WorkQueue::~WorkQueue()
{
    // Stop the worker threads. First make sure they are not waiting for work items
    shutDown_ = true;
    if (paused_)
    {
        queueMutex_.Release();
        paused_ = false;
    }

    for (unsigned i = 0; i < threads_.Size(); ++i)
        threads_[i]->Stop();
}

void WorkQueue::CreateThreads(unsigned numThreads)
{
    // Other subsystems may initialize themselves according to the number of threads.
    // Therefore allow creating the threads only once, after which the amount is fixed
    if (!threads_.Empty())
        return;

    // Start threads in paused mode
    Pause();

    for (unsigned i = 0; i < numThreads; ++i)
    {
        SharedPtr<WorkerThread> thread(new WorkerThread(this, i + 1));
        thread->Start();
        threads_.Push(thread);
    }
}

void WorkQueue::AddWorkItem(const WorkItem& item)
{
    if (threads_.Size())
    {
        if (paused_)
        {
            queue_.Push(item);
            queueMutex_.Release();
            paused_ = false;
        }
        else
        {
            queueMutex_.Acquire();
            queue_.Push(item);
            queueMutex_.Release();
        }
    }
    else
        item.workFunction_(&item, 0);
}

void WorkQueue::Pause()
{
    if (!paused_)
    {
        queueMutex_.Acquire();
        paused_ = true;
    }
}

void WorkQueue::Resume()
{
    if (paused_)
    {
        queueMutex_.Release();
        paused_ = false;
    }
}

void WorkQueue::Complete()
{
    if (threads_.Size())
    {
        Resume();

        for (;;)
        {
            queueMutex_.Acquire();
            if (!queue_.Empty())
            {
                WorkItem item = queue_.Front();
                queue_.PopFront();
                queueMutex_.Release();
                item.workFunction_(&item, 0);
            }
            else
            {
                if (numActive_)
                    queueMutex_.Release();
                else
                {
                    // All work items are done. Leave the mutex locked and re-enter pause mode
                    paused_ = true;
                    return;
                }
            }
        }
    }
}

bool WorkQueue::IsCompleted()
{
    if (threads_.Size())
        return !numActive_ && queue_.Empty();
    else
        return true;
}

void WorkQueue::ProcessItems(unsigned threadIndex)
{
    bool wasActive = false;

    for (;;)
    {
        if (shutDown_)
            return;

        if (queue_.Empty())
            Time::Sleep(0);

        queueMutex_.Acquire();
        if (!queue_.Empty())
        {
            if (!wasActive)
            {
                ++numActive_;
                wasActive = true;
            }
            WorkItem item = queue_.Front();
            queue_.PopFront();
            queueMutex_.Release();
            item.workFunction_(&item, threadIndex);
        }
        else
        {
            if (wasActive)
            {
                --numActive_;
                wasActive = false;
            }
            queueMutex_.Release();
        }
    }
}
<|endoftext|>


<commit_before>#include "ConnectionList.hpp"

void AbstractConnection::disconnect()
{
	ThreadDataLocker lock1(outerLock_);
	ThreadDataLocker lock2(innerLock_);
	doDisconnect();
}

bool AbstractConnection::tryDisconnectWithLock(ThreadDataRef const & lock)
{
	if(lock != outerLock_) return false;
	ThreadDataLocker lock2(innerLock_);
	doDisconnect();
	return true;
}

void AbstractConnection::doDisconnect()
{
	if(!sourceList_ && !targetList_) return;
	assert(sourceList_ && targetList_);

	{
		ConnectionsVector & connections = sourceList_->data_.mutableRef();
		AbstractConnection * & xs = connections[sourceIndex_];
		assert(xs == this);
		xs = connections.back();
		xs->sourceIndex_ = sourceIndex_;
		connections.pop_back();
		sourceIndex_ = npos; sourceList_ = 0;
		release();
	}
	{
		ConnectionsVector & connections = targetList_->data_.mutableRef();
		AbstractConnection * & xt = connections[targetIndex_];
		assert(xt == this);
		xt = connections.back();
		xt->targetIndex_ = targetIndex_;
		connections.pop_back();
		targetIndex_ = npos; targetList_ = 0;
		release();
	}
}

ConnectionList::ConnectionList()
	: lock_(ThreadDataRef::current())
	, data_()
{
}

ConnectionList::~ConnectionList()
{
	assert(!data_.isBorrowed());
	disconnectAll();
}

void ConnectionList::connect(ConnectionList * peer, AbstractConnection * conn)
{
	conn->outerLock_ = this->lock_;
	conn->innerLock_ = peer->lock_;
	conn->outerLock_.makeBefore(conn->innerLock_);

	ThreadDataLocker lock1(conn->outerLock_);
	ThreadDataLocker lock2(conn->innerLock_);

	{
		assert(!conn->sourceList_ && conn->sourceIndex_ == AbstractConnection::npos);
		ConnectionsVector & connections = data_.mutableRef();
		conn->sourceList_ = this;
		conn->sourceIndex_ = connections.size();
		connections.push_back(conn);
		conn->retain();
	}
	{
		assert(!conn->targetList_ && conn->targetIndex_ == AbstractConnection::npos);
		ConnectionsVector & connections = data_.mutableRef();
		conn->targetList_ = peer;
		conn->targetIndex_ = connections.size();
		connections.push_back(conn);
		conn->retain();
	}
}

#define mutable_iterate(it, container) \
	ConnectionsVector::iterator it = (container).begin(); it != (container).end(); ++it

#define const_iterate(it, container) \
	ConnectionsVector::const_iterator it = (container).begin(); it != (container).end(); ++it

class ConnectionList::NullComparer
{
public:
	bool operator()(AbstractConnection const * conn) const { (void)conn; return true; }
};

class ConnectionList::DelegateComparer
{
public:
	DelegateComparer(AbstractDelegate const & deleg) : deleg_(deleg) {}
	bool operator()(AbstractConnection const * conn) const { return conn->recieverDelegate() == deleg_; }
private:
	AbstractDelegate const & deleg_;
};

class ConnectionList::PeerComparer
{
public:
	PeerComparer(ConnectionList * peer) : peer_(peer) {}
	bool operator()(AbstractConnection const * conn) const { return conn->hasPeer(peer_); }
private:
	ConnectionList * const peer_;
};

class ConnectionList::FullComparer
{
public:
	FullComparer(ConnectionList * peer, AbstractDelegate const & deleg) : e_(peer), d_(deleg) {}
	bool operator()(AbstractConnection const * conn) const { return e_(conn) && d_(conn); }
private:
	PeerComparer e_;
	DelegateComparer d_;
};

size_t ConnectionList::connectionCount() const
{
	ThreadDataLocker lock(lock_);
	return data_.constRef().size();
}

template<class Comparer> inline size_t ConnectionList::getConnectionCount(Comparer const & comp) const
{
	ThreadDataLocker lock(lock_);
	ConnectionsVector const & connections = data_.constRef();
	size_t retVal = 0;
	for(const_iterate(it, connections))
	{
		AbstractConnection const * conn = *it;
		if(comp(conn)) ++retVal;
	}
	return retVal;
}

size_t ConnectionList::connectionCount(AbstractDelegate const & deleg) const
{
	DelegateComparer comp(deleg);
	return getConnectionCount(comp);
}

size_t ConnectionList::connectionCount(ConnectionList * peer) const
{
	PeerComparer comp(peer);
	return getConnectionCount(comp);
}

size_t ConnectionList::connectionCount(ConnectionList * peer, AbstractDelegate const & deleg) const
{
	FullComparer comp(peer, deleg);
	return getConnectionCount(comp);
}

bool ConnectionList::hasConnections() const
{
	ThreadDataLocker lock(lock_);
	return !data_.constRef().empty();
}

template<class Comparer> inline bool ConnectionList::getHasConnections(Comparer const & comp) const
{
	ThreadDataLocker lock(lock_);
	ConnectionsVector const & connections = data_.constRef();
	for(const_iterate(it, connections))
	{
		AbstractConnection const * conn = *it;
		if(comp(conn)) return true;
	}
	return false;
}

bool ConnectionList::hasConnections(AbstractDelegate const & deleg) const
{
	DelegateComparer comp(deleg);
	return getHasConnections(comp);
}

bool ConnectionList::hasConnections(ConnectionList * peer) const
{
	PeerComparer comp(peer);
	return getHasConnections(comp);
}

bool ConnectionList::hasConnections(ConnectionList * peer, AbstractDelegate const & deleg) const
{
	FullComparer comp(peer, deleg);
	return getHasConnections(comp);
}

template<class Comparer> inline size_t ConnectionList::doDisconnectAll(Comparer const & comp)
{
	ConnectionsVector needRelock;
	size_t retVal = 0;
	{
		ThreadDataLocker lock(lock_);
		ConnectionsVector & connections = data_.mutableRef();
		for(size_t i = 0; i < connections.size(); )
		{
			AbstractConnection * conn = connections.at(i);
			if(!comp(conn))
			{
				++i;
				continue;
			}
			++retVal;
			bool done = conn->tryDisconnectWithLock(lock_);
			if(!done)
			{
				conn->retain();
				needRelock.push_back(conn);
				++i;
			}
		}
	}
	for(const_iterate(it, needRelock))
	{
		AbstractConnection * conn = *it;
		conn->disconnect();
		conn->release();
	}
	return retVal;
}

size_t ConnectionList::disconnectAll()
{
	NullComparer comp;
	return doDisconnectAll(comp);
}

size_t ConnectionList::disconnectAll(AbstractDelegate const & deleg)
{
	DelegateComparer comp(deleg);
	return doDisconnectAll(comp);
}

size_t ConnectionList::disconnectAll(ConnectionList * peer, AbstractDelegate const & deleg)
{
	FullComparer comp(peer, deleg);
	return doDisconnectAll(comp);
}

size_t ConnectionList::disconnectAll(ConnectionList * peer)
{
	PeerComparer comp(peer);
	return doDisconnectAll(comp);
}

template<class Comparer> inline bool ConnectionList::doDisconnectOne(Comparer const & comp)
{
	AbstractConnection * needRelock = 0;
	{
		ThreadDataLocker lock(lock_);
		ConnectionsVector & connections = data_.mutableRef();
		for(size_t i = 0; i < connections.size(); )
		{
			AbstractConnection * conn = connections.at(i);
			if(!comp(conn))
			{
				++i;
				continue;
			}
			bool done = conn->tryDisconnectWithLock(lock_);
			if(done) return true;
			needRelock = conn;
			conn->retain();
			break;
		}
	}

	if(!needRelock) return false;

	needRelock->disconnect();
	needRelock->release();
	return true;
}

bool ConnectionList::disconnectOne(AbstractDelegate const & deleg)
{
	DelegateComparer comp(deleg);
	return doDisconnectOne(comp);
}

bool ConnectionList::disconnectOne(ConnectionList * peer)
{
	PeerComparer comp(peer);
	return doDisconnectOne(comp);
}

bool ConnectionList::disconnectOne(ConnectionList * peer, AbstractDelegate const & deleg)
{
	FullComparer comp(peer, deleg);
	return doDisconnectOne(comp);
}
<commit_msg>-: Fixed: bug in ConnectionList::connect()<commit_after>#include "ConnectionList.hpp"

void AbstractConnection::disconnect()
{
	ThreadDataLocker lock1(outerLock_);
	ThreadDataLocker lock2(innerLock_);
	doDisconnect();
}

bool AbstractConnection::tryDisconnectWithLock(ThreadDataRef const & lock)
{
	if(lock != outerLock_) return false;
	ThreadDataLocker lock2(innerLock_);
	doDisconnect();
	return true;
}

void AbstractConnection::doDisconnect()
{
	if(!sourceList_ && !targetList_) return;
	assert(sourceList_ && targetList_);

	{
		ConnectionsVector & connections = sourceList_->data_.mutableRef();
		AbstractConnection * & xs = connections[sourceIndex_];
		assert(xs == this);
		xs = connections.back();
		xs->sourceIndex_ = sourceIndex_;
		connections.pop_back();
		sourceIndex_ = npos; sourceList_ = 0;
		release();
	}
	{
		ConnectionsVector & connections = targetList_->data_.mutableRef();
		AbstractConnection * & xt = connections[targetIndex_];
		assert(xt == this);
		xt = connections.back();
		xt->targetIndex_ = targetIndex_;
		connections.pop_back();
		targetIndex_ = npos; targetList_ = 0;
		release();
	}
}

ConnectionList::ConnectionList()
	: lock_(ThreadDataRef::current())
	, data_()
{
}

ConnectionList::~ConnectionList()
{
	assert(!data_.isBorrowed());
	disconnectAll();
}

void ConnectionList::connect(ConnectionList * peer, AbstractConnection * conn)
{
	conn->outerLock_ = this->lock_;
	conn->innerLock_ = peer->lock_;
	conn->outerLock_.makeBefore(conn->innerLock_);

	ThreadDataLocker lock1(conn->outerLock_);
	ThreadDataLocker lock2(conn->innerLock_);

	{
		assert(!conn->sourceList_ && conn->sourceIndex_ == AbstractConnection::npos);
		ConnectionsVector & connections = data_.mutableRef();
		conn->sourceList_ = this;
		conn->sourceIndex_ = connections.size();
		connections.push_back(conn);
		conn->retain();
	}
	{
		assert(!conn->targetList_ && conn->targetIndex_ == AbstractConnection::npos);
		ConnectionsVector & connections = peer->data_.mutableRef();
		conn->targetList_ = peer;
		conn->targetIndex_ = connections.size();
		connections.push_back(conn);
		conn->retain();
	}
}

#define mutable_iterate(it, container) \
	ConnectionsVector::iterator it = (container).begin(); it != (container).end(); ++it

#define const_iterate(it, container) \
	ConnectionsVector::const_iterator it = (container).begin(); it != (container).end(); ++it

class ConnectionList::NullComparer
{
public:
	bool operator()(AbstractConnection const * conn) const { (void)conn; return true; }
};

class ConnectionList::DelegateComparer
{
public:
	DelegateComparer(AbstractDelegate const & deleg) : deleg_(deleg) {}
	bool operator()(AbstractConnection const * conn) const { return conn->recieverDelegate() == deleg_; }
private:
	AbstractDelegate const & deleg_;
};

class ConnectionList::PeerComparer
{
public:
	PeerComparer(ConnectionList * peer) : peer_(peer) {}
	bool operator()(AbstractConnection const * conn) const { return conn->hasPeer(peer_); }
private:
	ConnectionList * const peer_;
};

class ConnectionList::FullComparer
{
public:
	FullComparer(ConnectionList * peer, AbstractDelegate const & deleg) : e_(peer), d_(deleg) {}
	bool operator()(AbstractConnection const * conn) const { return e_(conn) && d_(conn); }
private:
	PeerComparer e_;
	DelegateComparer d_;
};

size_t ConnectionList::connectionCount() const
{
	ThreadDataLocker lock(lock_);
	return data_.constRef().size();
}

template<class Comparer> inline size_t ConnectionList::getConnectionCount(Comparer const & comp) const
{
	ThreadDataLocker lock(lock_);
	ConnectionsVector const & connections = data_.constRef();
	size_t retVal = 0;
	for(const_iterate(it, connections))
	{
		AbstractConnection const * conn = *it;
		if(comp(conn)) ++retVal;
	}
	return retVal;
}

size_t ConnectionList::connectionCount(AbstractDelegate const & deleg) const
{
	DelegateComparer comp(deleg);
	return getConnectionCount(comp);
}

size_t ConnectionList::connectionCount(ConnectionList * peer) const
{
	PeerComparer comp(peer);
	return getConnectionCount(comp);
}

size_t ConnectionList::connectionCount(ConnectionList * peer, AbstractDelegate const & deleg) const
{
	FullComparer comp(peer, deleg);
	return getConnectionCount(comp);
}

bool ConnectionList::hasConnections() const
{
	ThreadDataLocker lock(lock_);
	return !data_.constRef().empty();
}

template<class Comparer> inline bool ConnectionList::getHasConnections(Comparer const & comp) const
{
	ThreadDataLocker lock(lock_);
	ConnectionsVector const & connections = data_.constRef();
	for(const_iterate(it, connections))
	{
		AbstractConnection const * conn = *it;
		if(comp(conn)) return true;
	}
	return false;
}

bool ConnectionList::hasConnections(AbstractDelegate const & deleg) const
{
	DelegateComparer comp(deleg);
	return getHasConnections(comp);
}

bool ConnectionList::hasConnections(ConnectionList * peer) const
{
	PeerComparer comp(peer);
	return getHasConnections(comp);
}

bool ConnectionList::hasConnections(ConnectionList * peer, AbstractDelegate const & deleg) const
{
	FullComparer comp(peer, deleg);
	return getHasConnections(comp);
}

template<class Comparer> inline size_t ConnectionList::doDisconnectAll(Comparer const & comp)
{
	ConnectionsVector needRelock;
	size_t retVal = 0;
	{
		ThreadDataLocker lock(lock_);
		ConnectionsVector & connections = data_.mutableRef();
		for(size_t i = 0; i < connections.size(); )
		{
			AbstractConnection * conn = connections.at(i);
			if(!comp(conn))
			{
				++i;
				continue;
			}
			++retVal;
			bool done = conn->tryDisconnectWithLock(lock_);
			if(!done)
			{
				conn->retain();
				needRelock.push_back(conn);
				++i;
			}
		}
	}
	for(const_iterate(it, needRelock))
	{
		AbstractConnection * conn = *it;
		conn->disconnect();
		conn->release();
	}
	return retVal;
}

size_t ConnectionList::disconnectAll()
{
	NullComparer comp;
	return doDisconnectAll(comp);
}

size_t ConnectionList::disconnectAll(AbstractDelegate const & deleg)
{
	DelegateComparer comp(deleg);
	return doDisconnectAll(comp);
}

size_t ConnectionList::disconnectAll(ConnectionList * peer, AbstractDelegate const & deleg)
{
	FullComparer comp(peer, deleg);
	return doDisconnectAll(comp);
}

size_t ConnectionList::disconnectAll(ConnectionList * peer)
{
	PeerComparer comp(peer);
	return doDisconnectAll(comp);
}

template<class Comparer> inline bool ConnectionList::doDisconnectOne(Comparer const & comp)
{
	AbstractConnection * needRelock = 0;
	{
		ThreadDataLocker lock(lock_);
		ConnectionsVector & connections = data_.mutableRef();
		for(size_t i = 0; i < connections.size(); )
		{
			AbstractConnection * conn = connections.at(i);
			if(!comp(conn))
			{
				++i;
				continue;
			}
			bool done = conn->tryDisconnectWithLock(lock_);
			if(done) return true;
			needRelock = conn;
			conn->retain();
			break;
		}
	}

	if(!needRelock) return false;

	needRelock->disconnect();
	needRelock->release();
	return true;
}

bool ConnectionList::disconnectOne(AbstractDelegate const & deleg)
{
	DelegateComparer comp(deleg);
	return doDisconnectOne(comp);
}

bool ConnectionList::disconnectOne(ConnectionList * peer)
{
	PeerComparer comp(peer);
	return doDisconnectOne(comp);
}

bool ConnectionList::disconnectOne(ConnectionList * peer, AbstractDelegate const & deleg)
{
	FullComparer comp(peer, deleg);
	return doDisconnectOne(comp);
}
<|endoftext|>


<commit_before>#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <freertos/semphr.h>
#include <nvs_flash.h>
#include <esp_task_wdt.h>
#include <driver/periph_ctrl.h>
#include <soc/timer_group_struct.h>

#include "Motors_Controller.h"
#include "IMU_Detector.h"
#include "Mahony_Filter.h"
#include "Complementary_Filter.h"
#include "WiFi_Controller.h"
#include "Logger.h"

using namespace flyhero;

Motors_Controller & motors_controller = Motors_Controller::Instance();

void wifi_task(void * args);

void imu_task(void * args);

void gpio_isr_task(void * args)
{
    ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3));

    vTaskDelete(NULL);
}

void TCP_process(const char * command);

extern "C" void app_main(void)
{
    // Initialize NVS
    esp_err_t nvs_status = nvs_flash_init();

    if (nvs_status == ESP_ERR_NVS_NO_FREE_PAGES)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }

    xTaskCreatePinnedToCore(gpio_isr_task, "GPIO ISR register task", 2048, NULL, 2, NULL, 1);
    vTaskDelay(1000 / portTICK_PERIOD_MS);

    LEDs::Init();
    motors_controller.Init();

    Logger::Instance().Init();
    IMU & imu = IMU_Detector::Detect_IMU();
    imu.Init();

    xTaskCreatePinnedToCore(wifi_task, "WiFi task", 4096, NULL, 2, NULL, 0);
}

void imu_task(void * args)
{
    IMU::Sensor_Data accel, gyro;
    IMU::Euler_Angles complementary_euler;
    IMU::Read_Data_Type data_type;

    IMU & imu = IMU_Detector::Detect_IMU();
    Logger & logger = Logger::Instance();
    Complementary_Filter complementary(0.97f);

    periph_module_enable(PERIPH_TIMG1_MODULE);  // enable TIMG1 watchdog clock
    TIMERG1.wdt_wprotect = 0x50d83aa1;          // disable write protection
    TIMERG1.wdt_config0.sys_reset_length = 7;
    TIMERG1.wdt_config0.cpu_reset_length = 7;
    TIMERG1.wdt_config0.level_int_en = 0;       // disable level interrupt
    TIMERG1.wdt_config0.edge_int_en = 0;        // disable edge interrupt
    TIMERG1.wdt_config0.stg0 = 3;               // reset chip when reaching stage 0 limit
    TIMERG1.wdt_config0.stg1 = 0;               //
    TIMERG1.wdt_config0.stg2 = 0;               // disable other stages
    TIMERG1.wdt_config0.stg3 = 0;               //
    TIMERG1.wdt_config1.clk_prescale = 80;      // tick every 1 us
    TIMERG1.wdt_config2 = 1100;                 // wait 1100 ticks (1100 microseconds) before resetting chip
    TIMERG1.wdt_config0.en = 1;
    TIMERG1.wdt_feed = 1;
    TIMERG1.wdt_wprotect = 0;                   // enable write protection

    while (true)
    {
        if (imu.Data_Ready())
        {
            TIMERG1.wdt_wprotect = 0x50d83aa1;
            TIMERG1.wdt_feed = 1;
            TIMERG1.wdt_wprotect = 0;

            data_type = imu.Read_Data(accel, gyro);

            complementary.Compute(accel, gyro, complementary_euler);

            if (data_type == IMU::Read_Data_Type::ACCEL_GYRO)
            {
                logger.Log_Next(&accel, sizeof(accel));
                logger.Log_Next(&gyro, sizeof(gyro));

                motors_controller.Feed_Stab_PIDs(complementary_euler);
                motors_controller.Feed_Rate_PIDs(gyro);
            } else
                motors_controller.Feed_Rate_PIDs(gyro);
        }
    }
}

void wifi_task(void * args)
{
    WiFi_Controller & wifi = WiFi_Controller::Instance();
    WiFi_Controller::In_Datagram_Data in_datagram_data;

    const char * received_data;
    size_t received_length;
    bool process_tcp, process_udp;

    wifi.Init();

    ESP_ERROR_CHECK(wifi.UDP_Server_Start());
    ESP_ERROR_CHECK(wifi.TCP_Server_Start());
    ESP_ERROR_CHECK(wifi.TCP_Wait_For_Client());

    while (true)
    {
        // TCP phase

        process_tcp = true;

        while (process_tcp)
        {
            if (wifi.TCP_Receive(received_data, received_length))
            {
                if (strncmp(received_data, "start", strlen("start")) == 0)
                {
                    IMU_Detector::Detect_IMU().Gyro_Calibrate();
                    if (IMU_Detector::Detect_IMU().Start())
                    {
                        motors_controller.Start();
                        wifi.TCP_Send("yup", 3);
                        process_tcp = false;
                    } else
                        wifi.TCP_Send("nah", 3);
                } else
                    TCP_process(received_data);
            }
        }

        TaskHandle_t imu_task_handle;
        assert(xTaskCreatePinnedToCore(imu_task, "IMU task", 4096, NULL, 20, &imu_task_handle, 1) == pdTRUE);

        periph_module_enable(PERIPH_TIMG0_MODULE);  // enable TIMG0 watchdog clock
        TIMERG0.wdt_wprotect = 0x50d83aa1;          // disable write protection
        TIMERG0.wdt_config0.sys_reset_length = 7;
        TIMERG0.wdt_config0.cpu_reset_length = 7;
        TIMERG0.wdt_config0.level_int_en = 0;       // disable level interrupt
        TIMERG0.wdt_config0.edge_int_en = 0;        // disable edge interrupt
        TIMERG0.wdt_config0.stg0 = 3;               // reset chip when reaching stage 0 limit
        TIMERG0.wdt_config0.stg1 = 0;               //
        TIMERG0.wdt_config0.stg2 = 0;               // disable other stages
        TIMERG0.wdt_config0.stg3 = 0;               //
        TIMERG0.wdt_config1.clk_prescale = 40000;   // tick every 500 us
        TIMERG0.wdt_config2 = 2000;                 // wait 2000 ticks (1 second) before resetting chip
        TIMERG0.wdt_config0.en = 1;
        TIMERG0.wdt_feed = 1;
        TIMERG0.wdt_wprotect = 0;                   // enable write protection

        // UDP phase

        process_udp = true;

        while (process_udp)
        {
            if (wifi.UDP_Receive(in_datagram_data))
            {
                TIMERG0.wdt_wprotect = 0x50d83aa1;
                TIMERG0.wdt_feed = 1;
                TIMERG0.wdt_wprotect = 0;

                float rate_parameters[3][3] = {
                        { in_datagram_data.rate_roll_kp * 0.01f,  0, 0 },
                        { in_datagram_data.rate_pitch_kp * 0.01f, 0, 0 },
                        { in_datagram_data.rate_yaw_kp * 0.01f,   0, 0 }
                };

                float stab_parameters[3][3] = {
                        { in_datagram_data.stab_roll_kp * 0.01f,  in_datagram_data.stab_roll_ki * 0.01f,  0 },
                        { in_datagram_data.stab_pitch_kp * 0.01f, in_datagram_data.stab_pitch_ki * 0.01f, 0 },
                        { 0,                                      0,                                      0 }
                };

                motors_controller.Set_Throttle(in_datagram_data.throttle);
                motors_controller.Set_PID_Constants(Motors_Controller::RATE, rate_parameters);
                motors_controller.Set_PID_Constants(Motors_Controller::STABILIZE, stab_parameters);
            }
            if (wifi.TCP_Receive(received_data, received_length))
            {
                if (strncmp(received_data, "stop", strlen("stop")) == 0)
                {
                    motors_controller.Stop();

                    // motors disabled, safe to disable both watchdogs
                    TIMERG0.wdt_wprotect = 0x50d83aa1;
                    TIMERG0.wdt_config0.en = 0;
                    TIMERG0.wdt_wprotect = 0;

                    TIMERG1.wdt_wprotect = 0x50d83aa1;
                    TIMERG1.wdt_config0.en = 0;
                    TIMERG1.wdt_wprotect = 0;

                    vTaskDelete(imu_task_handle);
                    IMU_Detector::Detect_IMU().Stop();
                    process_udp = false;

                    wifi.TCP_Send("yup", 3);
                } else
                    wifi.TCP_Send("nah", 3);
            }
        }
    }
}

void TCP_process(const char * command)
{
    WiFi_Controller & wifi = WiFi_Controller::Instance();

    if (strncmp(command, "calibrate", strlen("calibrate")) == 0)
    {
        IMU_Detector::Detect_IMU().Accel_Calibrate();
        wifi.TCP_Send("yup", 3);
    } else if (strncmp(command, "log", strlen("log")) == 0)
    {
        Logger::Instance().Erase();
        Logger::Instance().Enable_Writes();
        wifi.TCP_Send("yup", 3);
    } else if (strncmp(command, "download", strlen("download")) == 0)
    {
        char buffer[1024];

        Logger & logger = Logger::Instance();

        logger.Reset_Read_Pointer();
        if (!logger.Read_Next(buffer, 1024))
        {
            wifi.TCP_Send("nah", 3);
            return;
        }

        bool empty = true;

        for (uint8_t i = 0; i < 100; i++)
        {
            if (buffer[i] != 0xFF)
            {
                empty = false;
                break;
            }
        }

        if (empty)
        {
            wifi.TCP_Send("nah", 3);
            return;
        }

        wifi.TCP_Send("yup", 3);

        do
        {
            wifi.TCP_Send(buffer, 1024);
            if (!logger.Read_Next(buffer, 1024))
                break;

            empty = true;

            for (uint8_t i = 0; i < 100; i++)
            {
                if (buffer[i] != 0xFF)
                {
                    empty = false;
                    break;
                }
            }

        } while (!empty);
    } else
        wifi.TCP_Send("nah", 3);
}<commit_msg>Add some vTaskDelay calls to wifi task<commit_after>#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <freertos/semphr.h>
#include <nvs_flash.h>
#include <esp_task_wdt.h>
#include <driver/periph_ctrl.h>
#include <soc/timer_group_struct.h>

#include "Motors_Controller.h"
#include "IMU_Detector.h"
#include "Mahony_Filter.h"
#include "Complementary_Filter.h"
#include "WiFi_Controller.h"
#include "Logger.h"

using namespace flyhero;

Motors_Controller & motors_controller = Motors_Controller::Instance();

void wifi_task(void * args);

void imu_task(void * args);

void gpio_isr_task(void * args)
{
    ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3));

    vTaskDelete(NULL);
}

void TCP_process(const char * command);

extern "C" void app_main(void)
{
    // Initialize NVS
    esp_err_t nvs_status = nvs_flash_init();

    if (nvs_status == ESP_ERR_NVS_NO_FREE_PAGES)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }

    xTaskCreatePinnedToCore(gpio_isr_task, "GPIO ISR register task", 2048, NULL, 2, NULL, 1);
    vTaskDelay(1000 / portTICK_PERIOD_MS);

    LEDs::Init();
    motors_controller.Init();

    Logger::Instance().Init();
    IMU & imu = IMU_Detector::Detect_IMU();
    imu.Init();

    xTaskCreatePinnedToCore(wifi_task, "WiFi task", 4096, NULL, 2, NULL, 0);
}

void imu_task(void * args)
{
    IMU::Sensor_Data accel, gyro;
    IMU::Euler_Angles complementary_euler;
    IMU::Read_Data_Type data_type;

    IMU & imu = IMU_Detector::Detect_IMU();
    Logger & logger = Logger::Instance();
    Complementary_Filter complementary(0.97f);

    periph_module_enable(PERIPH_TIMG1_MODULE);  // enable TIMG1 watchdog clock
    TIMERG1.wdt_wprotect = 0x50d83aa1;          // disable write protection
    TIMERG1.wdt_config0.sys_reset_length = 7;
    TIMERG1.wdt_config0.cpu_reset_length = 7;
    TIMERG1.wdt_config0.level_int_en = 0;       // disable level interrupt
    TIMERG1.wdt_config0.edge_int_en = 0;        // disable edge interrupt
    TIMERG1.wdt_config0.stg0 = 3;               // reset chip when reaching stage 0 limit
    TIMERG1.wdt_config0.stg1 = 0;               //
    TIMERG1.wdt_config0.stg2 = 0;               // disable other stages
    TIMERG1.wdt_config0.stg3 = 0;               //
    TIMERG1.wdt_config1.clk_prescale = 80;      // tick every 1 us
    TIMERG1.wdt_config2 = 1100;                 // wait 1100 ticks (1100 microseconds) before resetting chip
    TIMERG1.wdt_config0.en = 1;
    TIMERG1.wdt_feed = 1;
    TIMERG1.wdt_wprotect = 0;                   // enable write protection

    while (true)
    {
        if (imu.Data_Ready())
        {
            TIMERG1.wdt_wprotect = 0x50d83aa1;
            TIMERG1.wdt_feed = 1;
            TIMERG1.wdt_wprotect = 0;

            data_type = imu.Read_Data(accel, gyro);

            complementary.Compute(accel, gyro, complementary_euler);

            if (data_type == IMU::Read_Data_Type::ACCEL_GYRO)
            {
                logger.Log_Next(&accel, sizeof(accel));
                logger.Log_Next(&gyro, sizeof(gyro));

                motors_controller.Feed_Stab_PIDs(complementary_euler);
                motors_controller.Feed_Rate_PIDs(gyro);
            } else
                motors_controller.Feed_Rate_PIDs(gyro);
        }
    }
}

void wifi_task(void * args)
{
    WiFi_Controller & wifi = WiFi_Controller::Instance();
    WiFi_Controller::In_Datagram_Data in_datagram_data;

    const char * received_data;
    size_t received_length;
    bool process_tcp, process_udp;

    wifi.Init();

    ESP_ERROR_CHECK(wifi.UDP_Server_Start());
    ESP_ERROR_CHECK(wifi.TCP_Server_Start());
    ESP_ERROR_CHECK(wifi.TCP_Wait_For_Client());

    while (true)
    {
        // TCP phase

        process_tcp = true;

        while (process_tcp)
        {
            if (wifi.TCP_Receive(received_data, received_length))
            {
                if (strncmp(received_data, "start", strlen("start")) == 0)
                {
                    IMU_Detector::Detect_IMU().Gyro_Calibrate();
                    if (IMU_Detector::Detect_IMU().Start())
                    {
                        motors_controller.Start();
                        wifi.TCP_Send("yup", 3);
                        process_tcp = false;
                    } else
                        wifi.TCP_Send("nah", 3);
                } else
                    TCP_process(received_data);
            }
            vTaskDelay(20);
        }

        TaskHandle_t imu_task_handle;
        assert(xTaskCreatePinnedToCore(imu_task, "IMU task", 4096, NULL, 20, &imu_task_handle, 1) == pdTRUE);

        periph_module_enable(PERIPH_TIMG0_MODULE);  // enable TIMG0 watchdog clock
        TIMERG0.wdt_wprotect = 0x50d83aa1;          // disable write protection
        TIMERG0.wdt_config0.sys_reset_length = 7;
        TIMERG0.wdt_config0.cpu_reset_length = 7;
        TIMERG0.wdt_config0.level_int_en = 0;       // disable level interrupt
        TIMERG0.wdt_config0.edge_int_en = 0;        // disable edge interrupt
        TIMERG0.wdt_config0.stg0 = 3;               // reset chip when reaching stage 0 limit
        TIMERG0.wdt_config0.stg1 = 0;               //
        TIMERG0.wdt_config0.stg2 = 0;               // disable other stages
        TIMERG0.wdt_config0.stg3 = 0;               //
        TIMERG0.wdt_config1.clk_prescale = 40000;   // tick every 500 us
        TIMERG0.wdt_config2 = 2000;                 // wait 2000 ticks (1 second) before resetting chip
        TIMERG0.wdt_config0.en = 1;
        TIMERG0.wdt_feed = 1;
        TIMERG0.wdt_wprotect = 0;                   // enable write protection

        // UDP phase

        process_udp = true;

        while (process_udp)
        {
            if (wifi.UDP_Receive(in_datagram_data))
            {
                TIMERG0.wdt_wprotect = 0x50d83aa1;
                TIMERG0.wdt_feed = 1;
                TIMERG0.wdt_wprotect = 0;

                float rate_parameters[3][3] = {
                        { in_datagram_data.rate_roll_kp * 0.01f,  0, 0 },
                        { in_datagram_data.rate_pitch_kp * 0.01f, 0, 0 },
                        { in_datagram_data.rate_yaw_kp * 0.01f,   0, 0 }
                };

                float stab_parameters[3][3] = {
                        { in_datagram_data.stab_roll_kp * 0.01f,  in_datagram_data.stab_roll_ki * 0.01f,  0 },
                        { in_datagram_data.stab_pitch_kp * 0.01f, in_datagram_data.stab_pitch_ki * 0.01f, 0 },
                        { 0,                                      0,                                      0 }
                };

                motors_controller.Set_Throttle(in_datagram_data.throttle);
                motors_controller.Set_PID_Constants(Motors_Controller::RATE, rate_parameters);
                motors_controller.Set_PID_Constants(Motors_Controller::STABILIZE, stab_parameters);
            }
            if (wifi.TCP_Receive(received_data, received_length))
            {
                if (strncmp(received_data, "stop", strlen("stop")) == 0)
                {
                    motors_controller.Stop();

                    // motors disabled, safe to disable both watchdogs
                    TIMERG0.wdt_wprotect = 0x50d83aa1;
                    TIMERG0.wdt_config0.en = 0;
                    TIMERG0.wdt_wprotect = 0;

                    TIMERG1.wdt_wprotect = 0x50d83aa1;
                    TIMERG1.wdt_config0.en = 0;
                    TIMERG1.wdt_wprotect = 0;

                    vTaskDelete(imu_task_handle);
                    IMU_Detector::Detect_IMU().Stop();
                    process_udp = false;

                    wifi.TCP_Send("yup", 3);
                } else
                    wifi.TCP_Send("nah", 3);
            }
            vTaskDelay(20);
        }
    }
}

void TCP_process(const char * command)
{
    WiFi_Controller & wifi = WiFi_Controller::Instance();

    if (strncmp(command, "calibrate", strlen("calibrate")) == 0)
    {
        IMU_Detector::Detect_IMU().Accel_Calibrate();
        wifi.TCP_Send("yup", 3);
    } else if (strncmp(command, "log", strlen("log")) == 0)
    {
        Logger::Instance().Erase();
        Logger::Instance().Enable_Writes();
        wifi.TCP_Send("yup", 3);
    } else if (strncmp(command, "download", strlen("download")) == 0)
    {
        char buffer[1024];

        Logger & logger = Logger::Instance();

        logger.Reset_Read_Pointer();
        if (!logger.Read_Next(buffer, 1024))
        {
            wifi.TCP_Send("nah", 3);
            return;
        }

        bool empty = true;

        for (uint8_t i = 0; i < 100; i++)
        {
            if (buffer[i] != 0xFF)
            {
                empty = false;
                break;
            }
        }

        if (empty)
        {
            wifi.TCP_Send("nah", 3);
            return;
        }

        wifi.TCP_Send("yup", 3);

        do
        {
            wifi.TCP_Send(buffer, 1024);
            if (!logger.Read_Next(buffer, 1024))
                break;

            empty = true;

            for (uint8_t i = 0; i < 100; i++)
            {
                if (buffer[i] != 0xFF)
                {
                    empty = false;
                    break;
                }
            }

        } while (!empty);
    } else
        wifi.TCP_Send("nah", 3);
}<|endoftext|>


<commit_before>/*
 OFX FrameRange plugin.

 Copyright (C) 2014 INRIA
 Author: Frederic Devernay <frederic.devernay@inria.fr>

 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice, this
 list of conditions and the following disclaimer in the documentation and/or
 other materials provided with the distribution.

 Neither the name of the {organization} nor the names of its
 contributors may be used to endorse or promote products derived from
 this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 INRIA
 Domaine de Voluceau
 Rocquencourt - B.P. 105
 78153 Le Chesnay Cedex - France

 */

#include "FrameRange.h"

#include <algorithm> // for std::max
#ifdef _WINDOWS
#include <windows.h>
#endif

#include "ofxsProcessing.H"
#include "ofxsMacros.h"
#include "ofxsCopier.h"

#ifdef OFX_EXTENSIONS_NUKE
#include "nuke/fnOfxExtensions.h"
#endif

#define kPluginName "FrameRangeOFX"
#define kPluginGrouping "Time"
#define kPluginDescription "Set the frame range for a clip. Useful in conjunction with AppendClipOFX."
#define kPluginIdentifier "net.sf.openfx.FrameRange"
#define kPluginVersionMajor 1 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
#define kPluginVersionMinor 0 // Increment this when you have fixed a bug or made it faster.

#define kSupportsTiles 1
#define kSupportsMultiResolution 1
#define kSupportsRenderScale 1
#define kSupportsMultipleClipPARs false
#define kSupportsMultipleClipDepths true
#define kRenderThreadSafety eRenderFullySafe

#define kParamFrameRange "frameRange"
#define kParamFrameRangeLabel "Frame Range"
#define kParamFrameRangeHint "Output frame range."

#define kParamReset "reset"
#define kParamResetLabel "Reset"
#define kParamResetHint "Resets the frame range to its initial value."

using namespace OFX;

////////////////////////////////////////////////////////////////////////////////
/** @brief The plugin that does our work */
class FrameRangePlugin : public OFX::ImageEffect
{
public:
    /** @brief ctor */
    FrameRangePlugin(OfxImageEffectHandle handle)
    : ImageEffect(handle)
    , _dstClip(0)
    , _srcClip(0)
    , _frameRange(0)
    {
        _dstClip = fetchClip(kOfxImageEffectOutputClipName);
        assert(_dstClip && (_dstClip->getPixelComponents() == ePixelComponentAlpha || _dstClip->getPixelComponents() == ePixelComponentRGB || _dstClip->getPixelComponents() == ePixelComponentRGBA));
        _srcClip = fetchClip(kOfxImageEffectSimpleSourceClipName);
        assert(_srcClip && (_srcClip->getPixelComponents() == ePixelComponentAlpha || _srcClip->getPixelComponents() == ePixelComponentRGB || _srcClip->getPixelComponents() == ePixelComponentRGBA));
        _frameRange = fetchInt2DParam(kParamFrameRange);
        assert(_frameRange);
    }

private:
    /* Override the render */
    virtual void render(const OFX::RenderArguments &args) OVERRIDE FINAL;

    virtual bool isIdentity(const IsIdentityArguments &args, Clip * &identityClip, double &identityTime) OVERRIDE FINAL;

#ifdef OFX_EXTENSIONS_NUKE
    /** @brief recover a transform matrix from an effect */
    virtual bool getTransform(const OFX::TransformArguments &args, OFX::Clip * &transformClip, double transformMatrix[9]);
#endif

    virtual void changedParam(const OFX::InstanceChangedArgs &args, const std::string &paramName) OVERRIDE FINAL;

      /* override the time domain action, only for the general context */
    virtual bool getTimeDomain(OfxRangeD &range) OVERRIDE FINAL;

private:
    // do not need to delete these, the ImageEffect is managing them for us
    OFX::Clip *_dstClip;
    OFX::Clip *_srcClip;

    OFX::Int2DParam *_frameRange;
};

////////////////////////////////////////////////////////////////////////////////
/** @brief render for the filter */

////////////////////////////////////////////////////////////////////////////////
// basic plugin render function, just a skelington to instantiate templates from

// the overridden render function
void
FrameRangePlugin::render(const OFX::RenderArguments &/*args*/)
{
    assert(false);
}

bool
FrameRangePlugin::isIdentity(const IsIdentityArguments &/*args*/, Clip * &identityClip, double &/*identityTime*/)
{
    identityClip = _srcClip;
    return true;
}

#ifdef OFX_EXTENSIONS_NUKE
// overridden getTransform
bool
FrameRangePlugin::getTransform(const OFX::TransformArguments &/*args*/, OFX::Clip * &transformClip, double transformMatrix[9])
{
    transformClip = _srcClip;
    transformMatrix[0] = 1.;
    transformMatrix[1] = 0.;
    transformMatrix[2] = 0.;
    transformMatrix[3] = 0.;
    transformMatrix[4] = 1.;
    transformMatrix[5] = 0.;
    transformMatrix[6] = 0.;
    transformMatrix[7] = 0.;
    transformMatrix[8] = 1.;

    return true;
}
#endif

void
FrameRangePlugin::changedParam(const OFX::InstanceChangedArgs &/*args*/, const std::string &paramName)
{
    if (paramName == kParamReset) {
        OfxRangeD range = _srcClip->getFrameRange();
        _frameRange->setValue((int)range.min, (int)range.max);
    }
}

/* override the time domain action, only for the general context */
bool
FrameRangePlugin::getTimeDomain(OfxRangeD &range)
{
    // this should only be called in the general context, ever!
    assert (getContext() == OFX::eContextGeneral);
    int min, max;
    _frameRange->getValue(min, max);
    range.min = min;
    range.max = std::max(min, max);
    return true;
}

using namespace OFX;

mDeclarePluginFactory(FrameRangePluginFactory, {}, {});

void FrameRangePluginFactory::describe(OFX::ImageEffectDescriptor &desc)
{
    // basic labels
    desc.setLabel(kPluginName);
    desc.setPluginGrouping(kPluginGrouping);
    desc.setPluginDescription(kPluginDescription);

    // add the supported contexts, only general, because the only useful action is getTimeDomain
    desc.addSupportedContext(eContextGeneral);

    // add supported pixel depths
    desc.addSupportedBitDepth(eBitDepthNone);
    desc.addSupportedBitDepth(eBitDepthUByte);
    desc.addSupportedBitDepth(eBitDepthUShort);
    desc.addSupportedBitDepth(eBitDepthHalf);
    desc.addSupportedBitDepth(eBitDepthFloat);
    desc.addSupportedBitDepth(eBitDepthCustom);
#ifdef OFX_EXTENSIONS_VEGAS
    desc.addSupportedBitDepth(eBitDepthUByteBGRA);
    desc.addSupportedBitDepth(eBitDepthUShortBGRA);
    desc.addSupportedBitDepth(eBitDepthFloatBGRA);
#endif

    // set a few flags
    desc.setSingleInstance(false);
    desc.setHostFrameThreading(false);
    desc.setSupportsMultiResolution(kSupportsMultiResolution);
    desc.setSupportsTiles(kSupportsTiles);
    desc.setTemporalClipAccess(false);
    desc.setRenderTwiceAlways(false);
    desc.setSupportsMultipleClipPARs(kSupportsMultipleClipPARs);
    desc.setSupportsMultipleClipDepths(kSupportsMultipleClipDepths);
    desc.setRenderThreadSafety(kRenderThreadSafety);
#ifdef OFX_EXTENSIONS_NUKE
    // Enable transform by the host.
    // It is only possible for transforms which can be represented as a 3x3 matrix.
    desc.setCanTransform(true);
#endif
}

void FrameRangePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum /*context*/)
{
    // Source clip only in the filter context
    // create the mandated source clip
    ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
    srcClip->addSupportedComponent(ePixelComponentNone);
    srcClip->addSupportedComponent(ePixelComponentRGBA);
    srcClip->addSupportedComponent(ePixelComponentRGB);
    srcClip->addSupportedComponent(ePixelComponentAlpha);
#ifdef OFX_EXTENSIONS_NUKE
    //srcClip->addSupportedComponent(ePixelComponentMotionVectors);
    //srcClip->addSupportedComponent(ePixelComponentStereoDisparity);
    srcClip->setCanTransform(true);
#endif
    srcClip->addSupportedComponent(ePixelComponentCustom);
    srcClip->setTemporalClipAccess(false);
    srcClip->setSupportsTiles(kSupportsTiles);
    srcClip->setIsMask(false);

    // create the mandated output clip
    ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
    dstClip->addSupportedComponent(ePixelComponentNone);
    dstClip->addSupportedComponent(ePixelComponentRGBA);
    dstClip->addSupportedComponent(ePixelComponentRGB);
    dstClip->addSupportedComponent(ePixelComponentAlpha);
#ifdef OFX_EXTENSIONS_NUKE
    //dstClip->addSupportedComponent(ePixelComponentMotionVectors); // crashes Nuke
    //dstClip->addSupportedComponent(ePixelComponentStereoDisparity);
#endif
    dstClip->addSupportedComponent(ePixelComponentCustom);
    dstClip->setSupportsTiles(kSupportsTiles);

    // make some pages and to things in
    PageParamDescriptor *page = desc.definePageParam("Controls");

    // frameRange
    {
        Int2DParamDescriptor *param = desc.defineInt2DParam(kParamFrameRange);
        param->setLabel(kParamFrameRangeLabel);
        param->setHint(kParamFrameRangeHint);
        param->setDefault(1,1);
        param->setAnimates(false);
        param->setLayoutHint(eLayoutHintNoNewLine);
        if (page) {
            page->addChild(*param);
        }
    }
    // reset
    {
        PushButtonParamDescriptor *param = desc.definePushButtonParam(kParamReset);
        param->setLabel(kParamResetLabel);
        param->setHint(kParamResetHint);
        if (page) {
            page->addChild(*param);
        }
    }
}

OFX::ImageEffect* FrameRangePluginFactory::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum /*context*/)
{
    return new FrameRangePlugin(handle);
}

void getFrameRangePluginID(OFX::PluginFactoryArray &ids)
{
    static FrameRangePluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
    ids.push_back(&p);
}
<commit_msg>FrameRange: set dimensionlabels<commit_after>/*
 OFX FrameRange plugin.

 Copyright (C) 2014 INRIA
 Author: Frederic Devernay <frederic.devernay@inria.fr>

 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice, this
 list of conditions and the following disclaimer in the documentation and/or
 other materials provided with the distribution.

 Neither the name of the {organization} nor the names of its
 contributors may be used to endorse or promote products derived from
 this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 INRIA
 Domaine de Voluceau
 Rocquencourt - B.P. 105
 78153 Le Chesnay Cedex - France

 */

#include "FrameRange.h"

#include <algorithm> // for std::max
#ifdef _WINDOWS
#include <windows.h>
#endif

#include "ofxsProcessing.H"
#include "ofxsMacros.h"
#include "ofxsCopier.h"

#ifdef OFX_EXTENSIONS_NUKE
#include "nuke/fnOfxExtensions.h"
#endif

#define kPluginName "FrameRangeOFX"
#define kPluginGrouping "Time"
#define kPluginDescription "Set the frame range for a clip. Useful in conjunction with AppendClipOFX."
#define kPluginIdentifier "net.sf.openfx.FrameRange"
#define kPluginVersionMajor 1 // Incrementing this number means that you have broken backwards compatibility of the plug-in.
#define kPluginVersionMinor 0 // Increment this when you have fixed a bug or made it faster.

#define kSupportsTiles 1
#define kSupportsMultiResolution 1
#define kSupportsRenderScale 1
#define kSupportsMultipleClipPARs false
#define kSupportsMultipleClipDepths true
#define kRenderThreadSafety eRenderFullySafe

#define kParamFrameRange "frameRange"
#define kParamFrameRangeLabel "Frame Range"
#define kParamFrameRangeHint "Output frame range."

#define kParamReset "reset"
#define kParamResetLabel "Reset"
#define kParamResetHint "Resets the frame range to its initial value."

using namespace OFX;

////////////////////////////////////////////////////////////////////////////////
/** @brief The plugin that does our work */
class FrameRangePlugin : public OFX::ImageEffect
{
public:
    /** @brief ctor */
    FrameRangePlugin(OfxImageEffectHandle handle)
    : ImageEffect(handle)
    , _dstClip(0)
    , _srcClip(0)
    , _frameRange(0)
    {
        _dstClip = fetchClip(kOfxImageEffectOutputClipName);
        assert(_dstClip && (_dstClip->getPixelComponents() == ePixelComponentAlpha || _dstClip->getPixelComponents() == ePixelComponentRGB || _dstClip->getPixelComponents() == ePixelComponentRGBA));
        _srcClip = fetchClip(kOfxImageEffectSimpleSourceClipName);
        assert(_srcClip && (_srcClip->getPixelComponents() == ePixelComponentAlpha || _srcClip->getPixelComponents() == ePixelComponentRGB || _srcClip->getPixelComponents() == ePixelComponentRGBA));
        _frameRange = fetchInt2DParam(kParamFrameRange);
        assert(_frameRange);
    }

private:
    /* Override the render */
    virtual void render(const OFX::RenderArguments &args) OVERRIDE FINAL;

    virtual bool isIdentity(const IsIdentityArguments &args, Clip * &identityClip, double &identityTime) OVERRIDE FINAL;

#ifdef OFX_EXTENSIONS_NUKE
    /** @brief recover a transform matrix from an effect */
    virtual bool getTransform(const OFX::TransformArguments &args, OFX::Clip * &transformClip, double transformMatrix[9]);
#endif

    virtual void changedParam(const OFX::InstanceChangedArgs &args, const std::string &paramName) OVERRIDE FINAL;

      /* override the time domain action, only for the general context */
    virtual bool getTimeDomain(OfxRangeD &range) OVERRIDE FINAL;

private:
    // do not need to delete these, the ImageEffect is managing them for us
    OFX::Clip *_dstClip;
    OFX::Clip *_srcClip;

    OFX::Int2DParam *_frameRange;
};

////////////////////////////////////////////////////////////////////////////////
/** @brief render for the filter */

////////////////////////////////////////////////////////////////////////////////
// basic plugin render function, just a skelington to instantiate templates from

// the overridden render function
void
FrameRangePlugin::render(const OFX::RenderArguments &/*args*/)
{
    assert(false);
}

bool
FrameRangePlugin::isIdentity(const IsIdentityArguments &/*args*/, Clip * &identityClip, double &/*identityTime*/)
{
    identityClip = _srcClip;
    return true;
}

#ifdef OFX_EXTENSIONS_NUKE
// overridden getTransform
bool
FrameRangePlugin::getTransform(const OFX::TransformArguments &/*args*/, OFX::Clip * &transformClip, double transformMatrix[9])
{
    transformClip = _srcClip;
    transformMatrix[0] = 1.;
    transformMatrix[1] = 0.;
    transformMatrix[2] = 0.;
    transformMatrix[3] = 0.;
    transformMatrix[4] = 1.;
    transformMatrix[5] = 0.;
    transformMatrix[6] = 0.;
    transformMatrix[7] = 0.;
    transformMatrix[8] = 1.;

    return true;
}
#endif

void
FrameRangePlugin::changedParam(const OFX::InstanceChangedArgs &/*args*/, const std::string &paramName)
{
    if (paramName == kParamReset) {
        OfxRangeD range = _srcClip->getFrameRange();
        _frameRange->setValue((int)range.min, (int)range.max);
    }
}

/* override the time domain action, only for the general context */
bool
FrameRangePlugin::getTimeDomain(OfxRangeD &range)
{
    // this should only be called in the general context, ever!
    assert (getContext() == OFX::eContextGeneral);
    int min, max;
    _frameRange->getValue(min, max);
    range.min = min;
    range.max = std::max(min, max);
    return true;
}

using namespace OFX;

mDeclarePluginFactory(FrameRangePluginFactory, {}, {});

void FrameRangePluginFactory::describe(OFX::ImageEffectDescriptor &desc)
{
    // basic labels
    desc.setLabel(kPluginName);
    desc.setPluginGrouping(kPluginGrouping);
    desc.setPluginDescription(kPluginDescription);

    // add the supported contexts, only general, because the only useful action is getTimeDomain
    desc.addSupportedContext(eContextGeneral);

    // add supported pixel depths
    desc.addSupportedBitDepth(eBitDepthNone);
    desc.addSupportedBitDepth(eBitDepthUByte);
    desc.addSupportedBitDepth(eBitDepthUShort);
    desc.addSupportedBitDepth(eBitDepthHalf);
    desc.addSupportedBitDepth(eBitDepthFloat);
    desc.addSupportedBitDepth(eBitDepthCustom);
#ifdef OFX_EXTENSIONS_VEGAS
    desc.addSupportedBitDepth(eBitDepthUByteBGRA);
    desc.addSupportedBitDepth(eBitDepthUShortBGRA);
    desc.addSupportedBitDepth(eBitDepthFloatBGRA);
#endif

    // set a few flags
    desc.setSingleInstance(false);
    desc.setHostFrameThreading(false);
    desc.setSupportsMultiResolution(kSupportsMultiResolution);
    desc.setSupportsTiles(kSupportsTiles);
    desc.setTemporalClipAccess(false);
    desc.setRenderTwiceAlways(false);
    desc.setSupportsMultipleClipPARs(kSupportsMultipleClipPARs);
    desc.setSupportsMultipleClipDepths(kSupportsMultipleClipDepths);
    desc.setRenderThreadSafety(kRenderThreadSafety);
#ifdef OFX_EXTENSIONS_NUKE
    // Enable transform by the host.
    // It is only possible for transforms which can be represented as a 3x3 matrix.
    desc.setCanTransform(true);
#endif
}

void FrameRangePluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, OFX::ContextEnum /*context*/)
{
    // Source clip only in the filter context
    // create the mandated source clip
    ClipDescriptor *srcClip = desc.defineClip(kOfxImageEffectSimpleSourceClipName);
    srcClip->addSupportedComponent(ePixelComponentNone);
    srcClip->addSupportedComponent(ePixelComponentRGBA);
    srcClip->addSupportedComponent(ePixelComponentRGB);
    srcClip->addSupportedComponent(ePixelComponentAlpha);
#ifdef OFX_EXTENSIONS_NUKE
    //srcClip->addSupportedComponent(ePixelComponentMotionVectors);
    //srcClip->addSupportedComponent(ePixelComponentStereoDisparity);
    srcClip->setCanTransform(true);
#endif
    srcClip->addSupportedComponent(ePixelComponentCustom);
    srcClip->setTemporalClipAccess(false);
    srcClip->setSupportsTiles(kSupportsTiles);
    srcClip->setIsMask(false);

    // create the mandated output clip
    ClipDescriptor *dstClip = desc.defineClip(kOfxImageEffectOutputClipName);
    dstClip->addSupportedComponent(ePixelComponentNone);
    dstClip->addSupportedComponent(ePixelComponentRGBA);
    dstClip->addSupportedComponent(ePixelComponentRGB);
    dstClip->addSupportedComponent(ePixelComponentAlpha);
#ifdef OFX_EXTENSIONS_NUKE
    //dstClip->addSupportedComponent(ePixelComponentMotionVectors); // crashes Nuke
    //dstClip->addSupportedComponent(ePixelComponentStereoDisparity);
#endif
    dstClip->addSupportedComponent(ePixelComponentCustom);
    dstClip->setSupportsTiles(kSupportsTiles);

    // make some pages and to things in
    PageParamDescriptor *page = desc.definePageParam("Controls");

    // frameRange
    {
        Int2DParamDescriptor *param = desc.defineInt2DParam(kParamFrameRange);
        param->setLabel(kParamFrameRangeLabel);
        param->setHint(kParamFrameRangeHint);
        param->setDefault(1,1);
        param->setAnimates(false);
        param->setDimensionLabels("first", "last");
        param->setLayoutHint(eLayoutHintNoNewLine);
        if (page) {
            page->addChild(*param);
        }
    }
    // reset
    {
        PushButtonParamDescriptor *param = desc.definePushButtonParam(kParamReset);
        param->setLabel(kParamResetLabel);
        param->setHint(kParamResetHint);
        if (page) {
            page->addChild(*param);
        }
    }
}

OFX::ImageEffect* FrameRangePluginFactory::createInstance(OfxImageEffectHandle handle, OFX::ContextEnum /*context*/)
{
    return new FrameRangePlugin(handle);
}

void getFrameRangePluginID(OFX::PluginFactoryArray &ids)
{
    static FrameRangePluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
    ids.push_back(&p);
}
<|endoftext|>