<commit_before>/*
* Copyright (c) 2003-2016 Rony Shapiro <ronys@pwsafe.org>.
* All rights reserved. Use of the code is allowed under the
* Artistic License 2.0 terms, as specified in the LICENSE file
* distributed with this code, or available from
* http://www.opensource.org/licenses/artistic-license-2.0.php
*/
// OptionsSystem.cpp : implementation file
//

#include "stdafx.h"
#include "passwordsafe.h"
#include "ThisMfcApp.h"    // For Help
#include "Options_PropertySheet.h"
#include "GeneralMsgBox.h"

#include "core/PwsPlatform.h"
#include "core/PWSprefs.h"

#include "resource.h"
#include "resource2.h"  // Menu, Toolbar & Accelerator resources
#include "resource3.h"  // String resources

#include "OptionsSystem.h" // Must be after resource.h

extern bool OfferConfigMigration();
extern bool PerformConfigMigration();

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COptionsSystem property page

bool COptionsSystem::m_bShowConfigFile = false;

IMPLEMENT_DYNAMIC(COptionsSystem, COptions_PropertyPage)

COptionsSystem::COptionsSystem(CWnd *pParent, st_Opt_master_data *pOPTMD)
: COptions_PropertyPage(pParent,
                        COptionsSystem::IDD, COptionsSystem::IDD_SHORT,
                        pOPTMD),
  m_DeleteRegistry(FALSE), m_saveDeleteRegistry(FALSE),
  m_Migrate2Appdata(FALSE), m_saveMigrate2Appdata(FALSE)
{
#ifdef _DEBUG
  m_bShowConfigFile = true;
#endif

  m_UseSystemTray = M_UseSystemTray();
  m_HideSystemTray = M_HideSystemTray();
  m_Startup = M_Startup();
  m_MRUOnFileMenu = M_MRUOnFileMenu();
  m_DefaultOpenRO = M_DefaultOpenRO();
  m_MultipleInstances = M_MultipleInstances();
  m_MaxREItems = M_MaxREItems();
  m_MaxMRUItems = M_MaxMRUItems();
  m_InitialHotkeyState = M_AppHotKeyEnabled();
}

void COptionsSystem::DoDataExchange(CDataExchange *pDX)
{
  CPWPropertyPage::DoDataExchange(pDX);

  //{{AFX_DATA_MAP(COptionsSystem)
  DDX_Text(pDX, IDC_MAXREITEMS, m_MaxREItems);
  DDV_MinMaxInt(pDX, m_MaxREItems, 0, ID_TRAYRECENT_ENTRYMAX - ID_TRAYRECENT_ENTRY1 + 1);
  DDX_Check(pDX, IDC_DEFPWUSESYSTRAY, m_UseSystemTray);
  DDX_Check(pDX, IDC_DEFPWHIDESYSTRAY, m_HideSystemTray);
  DDX_Check(pDX, IDC_STARTUP, m_Startup);
  DDX_Text(pDX, IDC_MAXMRUITEMS, m_MaxMRUItems);
  DDV_MinMaxInt(pDX, m_MaxMRUItems, 0, ID_FILE_MRU_ENTRYMAX - ID_FILE_MRU_ENTRY1 + 1);
  DDX_Check(pDX, IDC_MRU_ONFILEMENU, m_MRUOnFileMenu);
  DDX_Check(pDX, IDC_REGDEL, m_DeleteRegistry);
  DDX_Check(pDX, IDC_MIGRATETOAPPDATA, m_Migrate2Appdata);
  DDX_Check(pDX, IDC_DEFAULTOPENRO, m_DefaultOpenRO);
  DDX_Check(pDX, IDC_MULTIPLEINSTANCES, m_MultipleInstances);

  DDX_Control(pDX, IDC_REGDELHELP, m_Help1);
  DDX_Control(pDX, IDC_MIGRATETOAPPDATAHELP, m_Help2);
  //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(COptionsSystem, CPWPropertyPage)
  //{{AFX_MSG_MAP(COptionsSystem)
  ON_BN_CLICKED(ID_HELP, OnHelp)

  ON_BN_CLICKED(IDC_DEFPWUSESYSTRAY, OnUseSystemTray)
  ON_BN_CLICKED(IDC_STARTUP, OnStartup)
  ON_BN_CLICKED(IDC_REGDEL, OnSetDeleteRegistry)
  ON_BN_CLICKED(IDC_MIGRATETOAPPDATA, OnSetMigrate2Appdata)
  ON_BN_CLICKED(IDC_APPLYCONFIGCHANGES, OnApplyConfigChanges)
  ON_MESSAGE(PSM_QUERYSIBLINGS, OnQuerySiblings)
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COptionsSystem message handlers

BOOL COptionsSystem::OnInitDialog()
{
  COptions_PropertyPage::OnInitDialog();

  PWSprefs *prefs = PWSprefs::GetInstance();
  if (!m_bShowConfigFile) {
    GetDlgItem(IDC_STATIC_CONFIGFILE)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_STATIC_RWSTATUS)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_CONFIGFILE)->ShowWindow(SW_HIDE);
  } else {
    PWSprefs::ConfigOption configoption;
    std::wstring wsCF = prefs->GetConfigFile(configoption);
    std::wstring wsCO(L"");
    switch (configoption) {
      case PWSprefs::CF_NONE:
        LoadAString(wsCF, IDS_NONE);
        break;
      case PWSprefs::CF_REGISTRY:
        LoadAString(wsCF, IDS_REGISTRY);
        break;
      case PWSprefs::CF_FILE_RO:
        LoadAString(wsCO, IDS_READ_ONLY);
        break;
      case PWSprefs::CF_FILE_RW:
      case PWSprefs::CF_FILE_RW_NEW:
        LoadAString(wsCO, IDS_READ_WRITE);
        break;
      default:
        ASSERT(0);
    }
    GetDlgItem(IDC_CONFIGFILE)->SetWindowText(wsCF.c_str());
    GetDlgItem(IDC_STATIC_RWSTATUS)->SetWindowText(wsCO.c_str());
  }

  bool bofferdeleteregistry = prefs->OfferDeleteRegistry();

  bool boffermigrate2appdata = OfferConfigMigration();

  if (!bofferdeleteregistry) {
    GetDlgItem(IDC_REGDEL)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_REGDEL)->EnableWindow(FALSE);
  }

  if (!boffermigrate2appdata) {
    GetDlgItem(IDC_MIGRATETOAPPDATA)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_MIGRATETOAPPDATA)->EnableWindow(FALSE);
  }

  if (!bofferdeleteregistry && !boffermigrate2appdata) {
    GetDlgItem(IDC_CONFIG_GRP)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_APPLYCONFIGCHANGES)->ShowWindow(SW_HIDE);
  } else {
    GetDlgItem(IDC_APPLYCONFIGCHANGES)->ShowWindow(SW_SHOW);
  }

  GetDlgItem(IDC_APPLYCONFIGCHANGES)->EnableWindow(FALSE);

  CSpinButtonCtrl *pspin = (CSpinButtonCtrl *)GetDlgItem(IDC_RESPIN);

  pspin->SetBuddy(GetDlgItem(IDC_MAXREITEMS));
  pspin->SetRange(0, ID_TRAYRECENT_ENTRYMAX - ID_TRAYRECENT_ENTRY1 + 1);
  pspin->SetBase(10);
  pspin->SetPos(m_MaxREItems);

  pspin = (CSpinButtonCtrl *)GetDlgItem(IDC_MRUSPIN);

  pspin->SetBuddy(GetDlgItem(IDC_MAXMRUITEMS));
  pspin->SetRange(0, ID_FILE_MRU_ENTRYMAX - ID_FILE_MRU_ENTRY1 + 1);
  pspin->SetBase(10);
  pspin->SetPos(m_MaxMRUItems);

  OnUseSystemTray();

  if (InitToolTip(TTS_BALLOON | TTS_NOPREFIX, 0)) {
    m_Help1.Init(IDB_QUESTIONMARK);
    m_Help2.Init(IDB_QUESTIONMARK);

    // Note naming convention: string IDS_xxx corresponds to control IDC_xxx_HELP
    AddTool(IDC_REGDELHELP, IDS_REGDEL);
    AddTool(IDC_MIGRATETOAPPDATAHELP, IDS_MIGRATETOAPPDATA);
    ActivateToolTip();
  } else {
    m_Help1.EnableWindow(FALSE);
    m_Help1.ShowWindow(SW_HIDE);
    m_Help2.EnableWindow(FALSE);
    m_Help2.ShowWindow(SW_HIDE);
  }

  if (!boffermigrate2appdata) {
    m_Help2.EnableWindow(FALSE);
    m_Help2.ShowWindow(SW_HIDE);
  }

  return TRUE;  // return TRUE unless you set the focus to a control
  // EXCEPTION: OCX Property Pages should return FALSE
}

LRESULT COptionsSystem::OnQuerySiblings(WPARAM wParam, LPARAM )
{
  UpdateData(TRUE);

  // Have any of my fields been changed?
  switch (wParam) {
    case PP_DATA_CHANGED:
      if (M_UseSystemTray()     != m_UseSystemTray     ||
          M_HideSystemTray()    != m_HideSystemTray    ||
          (m_UseSystemTray      == TRUE &&
           M_MaxREItems()       != m_MaxREItems)       ||
          M_Startup()           != m_Startup           ||
          M_MaxMRUItems()       != m_MaxMRUItems       ||
          M_MRUOnFileMenu()     != m_MRUOnFileMenu     ||
          M_DefaultOpenRO()     != m_DefaultOpenRO     ||
          M_MultipleInstances() != m_MultipleInstances ||
          m_saveDeleteRegistry  != m_DeleteRegistry    ||
          m_saveMigrate2Appdata != m_Migrate2Appdata)
        return 1L;
      break;
    case PP_UPDATE_VARIABLES:
      // Since OnOK calls OnApply after we need to verify and/or
      // copy data into the entry - we do it ourselves here first
      if (OnApply() == FALSE)
        return 1L;
  }
  return 0L;
}

BOOL COptionsSystem::OnApply()
{
  UpdateData(TRUE);

  M_UseSystemTray() = m_UseSystemTray;
  M_HideSystemTray() = m_HideSystemTray;
  M_Startup() = m_Startup;
  M_MRUOnFileMenu() = m_MRUOnFileMenu;
  M_DefaultOpenRO() = m_DefaultOpenRO;
  M_MultipleInstances() = m_MultipleInstances;
  M_MaxREItems() = m_MaxREItems;
  M_MaxMRUItems() = m_MaxMRUItems;
  M_AppHotKeyEnabled() = m_InitialHotkeyState;

  return COptions_PropertyPage::OnApply();
}

BOOL COptionsSystem::PreTranslateMessage(MSG* pMsg)
{
  RelayToolTipEvent(pMsg);

  if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F1) {
    PostMessage(WM_COMMAND, MAKELONG(ID_HELP, BN_CLICKED), NULL);
    return TRUE;
  }

  return COptions_PropertyPage::PreTranslateMessage(pMsg);
}

BOOL COptionsSystem::OnKillActive()
{
  // Needed as we have DDV routines.
  return CPWPropertyPage::OnKillActive();
}

void COptionsSystem::OnHelp()
{
  ShowHelp(L"::/html/system_tab.html");
}

void COptionsSystem::OnUseSystemTray()
{
  BOOL enable = (((CButton*)GetDlgItem(IDC_DEFPWUSESYSTRAY))->GetCheck() ==
                BST_CHECKED) ? TRUE : FALSE;

  GetDlgItem(IDC_STATIC_MAXREITEMS)->EnableWindow(enable);
  GetDlgItem(IDC_MAXREITEMS)->EnableWindow(enable);
  GetDlgItem(IDC_RESPIN)->EnableWindow(enable);

  if (enable == TRUE) {
    // Check if user has the Misc PP open and hot key set
    if (QuerySiblings(PPOPT_HOTKEY_SET, 0L) == 1L) {
      // Yes - open and hot key is set
      GetDlgItem(IDC_DEFPWHIDESYSTRAY)->EnableWindow(TRUE);
    } else {
      // No - Not open - then take initial value as the answer
      GetDlgItem(IDC_DEFPWHIDESYSTRAY)->EnableWindow(m_InitialHotkeyState);
    }
  }
}

void COptionsSystem::OnStartup()
{
  // Startup implies System tray
  bool enable = ((CButton*)GetDlgItem(IDC_STARTUP))->GetCheck() == BST_CHECKED;

  if (enable) {
    ((CButton*)GetDlgItem(IDC_DEFPWUSESYSTRAY))->SetCheck(BST_CHECKED);
    GetDlgItem(IDC_STATIC_MAXREITEMS)->EnableWindow(TRUE);
    GetDlgItem(IDC_MAXREITEMS)->EnableWindow(TRUE);
    GetDlgItem(IDC_RESPIN)->EnableWindow(TRUE);
  }
}

void COptionsSystem::OnSetDeleteRegistry()
{
  BOOL enable = (((CButton*)GetDlgItem(IDC_REGDEL))->GetCheck() == 1) ? TRUE : FALSE;

  GetDlgItem(IDC_APPLYCONFIGCHANGES)->EnableWindow(enable);
}

void COptionsSystem::OnSetMigrate2Appdata()
{
  BOOL enable = (((CButton*)GetDlgItem(IDC_MIGRATETOAPPDATA))->GetCheck() == 1) ? TRUE : FALSE;

  GetDlgItem(IDC_APPLYCONFIGCHANGES)->EnableWindow(enable);
}

void COptionsSystem::OnApplyConfigChanges()
{
  UpdateData(TRUE);

  CGeneralMsgBox gmb;
  if (m_DeleteRegistry == TRUE) {
    if (gmb.AfxMessageBox(IDS_CONFIRMDELETEREG, MB_YESNO | MB_ICONSTOP) == IDYES) {
      PWSprefs::GetInstance()->DeleteRegistryEntries();
      GetDlgItem(IDC_REGDEL)->EnableWindow(FALSE);
    }
  }

  if (m_Migrate2Appdata == TRUE) {
    GetDlgItem(IDC_MIGRATETOAPPDATA)->EnableWindow(FALSE);
    PerformConfigMigration();
  }

  if (!GetDlgItem(IDC_REGDEL)->IsWindowEnabled() &&
      !GetDlgItem(IDC_MIGRATETOAPPDATA)->IsWindowEnabled())
    GetDlgItem(IDC_APPLYCONFIGCHANGES)->EnableWindow(FALSE);

  UpdateData(FALSE);
}

BOOL COptionsSystem::OnSetActive()
{
  BOOL enable = (((CButton*)GetDlgItem(IDC_DEFPWUSESYSTRAY))->GetCheck() ==
                BST_CHECKED) ? TRUE : FALSE;

  if (enable == TRUE) {
    // Check if user has the Misc PP open and hot key set
    if (QuerySiblings(PPOPT_HOTKEY_SET, 0L) == 1L) {
      // Yes - open and hot key is set
      GetDlgItem(IDC_DEFPWHIDESYSTRAY)->EnableWindow(TRUE);
    } else {
      // No - Not open - then take initial value as the answer
      GetDlgItem(IDC_DEFPWHIDESYSTRAY)->EnableWindow(m_InitialHotkeyState);
    }
  }

  return CPWPropertyPage::OnSetActive();
}
<commit_msg>BR1357: Hide Options->System Reg cleanup tooltip button<commit_after>/*
* Copyright (c) 2003-2016 Rony Shapiro <ronys@pwsafe.org>.
* All rights reserved. Use of the code is allowed under the
* Artistic License 2.0 terms, as specified in the LICENSE file
* distributed with this code, or available from
* http://www.opensource.org/licenses/artistic-license-2.0.php
*/
// OptionsSystem.cpp : implementation file
//

#include "stdafx.h"
#include "passwordsafe.h"
#include "ThisMfcApp.h"    // For Help
#include "Options_PropertySheet.h"
#include "GeneralMsgBox.h"

#include "core/PwsPlatform.h"
#include "core/PWSprefs.h"

#include "resource.h"
#include "resource2.h"  // Menu, Toolbar & Accelerator resources
#include "resource3.h"  // String resources

#include "OptionsSystem.h" // Must be after resource.h

extern bool OfferConfigMigration();
extern bool PerformConfigMigration();

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COptionsSystem property page

bool COptionsSystem::m_bShowConfigFile = false;

IMPLEMENT_DYNAMIC(COptionsSystem, COptions_PropertyPage)

COptionsSystem::COptionsSystem(CWnd *pParent, st_Opt_master_data *pOPTMD)
: COptions_PropertyPage(pParent,
                        COptionsSystem::IDD, COptionsSystem::IDD_SHORT,
                        pOPTMD),
  m_DeleteRegistry(FALSE), m_saveDeleteRegistry(FALSE),
  m_Migrate2Appdata(FALSE), m_saveMigrate2Appdata(FALSE)
{
#ifdef _DEBUG
  m_bShowConfigFile = true;
#endif

  m_UseSystemTray = M_UseSystemTray();
  m_HideSystemTray = M_HideSystemTray();
  m_Startup = M_Startup();
  m_MRUOnFileMenu = M_MRUOnFileMenu();
  m_DefaultOpenRO = M_DefaultOpenRO();
  m_MultipleInstances = M_MultipleInstances();
  m_MaxREItems = M_MaxREItems();
  m_MaxMRUItems = M_MaxMRUItems();
  m_InitialHotkeyState = M_AppHotKeyEnabled();
}

void COptionsSystem::DoDataExchange(CDataExchange *pDX)
{
  CPWPropertyPage::DoDataExchange(pDX);

  //{{AFX_DATA_MAP(COptionsSystem)
  DDX_Text(pDX, IDC_MAXREITEMS, m_MaxREItems);
  DDV_MinMaxInt(pDX, m_MaxREItems, 0, ID_TRAYRECENT_ENTRYMAX - ID_TRAYRECENT_ENTRY1 + 1);
  DDX_Check(pDX, IDC_DEFPWUSESYSTRAY, m_UseSystemTray);
  DDX_Check(pDX, IDC_DEFPWHIDESYSTRAY, m_HideSystemTray);
  DDX_Check(pDX, IDC_STARTUP, m_Startup);
  DDX_Text(pDX, IDC_MAXMRUITEMS, m_MaxMRUItems);
  DDV_MinMaxInt(pDX, m_MaxMRUItems, 0, ID_FILE_MRU_ENTRYMAX - ID_FILE_MRU_ENTRY1 + 1);
  DDX_Check(pDX, IDC_MRU_ONFILEMENU, m_MRUOnFileMenu);
  DDX_Check(pDX, IDC_REGDEL, m_DeleteRegistry);
  DDX_Check(pDX, IDC_MIGRATETOAPPDATA, m_Migrate2Appdata);
  DDX_Check(pDX, IDC_DEFAULTOPENRO, m_DefaultOpenRO);
  DDX_Check(pDX, IDC_MULTIPLEINSTANCES, m_MultipleInstances);

  DDX_Control(pDX, IDC_REGDELHELP, m_Help1);
  DDX_Control(pDX, IDC_MIGRATETOAPPDATAHELP, m_Help2);
  //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(COptionsSystem, CPWPropertyPage)
  //{{AFX_MSG_MAP(COptionsSystem)
  ON_BN_CLICKED(ID_HELP, OnHelp)

  ON_BN_CLICKED(IDC_DEFPWUSESYSTRAY, OnUseSystemTray)
  ON_BN_CLICKED(IDC_STARTUP, OnStartup)
  ON_BN_CLICKED(IDC_REGDEL, OnSetDeleteRegistry)
  ON_BN_CLICKED(IDC_MIGRATETOAPPDATA, OnSetMigrate2Appdata)
  ON_BN_CLICKED(IDC_APPLYCONFIGCHANGES, OnApplyConfigChanges)
  ON_MESSAGE(PSM_QUERYSIBLINGS, OnQuerySiblings)
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COptionsSystem message handlers

BOOL COptionsSystem::OnInitDialog()
{
  COptions_PropertyPage::OnInitDialog();

  PWSprefs *prefs = PWSprefs::GetInstance();
  if (!m_bShowConfigFile) {
    GetDlgItem(IDC_STATIC_CONFIGFILE)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_STATIC_RWSTATUS)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_CONFIGFILE)->ShowWindow(SW_HIDE);
  } else {
    PWSprefs::ConfigOption configoption;
    std::wstring wsCF = prefs->GetConfigFile(configoption);
    std::wstring wsCO(L"");
    switch (configoption) {
      case PWSprefs::CF_NONE:
        LoadAString(wsCF, IDS_NONE);
        break;
      case PWSprefs::CF_REGISTRY:
        LoadAString(wsCF, IDS_REGISTRY);
        break;
      case PWSprefs::CF_FILE_RO:
        LoadAString(wsCO, IDS_READ_ONLY);
        break;
      case PWSprefs::CF_FILE_RW:
      case PWSprefs::CF_FILE_RW_NEW:
        LoadAString(wsCO, IDS_READ_WRITE);
        break;
      default:
        ASSERT(0);
    }
    GetDlgItem(IDC_CONFIGFILE)->SetWindowText(wsCF.c_str());
    GetDlgItem(IDC_STATIC_RWSTATUS)->SetWindowText(wsCO.c_str());
  }

  bool bofferdeleteregistry = prefs->OfferDeleteRegistry();

  bool boffermigrate2appdata = OfferConfigMigration();

  if (!bofferdeleteregistry) {
    GetDlgItem(IDC_REGDEL)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_REGDEL)->EnableWindow(FALSE);
  }

  if (!boffermigrate2appdata) {
    GetDlgItem(IDC_MIGRATETOAPPDATA)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_MIGRATETOAPPDATA)->EnableWindow(FALSE);
  }

  if (!bofferdeleteregistry && !boffermigrate2appdata) {
    GetDlgItem(IDC_CONFIG_GRP)->ShowWindow(SW_HIDE);
    GetDlgItem(IDC_APPLYCONFIGCHANGES)->ShowWindow(SW_HIDE);
  } else {
    GetDlgItem(IDC_APPLYCONFIGCHANGES)->ShowWindow(SW_SHOW);
  }

  GetDlgItem(IDC_APPLYCONFIGCHANGES)->EnableWindow(FALSE);

  CSpinButtonCtrl *pspin = (CSpinButtonCtrl *)GetDlgItem(IDC_RESPIN);

  pspin->SetBuddy(GetDlgItem(IDC_MAXREITEMS));
  pspin->SetRange(0, ID_TRAYRECENT_ENTRYMAX - ID_TRAYRECENT_ENTRY1 + 1);
  pspin->SetBase(10);
  pspin->SetPos(m_MaxREItems);

  pspin = (CSpinButtonCtrl *)GetDlgItem(IDC_MRUSPIN);

  pspin->SetBuddy(GetDlgItem(IDC_MAXMRUITEMS));
  pspin->SetRange(0, ID_FILE_MRU_ENTRYMAX - ID_FILE_MRU_ENTRY1 + 1);
  pspin->SetBase(10);
  pspin->SetPos(m_MaxMRUItems);

  OnUseSystemTray();

  if (InitToolTip(TTS_BALLOON | TTS_NOPREFIX, 0)) {
    m_Help1.Init(IDB_QUESTIONMARK);
    m_Help2.Init(IDB_QUESTIONMARK);

    // Note naming convention: string IDS_xxx corresponds to control IDC_xxx_HELP
    AddTool(IDC_REGDELHELP, IDS_REGDEL);
    AddTool(IDC_MIGRATETOAPPDATAHELP, IDS_MIGRATETOAPPDATA);
    ActivateToolTip();
  } else {
    m_Help1.EnableWindow(FALSE);
    m_Help1.ShowWindow(SW_HIDE);
    m_Help2.EnableWindow(FALSE);
    m_Help2.ShowWindow(SW_HIDE);
  }

  if (!bofferdeleteregistry) {
    m_Help1.EnableWindow(FALSE);
    m_Help1.ShowWindow(SW_HIDE);
  }

  if (!boffermigrate2appdata) {
    m_Help2.EnableWindow(FALSE);
    m_Help2.ShowWindow(SW_HIDE);
  }

  return TRUE;  // return TRUE unless you set the focus to a control
  // EXCEPTION: OCX Property Pages should return FALSE
}

LRESULT COptionsSystem::OnQuerySiblings(WPARAM wParam, LPARAM )
{
  UpdateData(TRUE);

  // Have any of my fields been changed?
  switch (wParam) {
    case PP_DATA_CHANGED:
      if (M_UseSystemTray()     != m_UseSystemTray     ||
          M_HideSystemTray()    != m_HideSystemTray    ||
          (m_UseSystemTray      == TRUE &&
           M_MaxREItems()       != m_MaxREItems)       ||
          M_Startup()           != m_Startup           ||
          M_MaxMRUItems()       != m_MaxMRUItems       ||
          M_MRUOnFileMenu()     != m_MRUOnFileMenu     ||
          M_DefaultOpenRO()     != m_DefaultOpenRO     ||
          M_MultipleInstances() != m_MultipleInstances ||
          m_saveDeleteRegistry  != m_DeleteRegistry    ||
          m_saveMigrate2Appdata != m_Migrate2Appdata)
        return 1L;
      break;
    case PP_UPDATE_VARIABLES:
      // Since OnOK calls OnApply after we need to verify and/or
      // copy data into the entry - we do it ourselves here first
      if (OnApply() == FALSE)
        return 1L;
  }
  return 0L;
}

BOOL COptionsSystem::OnApply()
{
  UpdateData(TRUE);

  M_UseSystemTray() = m_UseSystemTray;
  M_HideSystemTray() = m_HideSystemTray;
  M_Startup() = m_Startup;
  M_MRUOnFileMenu() = m_MRUOnFileMenu;
  M_DefaultOpenRO() = m_DefaultOpenRO;
  M_MultipleInstances() = m_MultipleInstances;
  M_MaxREItems() = m_MaxREItems;
  M_MaxMRUItems() = m_MaxMRUItems;
  M_AppHotKeyEnabled() = m_InitialHotkeyState;

  return COptions_PropertyPage::OnApply();
}

BOOL COptionsSystem::PreTranslateMessage(MSG* pMsg)
{
  RelayToolTipEvent(pMsg);

  if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F1) {
    PostMessage(WM_COMMAND, MAKELONG(ID_HELP, BN_CLICKED), NULL);
    return TRUE;
  }

  return COptions_PropertyPage::PreTranslateMessage(pMsg);
}

BOOL COptionsSystem::OnKillActive()
{
  // Needed as we have DDV routines.
  return CPWPropertyPage::OnKillActive();
}

void COptionsSystem::OnHelp()
{
  ShowHelp(L"::/html/system_tab.html");
}

void COptionsSystem::OnUseSystemTray()
{
  BOOL enable = (((CButton*)GetDlgItem(IDC_DEFPWUSESYSTRAY))->GetCheck() ==
                BST_CHECKED) ? TRUE : FALSE;

  GetDlgItem(IDC_STATIC_MAXREITEMS)->EnableWindow(enable);
  GetDlgItem(IDC_MAXREITEMS)->EnableWindow(enable);
  GetDlgItem(IDC_RESPIN)->EnableWindow(enable);

  if (enable == TRUE) {
    // Check if user has the Misc PP open and hot key set
    if (QuerySiblings(PPOPT_HOTKEY_SET, 0L) == 1L) {
      // Yes - open and hot key is set
      GetDlgItem(IDC_DEFPWHIDESYSTRAY)->EnableWindow(TRUE);
    } else {
      // No - Not open - then take initial value as the answer
      GetDlgItem(IDC_DEFPWHIDESYSTRAY)->EnableWindow(m_InitialHotkeyState);
    }
  }
}

void COptionsSystem::OnStartup()
{
  // Startup implies System tray
  bool enable = ((CButton*)GetDlgItem(IDC_STARTUP))->GetCheck() == BST_CHECKED;

  if (enable) {
    ((CButton*)GetDlgItem(IDC_DEFPWUSESYSTRAY))->SetCheck(BST_CHECKED);
    GetDlgItem(IDC_STATIC_MAXREITEMS)->EnableWindow(TRUE);
    GetDlgItem(IDC_MAXREITEMS)->EnableWindow(TRUE);
    GetDlgItem(IDC_RESPIN)->EnableWindow(TRUE);
  }
}

void COptionsSystem::OnSetDeleteRegistry()
{
  BOOL enable = (((CButton*)GetDlgItem(IDC_REGDEL))->GetCheck() == 1) ? TRUE : FALSE;

  GetDlgItem(IDC_APPLYCONFIGCHANGES)->EnableWindow(enable);
}

void COptionsSystem::OnSetMigrate2Appdata()
{
  BOOL enable = (((CButton*)GetDlgItem(IDC_MIGRATETOAPPDATA))->GetCheck() == 1) ? TRUE : FALSE;

  GetDlgItem(IDC_APPLYCONFIGCHANGES)->EnableWindow(enable);
}

void COptionsSystem::OnApplyConfigChanges()
{
  UpdateData(TRUE);

  CGeneralMsgBox gmb;
  if (m_DeleteRegistry == TRUE) {
    if (gmb.AfxMessageBox(IDS_CONFIRMDELETEREG, MB_YESNO | MB_ICONSTOP) == IDYES) {
      PWSprefs::GetInstance()->DeleteRegistryEntries();
      GetDlgItem(IDC_REGDEL)->EnableWindow(FALSE);
    }
  }

  if (m_Migrate2Appdata == TRUE) {
    GetDlgItem(IDC_MIGRATETOAPPDATA)->EnableWindow(FALSE);
    PerformConfigMigration();
  }

  if (!GetDlgItem(IDC_REGDEL)->IsWindowEnabled() &&
      !GetDlgItem(IDC_MIGRATETOAPPDATA)->IsWindowEnabled())
    GetDlgItem(IDC_APPLYCONFIGCHANGES)->EnableWindow(FALSE);

  UpdateData(FALSE);
}

BOOL COptionsSystem::OnSetActive()
{
  BOOL enable = (((CButton*)GetDlgItem(IDC_DEFPWUSESYSTRAY))->GetCheck() ==
                BST_CHECKED) ? TRUE : FALSE;

  if (enable == TRUE) {
    // Check if user has the Misc PP open and hot key set
    if (QuerySiblings(PPOPT_HOTKEY_SET, 0L) == 1L) {
      // Yes - open and hot key is set
      GetDlgItem(IDC_DEFPWHIDESYSTRAY)->EnableWindow(TRUE);
    } else {
      // No - Not open - then take initial value as the answer
      GetDlgItem(IDC_DEFPWHIDESYSTRAY)->EnableWindow(m_InitialHotkeyState);
    }
  }

  return CPWPropertyPage::OnSetActive();
}
<|endoftext|>


<commit_before>#include "vector3.h"
#include "catch.hpp"

template <typename V> void vectorTestSuite() {
	auto REQUIRE_VECS_EQ = [](V a, V b) {
		REQUIRE(a.x() == Approx(b.x()));
		REQUIRE(a.y() == Approx(b.y()));
		REQUIRE(a.z() == Approx(b.z()));
	};
	SECTION("Vector magSq is correct") {
		REQUIRE(V(2, 3, 6).magSq() == Approx(49));
	}
	SECTION("Vector mag is correct") {
		REQUIRE(V(2, 3, 6).mag() == Approx(7));
	}
    SECTION("Vector negation is correct") {
        REQUIRE_VECS_EQ(-V(2.0, -3.0, 1.5), V(-2.0, 3.0, -1.5));
    }
    SECTION("Vector normalization is correct") {
    	REQUIRE_VECS_EQ(V(2.0, 3.0, 6.0).norm(), V(2.0/7.0, 3.0/7.0, 6.0/7.0));
    }
    SECTION("Vector scaling is correct") {
        REQUIRE_VECS_EQ(V(2.0, -3.0, 1.5)*4, V(8.0, -12.0, 6.0));
    }
    SECTION("Vector scaling (by division) is correct") {
    	REQUIRE_VECS_EQ(V(2.0, -3.0, 4.0)/4.0, V(0.5, -0.75, 1.0));
    }
    SECTION("Vector addition is correct") {
        REQUIRE_VECS_EQ(V(2.0, -3.0, 1.5)+V(-1.5, 1.5, 0.5), V(0.5, -1.5, 2.0));
    }
    SECTION("Vector subtraction is correct") {
        REQUIRE_VECS_EQ(V(2.0, -3.0, 1.5)-V(-1.5, 1.5, 0.5), V(3.5, -4.5, 1.0));
    }
    SECTION("Vector dot product is correct") {
    	REQUIRE(V(5, 3, 2).dot(V(-2, 3, 4)) == Approx(7));
    }
    SECTION("Vector cross product is correct") {
    	REQUIRE_VECS_EQ(V(1, 2, 3).cross(V(2, 3, 4)), V(-1, 2, -1));
    }
    SECTION("Vector scalar projection is correct") {
    	REQUIRE(V(3, 4, 5).scalarProj(V(2, 0, 0)) == Approx(3));
    	REQUIRE(V(3, 4, 5).scalarProj(V(0, 2, 0)) == Approx(4));
    	REQUIRE(V(3, 4, 5).scalarProj(V(2, 6, 9)) == Approx(75.0/11.0));
    }
    SECTION("Vector project is correct") {
    	REQUIRE_VECS_EQ(V(3, 1, 4).proj(V(6, 0, 8)), V(3, 0, 4));
    }
    SECTION("Vector distance is correct") {
    	REQUIRE(V(2, 1, 3).distance(V(6, 2, -5)) == Approx(9.0));
    }
}

TEST_CASE("Vector3f math operations are accurate", "[vector3]") {
	vectorTestSuite<Vector3f>();
}
TEST_CASE("Vector3d math operations are accurate", "[vector3]") {
	vectorTestSuite<Vector3d>();
}<commit_msg>Add license<commit_after>/* The MIT License (MIT)
 *
 * Copyright (c) 2014 Colin Wallace
 *
 * 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 "vector3.h"
#include "catch.hpp"

template <typename V> void vectorTestSuite() {
	auto REQUIRE_VECS_EQ = [](V a, V b) {
		REQUIRE(a.x() == Approx(b.x()));
		REQUIRE(a.y() == Approx(b.y()));
		REQUIRE(a.z() == Approx(b.z()));
	};
	SECTION("Vector magSq is correct") {
		REQUIRE(V(2, 3, 6).magSq() == Approx(49));
	}
	SECTION("Vector mag is correct") {
		REQUIRE(V(2, 3, 6).mag() == Approx(7));
	}
    SECTION("Vector negation is correct") {
        REQUIRE_VECS_EQ(-V(2.0, -3.0, 1.5), V(-2.0, 3.0, -1.5));
    }
    SECTION("Vector normalization is correct") {
    	REQUIRE_VECS_EQ(V(2.0, 3.0, 6.0).norm(), V(2.0/7.0, 3.0/7.0, 6.0/7.0));
    }
    SECTION("Vector scaling is correct") {
        REQUIRE_VECS_EQ(V(2.0, -3.0, 1.5)*4, V(8.0, -12.0, 6.0));
    }
    SECTION("Vector scaling (by division) is correct") {
    	REQUIRE_VECS_EQ(V(2.0, -3.0, 4.0)/4.0, V(0.5, -0.75, 1.0));
    }
    SECTION("Vector addition is correct") {
        REQUIRE_VECS_EQ(V(2.0, -3.0, 1.5)+V(-1.5, 1.5, 0.5), V(0.5, -1.5, 2.0));
    }
    SECTION("Vector subtraction is correct") {
        REQUIRE_VECS_EQ(V(2.0, -3.0, 1.5)-V(-1.5, 1.5, 0.5), V(3.5, -4.5, 1.0));
    }
    SECTION("Vector dot product is correct") {
    	REQUIRE(V(5, 3, 2).dot(V(-2, 3, 4)) == Approx(7));
    }
    SECTION("Vector cross product is correct") {
    	REQUIRE_VECS_EQ(V(1, 2, 3).cross(V(2, 3, 4)), V(-1, 2, -1));
    }
    SECTION("Vector scalar projection is correct") {
    	REQUIRE(V(3, 4, 5).scalarProj(V(2, 0, 0)) == Approx(3));
    	REQUIRE(V(3, 4, 5).scalarProj(V(0, 2, 0)) == Approx(4));
    	REQUIRE(V(3, 4, 5).scalarProj(V(2, 6, 9)) == Approx(75.0/11.0));
    }
    SECTION("Vector project is correct") {
    	REQUIRE_VECS_EQ(V(3, 1, 4).proj(V(6, 0, 8)), V(3, 0, 4));
    }
    SECTION("Vector distance is correct") {
    	REQUIRE(V(2, 1, 3).distance(V(6, 2, -5)) == Approx(9.0));
    }
}

TEST_CASE("Vector3f math operations are accurate", "[vector3]") {
	vectorTestSuite<Vector3f>();
}
TEST_CASE("Vector3d math operations are accurate", "[vector3]") {
	vectorTestSuite<Vector3d>();
}<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mcbist/address.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file address.H
/// @brief Class for mcbist related addresses (addresses below the hash translation)
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: HB:FSP

#ifndef _MSS_MCBIST_ADDRESS_H_
#define _MSS_MCBIST_ADDRESS_H_

#include <fapi2.H>
#include <utility>

namespace mss
{
namespace mcbist
{

///
/// @class address
/// @brief Represents a physical address in memory
/// @note
/// 0:1   port select
/// 2     dimm select
/// 3:4   mrank(0 to 1)
/// 5:7   srank(0 to 2)
/// 8:25  row(0 to 17)
/// 26:32 col(3 to 9)
/// 33:35 bank(0 to 2)
/// 36:37 bank_group(0 to 1)
///
class address
{
    private:
        // How far over we shift to align the address in either the register or a buffer
        enum { MAGIC_PAD = 26 };

    public:

        // first is the start bit of the field, second is the length
        typedef std::pair<uint64_t, uint64_t> field;

        constexpr static field PORT = {0, 2};
        constexpr static field DIMM = {2, 1};
        constexpr static field MRANK = {3, 2};
        constexpr static field SRANK = {5, 3};
        constexpr static field ROW = {8, 18};
        constexpr static field COL = {26, 7};
        constexpr static field BANK = {33, 3};
        constexpr static field BANK_GROUP = {36, 2};
        constexpr static field LAST_VALID = BANK_GROUP;

        address() = default;

        ///
        /// @brief Construct an address from a uint64_t (scom'ed value)
        /// @param[in] i_value representing an address; say from a trap register
        ///
        /// @note This assumes input has the same bit layout as this address
        /// structure, and this is presently not the case for the trap registers (3/16).
        /// These are presently unused, however. There is an open defect against the
        /// design team to correct this.
        /// @warn Assumes right-aligned value; bit 63 is shifted to represent the Bank Group
        address( const uint64_t i_value ):
            iv_address(i_value << MAGIC_PAD)
        {
        }

        ///
        /// @brief Conversion operator to uint64_t
        /// @warn Right-aligns the address
        ///
        inline operator uint64_t() const
        {
            return iv_address >> MAGIC_PAD;
        }

        ///
        /// @brief Set a field for an address
        /// @tparam F the field to set
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        template< const field& F >
        inline address& set_field( const uint64_t i_value )
        {
            iv_address.insertFromRight<F.first, F.second>(i_value);
            return *this;
        }

        ///
        /// @brief Get a field from an address
        /// @tparam F the field to get
        /// @return right-aligned uint64_t representing the value
        ///
        template< const field& F >
        inline uint64_t get_field() const
        {
            uint64_t l_value = 0;
            iv_address.extractToRight<F.first, F.second>(l_value);
            return l_value;
        }

        ///
        /// @brief Get a range of addresses.
        /// @tparam[in] F the left-most valid field. So, if the address was for master rank,
        /// the left-most valid field would be MRANK
        /// @param[out] o_end representing an address to end at
        /// @note this pointer is the start address
        ///
        template< const field& F >
        inline void get_range( address& o_end ) const
        {
            constexpr uint64_t START = F.first + F.second;
            constexpr uint64_t LEN = (LAST_VALID.first + LAST_VALID.second) - START;

            // All we need to do is fill in the bits to the right of the last valid field
            o_end.iv_address = iv_address;
            o_end.iv_address.setBit<START, LEN>();
        }

        ///
        /// @brief Get a range of addresses given a master rank
        /// @param[in] i_start representing an address to start from
        /// @param[out] o_end representing an address to end at
        ///
        inline static void get_mrank_range( const address& i_start, address& o_end )
        {
            i_start.get_range<MRANK>(o_end);
        }

        ///
        /// @brief Get a range of addresses given a master rank
        /// @param[in] i_port representing the port for the starting address
        /// @param[in] i_dimm representing the dimm for the starting address
        /// @param[in] i_mrank representing the master rank for the starting address
        /// @param[out] o_start representing an address to start from
        /// @param[out] o_end representing an address to end at
        ///
        inline static void get_mrank_range( const uint64_t i_port, const uint64_t i_dimm, const uint64_t i_mrank,
                                            address& o_start, address& o_end )
        {
            o_start.set_port(i_port).set_dimm(i_dimm).set_master_rank(i_mrank);
            get_mrank_range(o_start, o_end);
        }

        ///
        /// @brief Get a range of addresses given a slave rank
        /// @param[in] i_start representing an address to start from
        /// @param[out] o_end representing an address to end at
        ///
        inline static void get_srank_range( const address& i_start, address& o_end )
        {
            i_start.get_range<SRANK>(o_end);
        }

        ///
        /// @brief Get a range of addresses given a slave rank
        /// @param[in] i_port representing the port for the starting address
        /// @param[in] i_dimm representing the dimm for the starting address
        /// @param[in] i_mrank representing the master rank for the starting address
        /// @param[in] i_srank representing the slave rank for the starting address
        /// @param[out] o_start representing an address to start from
        /// @param[out] o_end representing an address to end at
        ///
        inline static void get_srank_range( const uint64_t i_port, const uint64_t i_dimm,
                                            const uint64_t i_mrank, const uint64_t i_srank,
                                            address& o_start, address& o_end )
        {
            o_start.set_port(i_port).set_dimm(i_dimm).set_master_rank(i_mrank).set_slave_rank(i_srank);
            get_srank_range(o_start, o_end);
        }

        ///
        /// @brief Set the port value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_port( const uint64_t i_value )
        {
            return set_field<PORT>(i_value);
        }

        ///
        /// @brief Get the port value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_port() const
        {
            return get_field<PORT>();
        }

        ///
        /// @brief Set the DIMM value for an address
        /// @param[in] i_value the value to set
        /// @note 0 is the DIMM[0] != 0 is DIMM[1]
        /// @return address& for method chaining
        ///
        inline address& set_dimm( const uint64_t i_value )
        {
            return set_field<DIMM>(i_value);
        }

        ///
        /// @brief Get the DIMM value for an address
        /// @return right-aligned uint64_t representing the vaule
        ///
        inline uint64_t get_dimm() const
        {
            return (get_field<DIMM>() == true ? 1 : 0);
        }

        ///
        /// @brief Set the master rank value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_master_rank( const uint64_t i_value )
        {
            return set_field<MRANK>(i_value);
        }

        ///
        /// @brief Get the master rank value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_master_rank() const
        {
            return get_field<MRANK>();
        }

        ///
        /// @brief Set the slave rank value for an address
        /// @param[in] i_value the value to set
        ///
        inline void set_slave_rank( const uint64_t i_value )
        {
            set_field<SRANK>(i_value);
        }

        ///
        /// @brief Get the slave rank value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_slave_rank() const
        {
            return get_field<SRANK>();
        }

        ///
        /// @brief Set the row value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_row( const uint64_t i_value )
        {
            return set_field<ROW>(i_value);
        }

        ///
        /// @brief Get the row value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_row() const
        {
            return get_field<ROW>();
        }

        ///
        /// @brief Set the column value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_column( const uint64_t i_value )
        {
            return set_field<COL>(i_value);
        }

        ///
        /// @brief Get the column value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_column() const
        {
            return get_field<COL>();
        }

        ///
        /// @brief Set the bank value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_bank( const uint64_t i_value )
        {
            return set_field<BANK>(i_value);
        }

        ///
        /// @brief Get the bank value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_bank() const
        {
            return get_field<BANK>();
        }

        ///
        /// @brief Set the bank group value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_bank_group( const uint64_t i_value )
        {
            return set_field<BANK_GROUP>(i_value);
        }

        ///
        /// @brief Get the bank group value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_bank_group() const
        {
            return get_field<BANK_GROUP>();
        }

    private:
        // We use a fapi2 buffer as it has static compile-time support
        fapi2::buffer<uint64_t> iv_address;
};

} // namespace

} // namespace

#endif
<commit_msg>Add memdiags scrub capability<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mcbist/address.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file address.H
/// @brief Class for mcbist related addresses (addresses below the hash translation)
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: HB:FSP

#ifndef _MSS_MCBIST_ADDRESS_H_
#define _MSS_MCBIST_ADDRESS_H_

#include <fapi2.H>
#include <utility>

namespace mss
{
namespace mcbist
{

///
/// @class address
/// @brief Represents a physical address in memory
/// @note
/// 0:1   port select
/// 2     dimm select
/// 3:4   mrank(0 to 1)
/// 5:7   srank(0 to 2)
/// 8:25  row(0 to 17)
/// 26:32 col(3 to 9)
/// 33:35 bank(0 to 2)
/// 36:37 bank_group(0 to 1)
///
class address
{
    private:
        // How far over we shift to align the address in either the register or a buffer
        enum { MAGIC_PAD = 26 };

    public:

        // first is the start bit of the field, second is the length
        typedef std::pair<uint64_t, uint64_t> field;

        constexpr static field PORT = {0, 2};
        constexpr static field DIMM = {2, 1};
        constexpr static field MRANK = {3, 2};
        constexpr static field SRANK = {5, 3};
        constexpr static field ROW = {8, 18};
        constexpr static field COL = {26, 7};
        constexpr static field BANK = {33, 3};
        constexpr static field BANK_GROUP = {36, 2};
        constexpr static field LAST_VALID = BANK_GROUP;

        address() = default;

        ///
        /// @brief Construct an address from a uint64_t (scom'ed value)
        /// @param[in] i_value representing an address; say from a trap register
        ///
        /// @note This assumes input has the same bit layout as this address
        /// structure, and this is presently not the case for the trap registers (3/16).
        /// These are presently unused, however. There is an open defect against the
        /// design team to correct this.
        /// @warn Assumes right-aligned value; bit 63 is shifted to represent the Bank Group
        address( const uint64_t i_value ):
            iv_address(i_value << MAGIC_PAD)
        {
        }

        ///
        /// @brief Conversion operator to uint64_t
        /// @warn Right-aligns the address
        ///
        inline operator uint64_t() const
        {
            return iv_address >> MAGIC_PAD;
        }

        ///
        /// @brief Set a field for an address
        /// @tparam F the field to set
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        template< const field& F >
        inline address& set_field( const uint64_t i_value )
        {
            iv_address.insertFromRight<F.first, F.second>(i_value);
            return *this;
        }

        ///
        /// @brief Get a field from an address
        /// @tparam F the field to get
        /// @return right-aligned uint64_t representing the value
        ///
        template< const field& F >
        inline uint64_t get_field() const
        {
            uint64_t l_value = 0;
            iv_address.extractToRight<F.first, F.second>(l_value);
            return l_value;
        }

        ///
        /// @brief Get a range of addresses.
        /// @tparam[in] F the left-most valid field. So, if the address was for master rank,
        /// the left-most valid field would be MRANK
        /// @param[out] o_end representing an address to end at
        /// @note this pointer is the start address
        ///
        template< const field& F >
        inline void get_range( address& o_end ) const
        {
            constexpr uint64_t START = F.first + F.second;
            constexpr uint64_t LEN = (LAST_VALID.first + LAST_VALID.second) - START;

            // All we need to do is fill in the bits to the right of the last valid field
            o_end.iv_address = iv_address;
            o_end.iv_address.setBit<START, LEN>();
        }

        ///
        /// @brief Get an end address for sim mode
        /// @param[out] o_end representing an address to end at
        /// @note this pointer is the start address
        ///
        inline void get_sim_end_address( address& o_end ) const
        {
            // This magic number represents a range of addresses which cover all
            // cache lines the training algorithms touch. By effecting 0 - this end
            // address you'll effect everything which has bad ECC in the sim.
            constexpr uint64_t l_magic_sim_number = 0b1000000;

            get_range<COL>(o_end);
            o_end.set_column(l_magic_sim_number);
            return;
        }

        ///
        /// @brief Get a range of addresses given a master rank
        /// @param[in] i_start representing an address to start from
        /// @param[out] o_end representing an address to end at
        ///
        inline static void get_mrank_range( const address& i_start, address& o_end )
        {
            i_start.get_range<MRANK>(o_end);
        }

        ///
        /// @brief Get a range of addresses given a master rank
        /// @param[in] i_port representing the port for the starting address
        /// @param[in] i_dimm representing the dimm for the starting address
        /// @param[in] i_mrank representing the master rank for the starting address
        /// @param[out] o_start representing an address to start from
        /// @param[out] o_end representing an address to end at
        ///
        inline static void get_mrank_range( const uint64_t i_port, const uint64_t i_dimm, const uint64_t i_mrank,
                                            address& o_start, address& o_end )
        {
            o_start.set_port(i_port).set_dimm(i_dimm).set_master_rank(i_mrank);
            get_mrank_range(o_start, o_end);
        }

        ///
        /// @brief Get a range of addresses given a slave rank
        /// @param[in] i_start representing an address to start from
        /// @param[out] o_end representing an address to end at
        ///
        inline static void get_srank_range( const address& i_start, address& o_end )
        {
            i_start.get_range<SRANK>(o_end);
        }

        ///
        /// @brief Get a range of addresses given a slave rank
        /// @param[in] i_port representing the port for the starting address
        /// @param[in] i_dimm representing the dimm for the starting address
        /// @param[in] i_mrank representing the master rank for the starting address
        /// @param[in] i_srank representing the slave rank for the starting address
        /// @param[out] o_start representing an address to start from
        /// @param[out] o_end representing an address to end at
        ///
        inline static void get_srank_range( const uint64_t i_port, const uint64_t i_dimm,
                                            const uint64_t i_mrank, const uint64_t i_srank,
                                            address& o_start, address& o_end )
        {
            o_start.set_port(i_port).set_dimm(i_dimm).set_master_rank(i_mrank).set_slave_rank(i_srank);
            get_srank_range(o_start, o_end);
        }

        ///
        /// @brief Set the port value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_port( const uint64_t i_value )
        {
            return set_field<PORT>(i_value);
        }

        ///
        /// @brief Get the port value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_port() const
        {
            return get_field<PORT>();
        }

        ///
        /// @brief Set the DIMM value for an address
        /// @param[in] i_value the value to set
        /// @note 0 is the DIMM[0] != 0 is DIMM[1]
        /// @return address& for method chaining
        ///
        inline address& set_dimm( const uint64_t i_value )
        {
            return set_field<DIMM>(i_value);
        }

        ///
        /// @brief Get the DIMM value for an address
        /// @return right-aligned uint64_t representing the vaule
        ///
        inline uint64_t get_dimm() const
        {
            return (get_field<DIMM>() == true ? 1 : 0);
        }

        ///
        /// @brief Set the master rank value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_master_rank( const uint64_t i_value )
        {
            return set_field<MRANK>(i_value);
        }

        ///
        /// @brief Get the master rank value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_master_rank() const
        {
            return get_field<MRANK>();
        }

        ///
        /// @brief Set the slave rank value for an address
        /// @param[in] i_value the value to set
        ///
        inline void set_slave_rank( const uint64_t i_value )
        {
            set_field<SRANK>(i_value);
        }

        ///
        /// @brief Get the slave rank value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_slave_rank() const
        {
            return get_field<SRANK>();
        }

        ///
        /// @brief Set the row value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_row( const uint64_t i_value )
        {
            return set_field<ROW>(i_value);
        }

        ///
        /// @brief Get the row value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_row() const
        {
            return get_field<ROW>();
        }

        ///
        /// @brief Set the column value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_column( const uint64_t i_value )
        {
            return set_field<COL>(i_value);
        }

        ///
        /// @brief Get the column value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_column() const
        {
            return get_field<COL>();
        }

        ///
        /// @brief Set the bank value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_bank( const uint64_t i_value )
        {
            return set_field<BANK>(i_value);
        }

        ///
        /// @brief Get the bank value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_bank() const
        {
            return get_field<BANK>();
        }

        ///
        /// @brief Set the bank group value for an address
        /// @param[in] i_value the value to set
        /// @return address& for method chaining
        ///
        inline address& set_bank_group( const uint64_t i_value )
        {
            return set_field<BANK_GROUP>(i_value);
        }

        ///
        /// @brief Get the bank group value for an address
        /// @return right-aligned uint64_t representing the value
        ///
        inline uint64_t get_bank_group() const
        {
            return get_field<BANK_GROUP>();
        }

    private:
        // We use a fapi2 buffer as it has static compile-time support
        fapi2::buffer<uint64_t> iv_address;
};

} // namespace

} // namespace

#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/perv/p9_sbe_chiplet_reset.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//------------------------------------------------------------------------------
/// @file  p9_sbe_chiplet_reset.H
///
/// @brief Steps:-
///     1) Identify Partical good chiplet and configure Multicasting register
///     2) Similar way, Configure hang pulse counter for Nest/MC/OBus/XBus/PCIe
///     3) Similar way,  set fence for Nest and MC chiplet
///     4) Similar way,  Reset sys.config and OPCG setting for Nest and MC chiplet in sync mode
///
/// Done
//------------------------------------------------------------------------------
// *HWP HW Owner        : Abhishek Agarwal <abagarw8@in.ibm.com>
// *HWP HW Backup Owner : Srinivas V. Naga <srinivan@in.ibm.com>
// *HWP FW Owner        : Brian Silver <bsilver@us.ibm.com>
// *HWP Team            : Perv
// *HWP Level           : 2
// *HWP Consumed by     : SBE
//------------------------------------------------------------------------------

#ifndef _P9_SBE_CHIPLET_RESET_H_
#define _P9_SBE_CHIPLET_RESET_H_

#include <fapi2.H>

namespace p9SbeChipletReset
{
enum P9_SBE_CHIPLET_RESET_Public_Constants
{
    MCGR0_CNFG_SETTINGS = 0xE0001C0000000000ull,
    MCGR1_CNFG_SETTINGS = 0xE4001C0000000000ull,
    MCGR2_CNFG_SETTINGS = 0xE8001C0000000000ull,
    MCGR3_CNFG_SETTINGS = 0xEC001C0000000000ull,
    NET_CNTL0_HW_INIT_VALUE = 0x7C16222000000000ull,
    HANG_PULSE_0X10 = 0x10,
    HANG_PULSE_0X0F = 0x0F,
    HANG_PULSE_0X06 = 0x06,
    HANG_PULSE_0X17 = 0x17,
    HANG_PULSE_0X18 = 0x18,
    HANG_PULSE_0X22 = 0x22,
    HANG_PULSE_0X13 = 0x13,
    HANG_PULSE_0X03 = 0x03,
    OPCG_ALIGN_SETTING = 0x5000000000003020ull,
    INOP_ALIGN_SETTING_0X5 = 0x5,
    OPCG_WAIT_CYCLE_0X020 = 0x020,
    SCAN_RATIO_0X3 = 0x3,
    SYNC_PULSE_DELAY_0X0 = 0X00,
    SYNC_CONFIG_DEFAULT = 0X0000000000000000,
    HANG_PULSE_0X00 = 0x00,
    HANG_PULSE_0X01 = 0x01,
    HANG_PULSE_0X04 = 0x04,
    HANG_PULSE_0X1A = 0x1A,
    NET_CNTL1_HW_INIT_VALUE = 0x7200000000000000ull,
    MCGR2_CACHE_CNFG_SETTINGS = 0xF0001C0000000000ull,
    MCGR3_CACHE_CNFG_SETTINGS = 0xF4001C0000000000ull,
    MCGR4_CACHE_CNFG_SETTINGS = 0xF8001C0000000000ull,
    REGIONS_EXCEPT_VITAL = 0x7FF,
    SCAN_TYPES_EXCEPT_TIME_GPTR_REPR = 0xDCE,
    SCAN_TYPES_TIME_GPTR_REPR = 0x230,
    SCAN_RATIO_0X0 = 0x0,
    SYNC_CONFIG_4TO1 = 0X0800000000000000,
    HW_NS_DELAY = 200000, // unit is nano seconds
    SIM_CYCLE_DELAY = 10000, // unit is cycles
    HANG_PULSE_0X12 = 0x12,
    HANG_PULSE_0X1C = 0x1C,
    HANG_PULSE_0X05 = 0x05
};
}

typedef fapi2::ReturnCode (*p9_sbe_chiplet_reset_FP_t)(const
        fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&);

/// @brief Identify all good chiplets excluding EQ/EC
///  -- All chiplets will be reset and PLLs started
///  -- Partial bad - All nest Chiplets must be good, MC, IO can be partial bad
/// Setup multicast groups for all chiplets
///  -- Can't use the multicast for all non-nest chiplets
///  -- This is intended to be the eventual product setting
///  -- This includes the core/cache chiplets
/// For all good chiplets excluding EQ/EC
/// -- Setup Chiplet GP3 regs
///  -- Reset to default state
///  -- Set chiplet enable on all all good chiplets excluding EQ/EC
/// For all enabled chiplets excluding EQ/EC/Buses
///  -- Start vital clocks and release endpoint reset
///  -- PCB Slave error register Reset
///
///
/// @param[in]     i_target_chip   Reference to TARGET_TYPE_PROC_CHIP target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
extern "C"
{
    fapi2::ReturnCode p9_sbe_chiplet_reset(const
                                           fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip);
}

#endif
<commit_msg>Level 2 HWP for p9_sbe_chiplet_reset<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/perv/p9_sbe_chiplet_reset.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//------------------------------------------------------------------------------
/// @file  p9_sbe_chiplet_reset.H
///
/// @brief Steps:-
///     1) Identify Partical good chiplet and configure Multicasting register
///     2) Similar way, Configure hang pulse counter for Nest/MC/OBus/XBus/PCIe
///     3) Similar way,  set fence for Nest and MC chiplet
///     4) Similar way,  Reset sys.config and OPCG setting for Nest and MC chiplet in sync mode
///
/// Done
//------------------------------------------------------------------------------
// *HWP HW Owner        : Abhishek Agarwal <abagarw8@in.ibm.com>
// *HWP HW Backup Owner : Srinivas V. Naga <srinivan@in.ibm.com>
// *HWP FW Owner        : Brian Silver <bsilver@us.ibm.com>
// *HWP Team            : Perv
// *HWP Level           : 2
// *HWP Consumed by     : SBE
//------------------------------------------------------------------------------

#ifndef _P9_SBE_CHIPLET_RESET_H_
#define _P9_SBE_CHIPLET_RESET_H_

#include <fapi2.H>

namespace p9SbeChipletReset
{
enum P9_SBE_CHIPLET_RESET_Public_Constants
{
    MCGR0_CNFG_SETTINGS = 0xE0001C0000000000ull,
    MCGR1_CNFG_SETTINGS = 0xE4001C0000000000ull,
    MCGR2_CNFG_SETTINGS = 0xE8001C0000000000ull,
    MCGR3_CNFG_SETTINGS = 0xEC001C0000000000ull,
    NET_CNTL0_HW_INIT_VALUE = 0x7C16222000000000ull,
    HANG_PULSE_0X10 = 0x10,
    HANG_PULSE_0X0F = 0x0F,
    HANG_PULSE_0X06 = 0x06,
    HANG_PULSE_0X17 = 0x17,
    HANG_PULSE_0X18 = 0x18,
    HANG_PULSE_0X22 = 0x22,
    HANG_PULSE_0X13 = 0x13,
    HANG_PULSE_0X03 = 0x03,
    OPCG_ALIGN_SETTING = 0x5000000000003020ull,
    INOP_ALIGN_SETTING_0X5 = 0x5,
    OPCG_WAIT_CYCLE_0X020 = 0x020,
    SCAN_RATIO_0X3 = 0x3,
    SYNC_PULSE_DELAY_0X0 = 0X00,
    SYNC_CONFIG_DEFAULT = 0X0000000000000000,
    HANG_PULSE_0X00 = 0x00,
    HANG_PULSE_0X01 = 0x01,
    HANG_PULSE_0X04 = 0x04,
    HANG_PULSE_0X1A = 0x1A,
    NET_CNTL1_HW_INIT_VALUE = 0x7200000000000000ull,
    MCGR2_CACHE_CNFG_SETTINGS = 0xF0001C0000000000ull,
    MCGR3_CACHE_CNFG_SETTINGS = 0xF4001C0000000000ull,
    MCGR4_CACHE_CNFG_SETTINGS = 0xF8001C0000000000ull,
    REGIONS_EXCEPT_VITAL = 0x7FF,
    SCAN_TYPES_EXCEPT_TIME_GPTR_REPR = 0xDCE,
    SCAN_TYPES_TIME_GPTR_REPR = 0x230,
    SCAN_RATIO_0X0 = 0x0,
    SYNC_CONFIG_4TO1 = 0X0800000000000000,
    HW_NS_DELAY = 200000, // unit is nano seconds
    SIM_CYCLE_DELAY = 10000, // unit is cycles
    HANG_PULSE_0X12 = 0x12,
    HANG_PULSE_0X1C = 0x1C,
    HANG_PULSE_0X05 = 0x05,
    HANG_PULSE_0X08 = 0x08
};
}

typedef fapi2::ReturnCode (*p9_sbe_chiplet_reset_FP_t)(const
        fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&);

/// @brief Identify all good chiplets excluding EQ/EC
///  -- All chiplets will be reset and PLLs started
///  -- Partial bad - All nest Chiplets must be good, MC, IO can be partial bad
/// Setup multicast groups for all chiplets
///  -- Can't use the multicast for all non-nest chiplets
///  -- This is intended to be the eventual product setting
///  -- This includes the core/cache chiplets
/// For all good chiplets excluding EQ/EC
/// -- Setup Chiplet GP3 regs
///  -- Reset to default state
///  -- Set chiplet enable on all all good chiplets excluding EQ/EC
/// For all enabled chiplets excluding EQ/EC/Buses
///  -- Start vital clocks and release endpoint reset
///  -- PCB Slave error register Reset
///
///
/// @param[in]     i_target_chip   Reference to TARGET_TYPE_PROC_CHIP target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
extern "C"
{
    fapi2::ReturnCode p9_sbe_chiplet_reset(const
                                           fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip);
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2011-2015 Blender Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "util_aligned_malloc.h"

#include <cassert>

/* Adopted from Libmv. */

#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
/* Needed for memalign on Linux and _aligned_alloc on Windows. */
#  ifdef FREE_WINDOWS
/* Make sure _aligned_malloc is included. */
#    ifdef __MSVCRT_VERSION__
#      undef __MSVCRT_VERSION__
#    endif
#    define __MSVCRT_VERSION__ 0x0700
#  endif  /* FREE_WINDOWS */
#  include <malloc.h>
#else
/* Apple's malloc is 16-byte aligned, and does not have malloc.h, so include
 * stdilb instead.
 */
#  include <cstdlib>
#endif

CCL_NAMESPACE_BEGIN

void *util_aligned_malloc(int size, int alignment)
{
#ifdef _WIN32
	return _aligned_malloc(size, alignment);
#elif defined(__APPLE__)
	/* On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so
	 * they work natively with SSE types with no further work.
	 */
	assert(alignment == 16);
	return malloc(size);
#elif defined(__FreeBSD__) || defined(__NetBSD__)
	void *result;
	if (posix_memalign(&result, alignment, size)) {
		/* Non-zero means allocation error
		 * either no allocation or bad alignment value.
		 */
		return NULL;
	}
	return result;
#else  /* This is for Linux. */
	return memalign(alignment, size);
#endif
}

void util_aligned_free(void *ptr)
{
#ifdef _WIN32
	_aligned_free(ptr);
#else
	free(ptr);
#endif
}

CCL_NAMESPACE_END
<commit_msg>Make aligned allocation to respect WITH_BLENDER_GUARDEDALLOC<commit_after>/*
 * Copyright 2011-2015 Blender Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "util_aligned_malloc.h"
#include "util_guarded_allocator.h"

#include <cassert>

/* Adopted from Libmv. */

#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
/* Needed for memalign on Linux and _aligned_alloc on Windows. */
#  ifdef FREE_WINDOWS
/* Make sure _aligned_malloc is included. */
#    ifdef __MSVCRT_VERSION__
#      undef __MSVCRT_VERSION__
#    endif
#    define __MSVCRT_VERSION__ 0x0700
#  endif  /* FREE_WINDOWS */
#  include <malloc.h>
#else
/* Apple's malloc is 16-byte aligned, and does not have malloc.h, so include
 * stdilb instead.
 */
#  include <cstdlib>
#endif

CCL_NAMESPACE_BEGIN

void *util_aligned_malloc(int size, int alignment)
{
#ifdef WITH_BLENDER_GUARDEDALLOC
	return MEM_mallocN_aligned(size, alignment, "Cycles Aligned Alloc");
#endif
#ifdef _WIN32
	return _aligned_malloc(size, alignment);
#elif defined(__APPLE__)
	/* On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so
	 * they work natively with SSE types with no further work.
	 */
	assert(alignment == 16);
	return malloc(size);
#elif defined(__FreeBSD__) || defined(__NetBSD__)
	void *result;
	if (posix_memalign(&result, alignment, size)) {
		/* Non-zero means allocation error
		 * either no allocation or bad alignment value.
		 */
		return NULL;
	}
	return result;
#else  /* This is for Linux. */
	return memalign(alignment, size);
#endif
}

void util_aligned_free(void *ptr)
{
#if defined(WITH_BLENDER_GUARDEDALLOC)
	if(ptr != NULL) {
		MEM_freeN(ptr);
	}
#elif defined(_WIN32)
	_aligned_free(ptr);
#else
	free(ptr);
#endif
}

CCL_NAMESPACE_END
<|endoftext|>


<commit_before>//
// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "ClContextDeserializer.hpp"
#include "ClContextSchema_generated.h"

#include <armnn/Exceptions.hpp>
#include <armnn/utility/NumericCast.hpp>

#include <flatbuffers/flexbuffers.h>

#include <fmt/format.h>

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <vector>

namespace armnn
{

void ClContextDeserializer::Deserialize(arm_compute::CLCompileContext& clCompileContext,
                                        cl::Context& context,
                                        cl::Device& device,
                                        const std::string& filePath)
{
    std::ifstream inputFileStream(filePath, std::ios::binary);
    std::vector<std::uint8_t> binaryContent;
    while (inputFileStream)
    {
        char input;
        inputFileStream.get(input);
        if (inputFileStream)
        {
            binaryContent.push_back(static_cast<std::uint8_t>(input));
        }
    }
    inputFileStream.close();
    DeserializeFromBinary(clCompileContext, context, device, binaryContent);
}

void ClContextDeserializer::DeserializeFromBinary(arm_compute::CLCompileContext& clCompileContext,
                                                  cl::Context& context,
                                                  cl::Device& device,
                                                  const std::vector<uint8_t>& binaryContent)
{
    if (binaryContent.data() == nullptr)
    {
        throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
                                                   CHECK_LOCATION().AsString()));
    }

    size_t binaryContentSize = binaryContent.size();
    flatbuffers::Verifier verifier(binaryContent.data(), binaryContentSize);
    if (verifier.VerifyBuffer<ClContext>() == false)
    {
        throw ParseException(fmt::format("Buffer doesn't conform to the expected Armnn "
                                         "flatbuffers format. size:{0} {1}",
                                         binaryContentSize,
                                         CHECK_LOCATION().AsString()));
    }
    auto clContext = GetClContext(binaryContent.data());

    for (Program const* program : *clContext->programs())
    {
        const char* volatile programName = program->name()->c_str();
        auto programBinary = program->binary();
        std::vector<uint8_t> binary(programBinary->begin(), programBinary->begin() + programBinary->size());

        cl::Program::Binaries   binaries{ binary };
        std::vector<cl::Device> devices {device};
        cl::Program             theProgram(context, devices, binaries);
        theProgram.build();
        clCompileContext.add_built_program(programName, theProgram);
    }
}

} // namespace armnn
<commit_msg>Use mmap to load the clcache file<commit_after>//
// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//

#include "ClContextDeserializer.hpp"
#include "ClContextSchema_generated.h"

#include <armnn/Exceptions.hpp>
#include <armnn/utility/NumericCast.hpp>
#include <armnn/Logging.hpp>

#include <flatbuffers/flexbuffers.h>

#include <fmt/format.h>

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <vector>

#if defined(__linux__)
#define SERIALIZER_USE_MMAP 1
#if SERIALIZER_USE_MMAP
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#endif

namespace armnn
{

void ClContextDeserializer::Deserialize(arm_compute::CLCompileContext& clCompileContext,
                                        cl::Context& context,
                                        cl::Device& device,
                                        const std::string& filePath)
{
    std::vector<std::uint8_t> binaryContent;
#if !SERIALIZER_USE_MMAP
    std::ifstream inputFileStream(filePath, std::ios::binary);
    while (inputFileStream)
    {
        char input;
        inputFileStream.get(input);
        if (inputFileStream)
        {
            binaryContent.push_back(static_cast<std::uint8_t>(input));
        }
    }
    inputFileStream.close();
#else
    struct stat statbuf;
    int fp = open(filePath.c_str(),O_RDONLY);
    if (!fp)
    {
        ARMNN_LOG(error) << (std::string("Cannot open file ") + filePath);
        return;
    }
    fstat(fp,&statbuf);
    const unsigned long dataSize = static_cast<unsigned long>(statbuf.st_size);
    binaryContent.resize(static_cast<long unsigned int>(dataSize));
    void* ptrmem = mmap(NULL, dataSize,PROT_READ,MAP_PRIVATE,fp,0);
    if(ptrmem!=MAP_FAILED)
    {
         memcpy (binaryContent.data(), ptrmem, dataSize);
    }
    close(fp);
    if(ptrmem == MAP_FAILED)
    {
        ARMNN_LOG(error) << (std::string("Cannot map file ") + filePath);
        return;
    }
#endif

    DeserializeFromBinary(clCompileContext, context, device, binaryContent);
}

void ClContextDeserializer::DeserializeFromBinary(arm_compute::CLCompileContext& clCompileContext,
                                                  cl::Context& context,
                                                  cl::Device& device,
                                                  const std::vector<uint8_t>& binaryContent)
{
    if (binaryContent.data() == nullptr)
    {
        throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
                                                   CHECK_LOCATION().AsString()));
    }

    size_t binaryContentSize = binaryContent.size();
    flatbuffers::Verifier verifier(binaryContent.data(), binaryContentSize);
    if (verifier.VerifyBuffer<ClContext>() == false)
    {
        throw ParseException(fmt::format("Buffer doesn't conform to the expected Armnn "
                                         "flatbuffers format. size:{0} {1}",
                                         binaryContentSize,
                                         CHECK_LOCATION().AsString()));
    }
    auto clContext = GetClContext(binaryContent.data());

    for (Program const* program : *clContext->programs())
    {
        const char* volatile programName = program->name()->c_str();
        auto programBinary = program->binary();
        std::vector<uint8_t> binary(programBinary->begin(), programBinary->begin() + programBinary->size());

        cl::Program::Binaries   binaries{ binary };
        std::vector<cl::Device> devices {device};
        cl::Program             theProgram(context, devices, binaries);
        theProgram.build();
        clCompileContext.add_built_program(programName, theProgram);
    }
}

} // namespace armnn
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include <dynamic_reconfigure/server.h>
#include <geometry_msgs/Point.h>
#include <geometry_msgs/PointStamped.h>
#include <geometry_msgs/Pose.h>
#include <geometry_msgs/PoseArray.h>
#include <image_transport/image_transport.h>
#include <kinect_tomato_searcher/SearchConfig.h>
#include <sensor_msgs/image_encodings.h>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/video.hpp>

class ShowImage {
public:
  ShowImage()
    : m_gamma(2048),
      RGB_WINDOW_NAME {"RGB image"},
      DEPTH_WINDOW_NAME {"Depth image"},
      BINARY_WINDOW_NAME {"Binary image"}
  {
    for(int i = 0; i < 2048; i++) {
      float v = i / 2048.0;
      v = std::pow(v, 3) * 6;
      m_gamma[i] = v * 6 * 256;
    }

    cv::namedWindow(RGB_WINDOW_NAME);
    cv::namedWindow(DEPTH_WINDOW_NAME);
    cv::namedWindow(BINARY_WINDOW_NAME);
  }

  ~ShowImage() {
    cv::destroyWindow(RGB_WINDOW_NAME);
    cv::destroyWindow(DEPTH_WINDOW_NAME);
    cv::destroyWindow(BINARY_WINDOW_NAME);
  }

  void showRGB(const cv::Mat& rgb) {
    imshow(RGB_WINDOW_NAME, rgb);
  }

  void showBinary(const cv::Mat& binary) {
    imshow(BINARY_WINDOW_NAME, binary);
  }

  void showDepth(const cv::Mat& depth) {
    cv::Mat buf = cv::Mat::zeros(depth.size(), CV_16UC1);
    cv::Mat output = cv::Mat::zeros(depth.size(), CV_8UC3);
    cv::normalize(depth, buf, 0, 2013, cv::NORM_MINMAX);

    for (int i = 0; i < depth.rows * depth.cols; i++) {
      int y = (int)(i / depth.cols);
      int x = (int)(i % depth.cols);
      int pval = m_gamma[buf.at<uint16_t>(i)];
      int lb = pval & 0xff;

      switch(pval >> 8) {
      case 0:
        output.at<cv::Vec3b>(y,x)[2] = 255;
        output.at<cv::Vec3b>(y,x)[1] = 255-lb;
        output.at<cv::Vec3b>(y,x)[0] = 255-lb;
        break;
      case 1:
        output.at<cv::Vec3b>(y,x)[2] = 255;
        output.at<cv::Vec3b>(y,x)[1] = lb;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      case 2:
        output.at<cv::Vec3b>(y,x)[2] = 255-lb;
        output.at<cv::Vec3b>(y,x)[1] = 255;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      case 3:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 255;
        output.at<cv::Vec3b>(y,x)[0] = lb;
        break;
      case 4:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 255-lb;
        output.at<cv::Vec3b>(y,x)[0] = 255;
        break;
      case 5:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 0;
        output.at<cv::Vec3b>(y,x)[0] = 255-lb;
        break;
      default:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 0;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      }
    }
    imshow(DEPTH_WINDOW_NAME, output);
  }

private:
  std::vector<uint16_t> m_gamma;
  const std::string RGB_WINDOW_NAME;
  const std::string DEPTH_WINDOW_NAME;
  const std::string BINARY_WINDOW_NAME;
};

class SearchTomato
{
public:
  SearchTomato()
    : tomato_contours {},
      siObj {},
      server {},
      f(std::bind(&dynamic_reconfigure_callback, std::placeholders::_1, std::placeholders::_2))
  {
    server.setCallback(f);
  }

  void update(const cv::Mat& capture_rgb) {
    siObj.showRGB(capture_rgb);
    cv::Mat binary_mat = cv::Mat::zeros(capture_rgb.size(), CV_8UC1);
    imageProsessing(capture_rgb, binary_mat);
    siObj.showBinary(binary_mat);
    searchTomatoContours(binary_mat, tomato_contours);
  }

  bool searchTomato(const cv::Mat& capture_depth, geometry_msgs::Point& tomato_point) {
    siObj.showDepth(capture_depth);
    cv::Mat maskedDepth = cv::Mat::zeros(capture_depth.size(), CV_16UC1);
    cv::Mat mask = cv::Mat::zeros(capture_depth.size(), CV_8UC1);
    cv::drawContours(mask, tomato_contours, -1, cv::Scalar(255), CV_FILLED, 8);
    siObj.showBinary(mask);

    capture_depth.copyTo(maskedDepth, mask);
    return findClosePoint(maskedDepth, tomato_point);
  }

  bool searchTomato(const cv::Mat& capture_depth, geometry_msgs::PoseArray& tomato_poses) {
    tomato_poses.poses.clear();
    siObj.showDepth(capture_depth);
    cv::Mat maskedDepth = cv::Mat::zeros(capture_depth.size(), CV_16UC1);
    cv::Mat mask = cv::Mat::zeros(capture_depth.size(), CV_8UC1);
    for (std::size_t i {0}; i < tomato_contours.size(); ++i) {
      cv::drawContours(mask, tomato_contours, i, cv::Scalar(255), CV_FILLED, 8);
      siObj.showBinary(mask);

      capture_depth.copyTo(maskedDepth, mask);
      findClosePoint(maskedDepth, tomato_poses);
    }
    return tomato_poses.poses.empty() ? false : true;
  }

private:
  static void dynamic_reconfigure_callback(kinect_tomato_searcher::SearchConfig& config, uint32_t level)
  {
    h_min_ = config.h_min;
    h_max_ = config.h_max;
    s_min_ = config.s_min;
    s_max_ = config.s_max;
    v_min_ = config.v_min;
    v_max_ = config.v_max;
  }

  void imageProsessing(const cv::Mat& rgb, cv::Mat& binary) {
    cv::Mat blur, hsv;
    cv::GaussianBlur(rgb, blur, cv::Size(5, 5), 4.0, 4.0);
    cv::cvtColor(blur, hsv, CV_BGR2HSV);
    redFilter(hsv, binary);
    cv::dilate(binary, binary, cv::Mat(), cv::Point(-1, -1), 2);
    cv::erode(binary, binary, cv::Mat(), cv::Point(-1, -1), 4);
    cv::dilate(binary, binary, cv::Mat(), cv::Point(-1, -1), 1);
  }

  void searchTomatoContours(const cv::Mat& binary, std::vector<std::vector<cv::Point> >& tomato_contours) {
    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Point> contour;
    cv::Rect bounding_box;
    float ratio_balance;

    cv::findContours(binary, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    tomato_contours.clear();
    while (!contours.empty()) {
      contour = contours.back();
      contours.pop_back();

      bounding_box = cv::boundingRect(contour);
      ratio_balance = (float)bounding_box.width / (float)bounding_box.height;
      if (ratio_balance > 1.0f) ratio_balance = 1.0f / ratio_balance;

      // delete mismach. that is smaller or spier or empty
      if (bounding_box.area() >= 400 && bounding_box.area() < cv::contourArea(contour)*2 && ratio_balance > 0.4f)
        tomato_contours.push_back(contour);
    }
  }

  void redFilter(const cv::Mat& hsv, cv::Mat& binary) {
    int a, x, y;
    for(y = 0; y < hsv.rows; y++) {
      for(x = 0; x < hsv.cols; x++) {
        a = hsv.step*y+(x*3);
        if((hsv.data[a] <= h_min_ || hsv.data[a] >= h_max_) &&
           (hsv.data[a+1] >= s_min_ && hsv.data[a+1] <= s_max_) &&
           (hsv.data[a+2] >= v_min_ && hsv.data[a+2] <= v_max_))
          binary.at<unsigned char>(y,x) = 255;
        else
          binary.at<unsigned char>(y,x) = 0;
      }
    }
  }

  bool findClosePoint(const cv::Mat& maskedDepth, geometry_msgs::Point& tomato_point) {
    uint16_t depth;
    constexpr uint16_t OVER_RANGE = 3000;
    uint16_t close_depth = OVER_RANGE;

    for (int y = 0; y < maskedDepth.rows; y++) {
      const uint16_t* line_point = maskedDepth.ptr<uint16_t>(y);
      for (int x = 0; x < maskedDepth.cols; x++) {
        depth = line_point[x];
        if (512 < depth && depth <  close_depth) {
          tomato_point.x = depth; // for ros coordinate system
          tomato_point.y = x - maskedDepth.cols / 2; // for ros coordinate system
          tomato_point.z = -(y - maskedDepth.rows / 2); // for ros coordinate system
          close_depth = depth;
        }
      }
    }
    return (close_depth != OVER_RANGE ? true : false);
  }

  bool findClosePoint(const cv::Mat& maskedDepth, geometry_msgs::PoseArray& tomato_poses) {
    geometry_msgs::Point tomato_point {};
    if (findClosePoint(maskedDepth, tomato_point)) {
      geometry_msgs::Pose tomato_pose {};
      tomato_pose.position = tomato_point;
      tomato_pose.orientation.w = 1.0;
      tomato_poses.poses.push_back(tomato_pose);
      return true;
    }
    return false;
  }

  static uint16_t h_min_;
  static uint16_t h_max_;
  static uint16_t s_min_;
  static uint16_t s_max_;
  static uint16_t v_min_;
  static uint16_t v_max_;

  std::vector<std::vector<cv::Point> > tomato_contours;
  ShowImage siObj;
  dynamic_reconfigure::Server<kinect_tomato_searcher::SearchConfig> server;
  dynamic_reconfigure::Server<kinect_tomato_searcher::SearchConfig>::CallbackType f;
};
uint16_t SearchTomato::h_min_;
uint16_t SearchTomato::h_max_;
uint16_t SearchTomato::s_min_;
uint16_t SearchTomato::s_max_;
uint16_t SearchTomato::v_min_;
uint16_t SearchTomato::v_max_;

class ImageConverter {
private:
  ros::NodeHandle nh;
  ros::NodeHandle tomapo_nh;
  ros::Publisher poses_pub;
  geometry_msgs::PoseArray pub_msg;
  image_transport::ImageTransport it;
  image_transport::Subscriber rgb_sub;
  image_transport::Subscriber depth_sub;
  cv_bridge::CvImageConstPtr rgb_ptr;
  cv_bridge::CvImageConstPtr depth_ptr;
  SearchTomato stObj;
  const std::size_t height_;
  const double angle_x_per_piccell_;
  const double angle_y_per_piccell_;
  static constexpr double PI {3.141592653589793};

public:
  ImageConverter(const std::size_t width, const std::size_t height, const double angle_of_view_x, const double angle_of_view_y)
    : nh {},
      tomapo_nh {nh, "tomato_point"},
      poses_pub {tomapo_nh.advertise<geometry_msgs::PoseArray>("array", 1)},
      it {nh},
      rgb_sub {it.subscribe("color", 1, &ImageConverter::rgbCb, this)},
      depth_sub {it.subscribe("depth", 1, &ImageConverter::depthCb, this)},
      stObj {},
      height_ {height},
      angle_x_per_piccell_ {(angle_of_view_x * PI / 180.0) / width},
      angle_y_per_piccell_ {(angle_of_view_y * PI / 180.0) / height}
  {
    pub_msg.header.frame_id = "kinect";
  }

  /**
   * search tomato function.
   * get rgb image, and search tomato.
   * will tomato_point have data.
   *
   * @author Yusuke Doi
   */
  void rgbCb(const sensor_msgs::ImageConstPtr& msg) {
    // get rgb image on kinect
    try {
      rgb_ptr = cv_bridge::toCvShare(msg, "bgr8");
    } catch (cv_bridge::Exception& e) {
      ROS_ERROR("cv_bridge exception by rgb: %s", e.what());
    }

    stObj.update(rgb_ptr->image);

    cv::waitKey(100);
  }

  void depthCb(const sensor_msgs::ImageConstPtr& msg) {
    try {
      depth_ptr = cv_bridge::toCvShare(msg, sensor_msgs::image_encodings::TYPE_16UC1);
    } catch (cv_bridge::Exception& e) {
      ROS_ERROR("cv_bridge exception by depth: %s", e.what());
    }

    if (stObj.searchTomato(depth_ptr->image, pub_msg)) {
      pub_msg.header.stamp = ros::Time::now();
      for (auto& tomato_pose : pub_msg.poses) {
        tomato_pose.position.y = tomato_pose.position.x * tan(angle_x_per_piccell_ * tomato_pose.position.y) / 1000.0; // convert to m
        tomato_pose.position.z = tomato_pose.position.x * tan(angle_y_per_piccell_ * tomato_pose.position.z) / 1000.0; // convert to m
        tomato_pose.position.x = tomato_pose.position.x / 1000.0; // convert to m
      }
      poses_pub.publish(pub_msg);
    }

    cv::waitKey(100);
  }
};

int main(int argc, char** argv) {
  ros::init(argc, argv, "kinect_tomato_searcher_node");
  ImageConverter ic {512, 424, 70, 60};
  ros::spin();
  return 0;
}
<commit_msg>Remove max; unkown max value<commit_after>#include <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include <dynamic_reconfigure/server.h>
#include <geometry_msgs/Point.h>
#include <geometry_msgs/PointStamped.h>
#include <geometry_msgs/Pose.h>
#include <geometry_msgs/PoseArray.h>
#include <image_transport/image_transport.h>
#include <kinect_tomato_searcher/SearchConfig.h>
#include <sensor_msgs/image_encodings.h>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/video.hpp>

class ShowImage {
public:
  ShowImage()
    : m_gamma(2048),
      RGB_WINDOW_NAME {"RGB image"},
      DEPTH_WINDOW_NAME {"Depth image"},
      BINARY_WINDOW_NAME {"Binary image"}
  {
    for(int i = 0; i < 2048; i++) {
      float v = i / 2048.0;
      v = std::pow(v, 3) * 6;
      m_gamma[i] = v * 6 * 256;
    }

    cv::namedWindow(RGB_WINDOW_NAME);
    cv::namedWindow(DEPTH_WINDOW_NAME);
    cv::namedWindow(BINARY_WINDOW_NAME);
  }

  ~ShowImage() {
    cv::destroyWindow(RGB_WINDOW_NAME);
    cv::destroyWindow(DEPTH_WINDOW_NAME);
    cv::destroyWindow(BINARY_WINDOW_NAME);
  }

  void showRGB(const cv::Mat& rgb) {
    imshow(RGB_WINDOW_NAME, rgb);
  }

  void showBinary(const cv::Mat& binary) {
    imshow(BINARY_WINDOW_NAME, binary);
  }

  void showDepth(const cv::Mat& depth) {
    cv::Mat buf = cv::Mat::zeros(depth.size(), CV_16UC1);
    cv::Mat output = cv::Mat::zeros(depth.size(), CV_8UC3);
    cv::normalize(depth, buf, 0, 2013, cv::NORM_MINMAX);

    for (int i = 0; i < depth.rows * depth.cols; i++) {
      int y = (int)(i / depth.cols);
      int x = (int)(i % depth.cols);
      int pval = m_gamma[buf.at<uint16_t>(i)];
      int lb = pval & 0xff;

      switch(pval >> 8) {
      case 0:
        output.at<cv::Vec3b>(y,x)[2] = 255;
        output.at<cv::Vec3b>(y,x)[1] = 255-lb;
        output.at<cv::Vec3b>(y,x)[0] = 255-lb;
        break;
      case 1:
        output.at<cv::Vec3b>(y,x)[2] = 255;
        output.at<cv::Vec3b>(y,x)[1] = lb;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      case 2:
        output.at<cv::Vec3b>(y,x)[2] = 255-lb;
        output.at<cv::Vec3b>(y,x)[1] = 255;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      case 3:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 255;
        output.at<cv::Vec3b>(y,x)[0] = lb;
        break;
      case 4:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 255-lb;
        output.at<cv::Vec3b>(y,x)[0] = 255;
        break;
      case 5:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 0;
        output.at<cv::Vec3b>(y,x)[0] = 255-lb;
        break;
      default:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 0;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      }
    }
    imshow(DEPTH_WINDOW_NAME, output);
  }

private:
  std::vector<uint16_t> m_gamma;
  const std::string RGB_WINDOW_NAME;
  const std::string DEPTH_WINDOW_NAME;
  const std::string BINARY_WINDOW_NAME;
};

class SearchTomato
{
public:
  SearchTomato()
    : tomato_contours {},
      siObj {},
      server {},
      f(std::bind(&dynamic_reconfigure_callback, std::placeholders::_1, std::placeholders::_2))
  {
    server.setCallback(f);
  }

  void update(const cv::Mat& capture_rgb) {
    siObj.showRGB(capture_rgb);
    cv::Mat binary_mat = cv::Mat::zeros(capture_rgb.size(), CV_8UC1);
    imageProsessing(capture_rgb, binary_mat);
    siObj.showBinary(binary_mat);
    searchTomatoContours(binary_mat, tomato_contours);
  }

  bool searchTomato(const cv::Mat& capture_depth, geometry_msgs::Point& tomato_point) {
    siObj.showDepth(capture_depth);
    cv::Mat maskedDepth = cv::Mat::zeros(capture_depth.size(), CV_16UC1);
    cv::Mat mask = cv::Mat::zeros(capture_depth.size(), CV_8UC1);
    cv::drawContours(mask, tomato_contours, -1, cv::Scalar(255), CV_FILLED, 8);
    siObj.showBinary(mask);

    capture_depth.copyTo(maskedDepth, mask);
    return findClosePoint(maskedDepth, tomato_point);
  }

  bool searchTomato(const cv::Mat& capture_depth, geometry_msgs::PoseArray& tomato_poses) {
    tomato_poses.poses.clear();
    siObj.showDepth(capture_depth);
    cv::Mat maskedDepth = cv::Mat::zeros(capture_depth.size(), CV_16UC1);
    cv::Mat mask = cv::Mat::zeros(capture_depth.size(), CV_8UC1);
    for (std::size_t i {0}; i < tomato_contours.size(); ++i) {
      cv::drawContours(mask, tomato_contours, i, cv::Scalar(255), CV_FILLED, 8);
      siObj.showBinary(mask);

      capture_depth.copyTo(maskedDepth, mask);
      findClosePoint(maskedDepth, tomato_poses);
    }
    return tomato_poses.poses.empty() ? false : true;
  }

private:
  static void dynamic_reconfigure_callback(kinect_tomato_searcher::SearchConfig& config, uint32_t level)
  {
    h_min_ = config.h_min;
    h_max_ = config.h_max;
    s_min_ = config.s_min;
    s_max_ = config.s_max;
    v_min_ = config.v_min;
    v_max_ = config.v_max;
  }

  void imageProsessing(const cv::Mat& rgb, cv::Mat& binary) {
    cv::Mat blur, hsv;
    cv::GaussianBlur(rgb, blur, cv::Size(5, 5), 4.0, 4.0);
    cv::cvtColor(blur, hsv, CV_BGR2HSV);
    redFilter(hsv, binary);
    cv::dilate(binary, binary, cv::Mat(), cv::Point(-1, -1), 2);
    cv::erode(binary, binary, cv::Mat(), cv::Point(-1, -1), 4);
    cv::dilate(binary, binary, cv::Mat(), cv::Point(-1, -1), 1);
  }

  void searchTomatoContours(const cv::Mat& binary, std::vector<std::vector<cv::Point> >& tomato_contours) {
    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Point> contour;
    cv::Rect bounding_box;
    float ratio_balance;

    cv::findContours(binary, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    tomato_contours.clear();
    while (!contours.empty()) {
      contour = contours.back();
      contours.pop_back();

      bounding_box = cv::boundingRect(contour);
      ratio_balance = (float)bounding_box.width / (float)bounding_box.height;
      if (ratio_balance > 1.0f) ratio_balance = 1.0f / ratio_balance;

      // delete mismach. that is smaller or spier or empty
      if (bounding_box.area() >= 400 && bounding_box.area() < cv::contourArea(contour)*2 && ratio_balance > 0.4f)
        tomato_contours.push_back(contour);
    }
  }

  void redFilter(const cv::Mat& hsv, cv::Mat& binary) {
    int a, x, y;
    for(y = 0; y < hsv.rows; y++) {
      for(x = 0; x < hsv.cols; x++) {
        a = hsv.step*y+(x*3);
        if((hsv.data[a] <= h_min_ || hsv.data[a] >= h_max_) &&
           (hsv.data[a+1] >= s_min_) &&
           (hsv.data[a+2] >= v_min_))
          binary.at<unsigned char>(y,x) = 255;
        else
          binary.at<unsigned char>(y,x) = 0;
      }
    }
  }

  bool findClosePoint(const cv::Mat& maskedDepth, geometry_msgs::Point& tomato_point) {
    uint16_t depth;
    constexpr uint16_t OVER_RANGE = 3000;
    uint16_t close_depth = OVER_RANGE;

    for (int y = 0; y < maskedDepth.rows; y++) {
      const uint16_t* line_point = maskedDepth.ptr<uint16_t>(y);
      for (int x = 0; x < maskedDepth.cols; x++) {
        depth = line_point[x];
        if (512 < depth && depth <  close_depth) {
          tomato_point.x = depth; // for ros coordinate system
          tomato_point.y = x - maskedDepth.cols / 2; // for ros coordinate system
          tomato_point.z = -(y - maskedDepth.rows / 2); // for ros coordinate system
          close_depth = depth;
        }
      }
    }
    return (close_depth != OVER_RANGE ? true : false);
  }

  bool findClosePoint(const cv::Mat& maskedDepth, geometry_msgs::PoseArray& tomato_poses) {
    geometry_msgs::Point tomato_point {};
    if (findClosePoint(maskedDepth, tomato_point)) {
      geometry_msgs::Pose tomato_pose {};
      tomato_pose.position = tomato_point;
      tomato_pose.orientation.w = 1.0;
      tomato_poses.poses.push_back(tomato_pose);
      return true;
    }
    return false;
  }

  static uint16_t h_min_;
  static uint16_t h_max_;
  static uint16_t s_min_;
  static uint16_t s_max_;
  static uint16_t v_min_;
  static uint16_t v_max_;

  std::vector<std::vector<cv::Point> > tomato_contours;
  ShowImage siObj;
  dynamic_reconfigure::Server<kinect_tomato_searcher::SearchConfig> server;
  dynamic_reconfigure::Server<kinect_tomato_searcher::SearchConfig>::CallbackType f;
};
uint16_t SearchTomato::h_min_;
uint16_t SearchTomato::h_max_;
uint16_t SearchTomato::s_min_;
uint16_t SearchTomato::s_max_;
uint16_t SearchTomato::v_min_;
uint16_t SearchTomato::v_max_;

class ImageConverter {
private:
  ros::NodeHandle nh;
  ros::NodeHandle tomapo_nh;
  ros::Publisher poses_pub;
  geometry_msgs::PoseArray pub_msg;
  image_transport::ImageTransport it;
  image_transport::Subscriber rgb_sub;
  image_transport::Subscriber depth_sub;
  cv_bridge::CvImageConstPtr rgb_ptr;
  cv_bridge::CvImageConstPtr depth_ptr;
  SearchTomato stObj;
  const std::size_t height_;
  const double angle_x_per_piccell_;
  const double angle_y_per_piccell_;
  static constexpr double PI {3.141592653589793};

public:
  ImageConverter(const std::size_t width, const std::size_t height, const double angle_of_view_x, const double angle_of_view_y)
    : nh {},
      tomapo_nh {nh, "tomato_point"},
      poses_pub {tomapo_nh.advertise<geometry_msgs::PoseArray>("array", 1)},
      it {nh},
      rgb_sub {it.subscribe("color", 1, &ImageConverter::rgbCb, this)},
      depth_sub {it.subscribe("depth", 1, &ImageConverter::depthCb, this)},
      stObj {},
      height_ {height},
      angle_x_per_piccell_ {(angle_of_view_x * PI / 180.0) / width},
      angle_y_per_piccell_ {(angle_of_view_y * PI / 180.0) / height}
  {
    pub_msg.header.frame_id = "kinect";
  }

  /**
   * search tomato function.
   * get rgb image, and search tomato.
   * will tomato_point have data.
   *
   * @author Yusuke Doi
   */
  void rgbCb(const sensor_msgs::ImageConstPtr& msg) {
    // get rgb image on kinect
    try {
      rgb_ptr = cv_bridge::toCvShare(msg, "bgr8");
    } catch (cv_bridge::Exception& e) {
      ROS_ERROR("cv_bridge exception by rgb: %s", e.what());
    }

    stObj.update(rgb_ptr->image);

    cv::waitKey(100);
  }

  void depthCb(const sensor_msgs::ImageConstPtr& msg) {
    try {
      depth_ptr = cv_bridge::toCvShare(msg, sensor_msgs::image_encodings::TYPE_16UC1);
    } catch (cv_bridge::Exception& e) {
      ROS_ERROR("cv_bridge exception by depth: %s", e.what());
    }

    if (stObj.searchTomato(depth_ptr->image, pub_msg)) {
      pub_msg.header.stamp = ros::Time::now();
      for (auto& tomato_pose : pub_msg.poses) {
        tomato_pose.position.y = tomato_pose.position.x * tan(angle_x_per_piccell_ * tomato_pose.position.y) / 1000.0; // convert to m
        tomato_pose.position.z = tomato_pose.position.x * tan(angle_y_per_piccell_ * tomato_pose.position.z) / 1000.0; // convert to m
        tomato_pose.position.x = tomato_pose.position.x / 1000.0; // convert to m
      }
      poses_pub.publish(pub_msg);
    }

    cv::waitKey(100);
  }
};

int main(int argc, char** argv) {
  ros::init(argc, argv, "kinect_tomato_searcher_node");
  ImageConverter ic {512, 424, 70, 60};
  ros::spin();
  return 0;
}
<|endoftext|>