// ok no namespace fl
#pragma once

// IWYU pragma: private

#ifndef __INC_FASTLED_PLATFORMS_NRF52_DELAYCYCLES_H
#define __INC_FASTLED_PLATFORMS_NRF52_DELAYCYCLES_H

#include "platforms/cycle_type.h"
#include "fl/stl/compiler_control.h"
#include "fl/stl/noexcept.h"

/// @file platforms/arm/nrf52/delaycycles.h
/// nRF52 platform-specific cycle-accurate delay utilities

/// nRF52 (Cortex-M4): Use DWT cycle counter
/// Requires enabling DWT first (done once at init)
constexpr fl::u32 DEMCR_ADDR = 0xE000EDFC;
constexpr fl::u32 DWT_CTRL_ADDR = 0xE0001000;
constexpr fl::u32 DWT_CYCCNT_ADDR = 0xE0001004;

FASTLED_FORCE_INLINE void dwt_enable_cycle_counter() FL_NOEXCEPT {
  // Enable trace and DWT
  volatile fl::u32* demcr = (volatile fl::u32*)DEMCR_ADDR;
  volatile fl::u32* dwt_ctrl = (volatile fl::u32*)DWT_CTRL_ADDR;

  *demcr |= (1u << 24);  // DEMCR.TRCENA = 1
  *dwt_ctrl |= 1u;       // DWT.CYCCNTENA = 1
}

FASTLED_FORCE_INLINE fl::u32 dwt_cyccnt() FL_NOEXCEPT {
  volatile fl::u32* cyccnt = (volatile fl::u32*)DWT_CYCCNT_ADDR;
  return *cyccnt;
}

FASTLED_FORCE_INLINE void delay_cycles_dwt(fl::u32 cycles) FL_NOEXCEPT {
  if (cycles == 0) return;
  fl::u32 start = dwt_cyccnt();
  while ((fl::u32)(dwt_cyccnt() - start) < cycles) { }
}

#endif  // __INC_FASTLED_PLATFORMS_NRF52_DELAYCYCLES_H
