summaryrefslogtreecommitdiff
path: root/src/memory/include/himem.hpp
blob: 81166e0de6c1617c2249e5df234f4e14f634e06c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * Copyright 2023 jacqueline <me@jacqueline.id.au>
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#pragma once

#include <cstddef>
#include <cstdint>

#include "esp32/himem.h"
#include "span.hpp"

/*
 * Wrapper around an ESP-IDF himem allocation, which uses RAII to clean up after
 * itself.
 */
template <std::size_t size>
class HimemAlloc {
 public:
  esp_himem_handle_t handle;
  const bool is_valid;

  HimemAlloc() : is_valid(esp_himem_alloc(size, &handle) == ESP_OK) {}

  ~HimemAlloc() {
    if (is_valid) {
      esp_himem_free(handle);
    }
  }

  // Not copyable or movable.
  HimemAlloc(const HimemAlloc&) = delete;
  HimemAlloc& operator=(const HimemAlloc&) = delete;
};

/*
 * Wrapper around an ESP-IDF himem allocation, which maps a HimemAlloc into the
 * usable address space. Instances always contain the last memory region that
 * was mapped within them.
 */
template <std::size_t size>
class MappableRegion {
 private:
  std::byte* bytes_;

 public:
  esp_himem_rangehandle_t range_handle;
  const bool is_valid;

  MappableRegion()
      : bytes_(nullptr),
        is_valid(esp_himem_alloc_map_range(size, &range_handle) == ESP_OK) {}

  ~MappableRegion() {
    if (bytes_ != nullptr) {
      esp_himem_unmap(range_handle, bytes_, size);
    }
    if (is_valid) {
      esp_himem_free_map_range(range_handle);
    }
  }

  auto Get() -> cpp::span<std::byte> {
    if (bytes_ == nullptr) {
      return {};
    }
    return {bytes_, size};
  }

  auto Map(const HimemAlloc<size>& alloc) -> cpp::span<std::byte> {
    assert(bytes_ == nullptr);
    ESP_ERROR_CHECK(esp_himem_map(alloc.handle, range_handle, 0, 0, size, 0,
                                  reinterpret_cast<void**>(&bytes_)));
    return Get();
  }

  auto Unmap() -> void {
    if (bytes_ != nullptr) {
      ESP_ERROR_CHECK(esp_himem_unmap(range_handle, bytes_, size));
      bytes_ = nullptr;
    }
  }

  // Not copyable or movable.
  MappableRegion(const MappableRegion&) = delete;
  MappableRegion& operator=(const MappableRegion&) = delete;
};