ESPHome 2026.8.0b4
Loading...
Searching...
No Matches
model_data.cpp
Go to the documentation of this file.
1#include "model_data.h"
2
3#ifdef USE_ESP32
4
5#include <cstring>
6#include "esphome/core/log.h"
7
8#include <tensorflow/lite/core/c/common.h>
9#include <tensorflow/lite/micro/micro_interpreter.h>
10
12
13static const char *const TAG = "micro_wake_word";
14
16
18 // Reject up front: reallocating to zero frees the buffer and returns null, which would leave data_ pointing at
19 // freed memory. A zero-length model is never usable anyway.
20 if (size == 0) {
21 ESP_LOGE(TAG, "Refusing to allocate a zero-length model");
22 return false;
23 }
24
25 // Already allocated, so reallocate to the new size
26 if (this->data_) {
27 uint8_t *new_allocation = this->allocator_.reallocate(this->data_, size);
28 if (new_allocation == nullptr) {
29 ESP_LOGE(TAG, "Failed to reallocate %zu bytes", size);
30 return false;
31 }
32 this->data_ = new_allocation;
33 this->size_ = size;
34 this->valid_ = false; // Need to revalidate with new data
35 return true;
36 }
37
38 // Try to allocate in PSRAM first
39 this->data_ = this->allocator_.allocate(size);
40 if (this->data_ == nullptr) {
41 ESP_LOGE(TAG, "Failed to allocate %zu bytes", size);
42 return false;
43 }
44
45 this->size_ = size;
46 this->valid_ = false;
47 return true;
48}
49
51 if (this->data_ != nullptr) {
52 this->allocator_.deallocate(this->data_, this->size_);
53 this->data_ = nullptr;
54 this->size_ = 0;
55 this->valid_ = false;
56 }
57}
58
59const uint8_t *ModelData::get_model_pointer() const { return this->valid_ ? this->data_ : nullptr; }
60
62 this->valid_ = false; // Mark invalid while writing
63 return this->data_;
64}
65
67 // The magic number lives in bytes 4-7, so we need at least 8 bytes to read it.
68 if (!this->data_ || this->size_ < 8) {
69 ESP_LOGE(TAG, "Model data is null or too small");
70 return false;
71 }
72
73 // Check TFLite magic number "TFL3" in bytes 4-7
74 if (memcmp(this->data_ + 4, "TFL3", 4) != 0) {
75 ESP_LOGE(TAG, "Invalid TFLite model magic number");
76 return false;
77 }
78
79 // Bytes 0-3 hold the offset of the root table. tflite::GetModel only adds that offset to the start of the
80 // buffer, so check it lands inside the buffer before reading through it.
81 uint32_t root_offset;
82 memcpy(&root_offset, this->data_, sizeof(root_offset));
83 if (root_offset >= this->size_) {
84 ESP_LOGE(TAG, "TFLite model root offset is out of bounds");
85 return false;
86 }
87
88 const tflite::Model *model = tflite::GetModel(this->data_);
89 if (model->version() != TFLITE_SCHEMA_VERSION) {
90 ESP_LOGE(TAG, "TFLite model version mismatch (expected %d, got %d)", TFLITE_SCHEMA_VERSION, model->version());
91 return false;
92 }
93
94 this->valid_ = true;
95 return true;
96}
97
98} // namespace esphome::micro_wake_word
99
100#endif // USE_ESP32
T * reallocate(T *p, size_t n)
Definition helpers.h:2141
void deallocate(T *p, size_t n)
Definition helpers.h:2156
T * allocate(size_t n)
Definition helpers.h:2126
const uint8_t * get_model_pointer() const
RAMAllocator< uint8_t > allocator_
Definition model_data.h:55
uint16_t size
Definition helpers.cpp:25
static void uint32_t