Skip to content

Commit c839e87

Browse files
committed
Add byteswap and support native env
1 parent b16b01c commit c839e87

File tree

5 files changed

+353
-4
lines changed

5 files changed

+353
-4
lines changed

src/M5Utility.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "m5_utility/stl/extension.hpp"
1818
#include "m5_utility/stl/optional.hpp"
1919
#include "m5_utility/stl/endianness.hpp"
20+
#include "m5_utility/stl/byteswap.hpp"
2021

2122
#include "m5_utility/log/library_log.hpp"
2223

src/m5_utility/compatibility_feature.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,58 @@
88
@brief Maintain compatibility with Arduino API, etc.
99
*/
1010
#include "compatibility_feature.hpp"
11-
#include <freertos/task.h>
11+
12+
#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || \
13+
defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || \
14+
defined(CONFIG_IDF_TARGET_ESP32P4)
15+
#defined USING_ESP_PLATFORM
16+
#endif
17+
18+
#if defined(USING_ESP_PLATFORM)
19+
// #include <freertos/task.h>
20+
#include <freertos/FreeRTOS.h>
1221
#include <esp_cpu.h>
22+
#include <esp_timer.h>
23+
#else
24+
#include <ctime>
25+
#include <chrono>
26+
#include <thread>
27+
#define IRAM_ATTR /* nop */
28+
#endif
1329

1430
namespace {
1531

32+
#if !defined(USING_ESP_PLATFORM)
33+
using clock = std::chrono::high_resolution_clock;
34+
const clock::time_point start_at = clock::now();
35+
#endif
36+
1637
} // namespace
1738

1839
namespace m5 {
1940
namespace utility {
2041

2142
IRAM_ATTR unsigned long millis()
2243
{
44+
#if defined(USING_ESP_PLATFORM)
2345
return static_cast<unsigned long>(esp_timer_get_time() / 1000ULL);
46+
#else
47+
return std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - ::start_at).count();
48+
#endif
2449
}
2550

2651
IRAM_ATTR unsigned long micros()
2752
{
53+
#if defined(USING_ESP_PLATFORM)
2854
return static_cast<unsigned long>(esp_timer_get_time());
55+
#else
56+
return std::chrono::duration_cast<std::chrono::microseconds>(clock::now() - ::start_at).count();
57+
#endif
2958
}
3059

3160
void delay(const unsigned long ms)
3261
{
62+
#if defined(USING_ESP_PLATFORM)
3363
if (ms) {
3464
if (xPortInIsrContext()) {
3565
// Using busy-wait in ISR
@@ -40,10 +70,14 @@ void delay(const unsigned long ms)
4070
vTaskDelay(pdMS_TO_TICKS(ms));
4171
}
4272
}
73+
#else
74+
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
75+
#endif
4376
}
4477

4578
void delayMicroseconds(const unsigned int us)
4679
{
80+
#if defined(USING_ESP_PLATFORM)
4781
if (us) {
4882
// Using esp_rom_delay if less than 1ms
4983
if (us < 1000 || xPortInIsrContext()) {
@@ -58,6 +92,9 @@ void delayMicroseconds(const unsigned int us)
5892
esp_rom_delay_us(us_rem);
5993
}
6094
}
95+
#else
96+
std::this_thread::sleep_for(std::chrono::microseconds(us));
97+
#endif
6198
}
6299

63100
} // namespace utility

src/m5_utility/compatibility_feature.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
#ifndef M5_UTILITY_COMPATIBILITY_FEATURE_HPP
1111
#define M5_UTILITY_COMPATIBILITY_FEATURE_HPP
1212

13-
#include <freertos/FreeRTOS.h>
14-
#include <esp_timer.h>
15-
1613
namespace m5 {
1714
namespace utility {
1815

src/m5_utility/stl/byteswap.hpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
/*!
7+
@file byteswap.hpp
8+
@brief std::byteswap for less than C++23
9+
*/
10+
#ifndef M5_UTILITY_STL_BYTESWAP_HPP
11+
#define M5_UTILITY_STL_BYTESWAP_HPP
12+
13+
#include <stdint.h>
14+
#include <type_traits>
15+
#include <cstring> // memcpy
16+
17+
namespace m5 {
18+
namespace stl {
19+
20+
///@cond
21+
template <typename U,
22+
typename std::enable_if<sizeof(U) == 2 && std::is_unsigned<U>::value, std::nullptr_t>::type = nullptr>
23+
inline constexpr U bswap_fixed(U x) noexcept
24+
{
25+
return static_cast<U>((static_cast<uint16_t>(x >> 8) & 0x00FFu) | (static_cast<uint16_t>(x << 8) & 0xFF00u));
26+
}
27+
28+
template <typename U,
29+
typename std::enable_if<sizeof(U) == 4 && std::is_unsigned<U>::value, std::nullptr_t>::type = nullptr>
30+
inline constexpr U bswap_fixed(U x) noexcept
31+
{
32+
return static_cast<U>(((static_cast<uint32_t>(x) >> 24)) | ((static_cast<uint32_t>(x) >> 8) & 0x0000FF00u) |
33+
((static_cast<uint32_t>(x) << 8) & 0x00FF0000u) | ((static_cast<uint32_t>(x) << 24)));
34+
}
35+
36+
template <typename U,
37+
typename std::enable_if<sizeof(U) == 8 && std::is_unsigned<U>::value, std::nullptr_t>::type = nullptr>
38+
inline constexpr U bswap_fixed(U x) noexcept
39+
{
40+
return static_cast<U>(
41+
((static_cast<uint64_t>(x) >> 56)) | ((static_cast<uint64_t>(x) >> 40) & 0x000000000000FF00ull) |
42+
((static_cast<uint64_t>(x) >> 24) & 0x0000000000FF0000ull) |
43+
((static_cast<uint64_t>(x) >> 8) & 0x00000000FF000000ull) |
44+
((static_cast<uint64_t>(x) << 8) & 0x000000FF00000000ull) |
45+
((static_cast<uint64_t>(x) << 24) & 0x0000FF0000000000ull) |
46+
((static_cast<uint64_t>(x) << 40) & 0x00FF000000000000ull) | ((static_cast<uint64_t>(x) << 56)));
47+
}
48+
49+
#if defined(__SIZEOF_INT128__)
50+
template <typename U,
51+
typename std::enable_if<sizeof(U) == 16 && std::is_unsigned<U>::value, std::nullptr_t>::type = nullptr>
52+
inline constexpr U bswap_fixed(U x) noexcept
53+
{
54+
return ((static_cast<U>(bswap_fixed<uint64_t>(static_cast<uint64_t>(x))) << 64) |
55+
static_cast<U>(bswap_fixed<uint64_t>(static_cast<uint64_t>(x >> 64))));
56+
}
57+
#endif
58+
59+
template <typename U, typename std::enable_if<sizeof(U) == 1, std::nullptr_t>::type = nullptr>
60+
inline constexpr U bswap_fixed(U x) noexcept
61+
{
62+
return x;
63+
}
64+
65+
template <typename T, typename std::enable_if<(std::is_integral<T>::value || std::is_enum<T>::value),
66+
std::nullptr_t>::type = nullptr>
67+
inline constexpr T byteswap_constexpr(T v) noexcept
68+
{
69+
using U = typename std::make_unsigned<T>::type;
70+
return static_cast<T>(bswap_fixed<U>(static_cast<U>(v)));
71+
}
72+
73+
template <typename T, typename std::enable_if<std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
74+
T byteswap_any(T v)
75+
{
76+
if (sizeof(T) == 1) {
77+
return v;
78+
}
79+
if (sizeof(T) == 2) {
80+
uint16_t u;
81+
::memcpy(&u, &v, 2);
82+
u = byteswap_constexpr(u);
83+
::memcpy(&v, &u, 2);
84+
return v;
85+
}
86+
if (sizeof(T) == 4) {
87+
uint32_t u;
88+
::memcpy(&u, &v, 4);
89+
u = byteswap_constexpr(u);
90+
::memcpy(&v, &u, 4);
91+
return v;
92+
}
93+
if (sizeof(T) == 8) {
94+
uint64_t u;
95+
::memcpy(&u, &v, 8);
96+
u = byteswap_constexpr(u);
97+
::memcpy(&v, &u, 8);
98+
return v;
99+
}
100+
#if defined(__SIZEOF_INT128__)
101+
if (sizeof(T) == 16) {
102+
unsigned __int128 u = 0;
103+
::memcpy(&u, &v, 16);
104+
u = bswap_fixed(u);
105+
::memcpy(&v, &u, 16);
106+
return v;
107+
}
108+
#endif
109+
return v;
110+
}
111+
///@endcond
112+
113+
//! @brief byteswap for integral type
114+
template <typename T, typename std::enable_if<(std::is_integral<T>::value || std::is_enum<T>::value),
115+
std::nullptr_t>::type = nullptr>
116+
inline constexpr T byteswap(T v) noexcept
117+
{
118+
return byteswap_constexpr(v);
119+
}
120+
121+
//! @brief byteswap for floating point type
122+
template <typename T, typename std::enable_if<std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
123+
inline T byteswap(T v)
124+
{
125+
return byteswap_any(v);
126+
}
127+
128+
// If the type is not a number, it is prohibited
129+
template <typename T, typename std::enable_if<!(std::is_floating_point<T>::value) &&
130+
!(std::is_integral<T>::value || std::is_enum<T>::value),
131+
std::nullptr_t>::type = nullptr>
132+
T byteswap(T) = delete;
133+
134+
} // namespace stl
135+
} // namespace m5
136+
137+
#endif

0 commit comments

Comments
 (0)