libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::ESP32SPI Class Reference
Inheritance diagram for LibXR::ESP32SPI:
[legend]
Collaboration diagram for LibXR::ESP32SPI:
[legend]

Public Member Functions

 ESP32SPI (spi_host_device_t host, int sclk_pin, int miso_pin, int mosi_pin, RawData dma_rx, RawData dma_tx, SPI::Configuration config={ SPI::ClockPolarity::LOW, SPI::ClockPhase::EDGE_1, SPI::Prescaler::DIV_8, false, }, uint32_t dma_enable_min_size=3U, bool enable_dma=true)
 
ErrorCode ReadAndWrite (RawData read_data, ConstRawData write_data, OperationRW &op, bool in_isr=false) override
 进行 SPI 读写操作。Performs SPI read and write operations.
 
ErrorCode SetConfig (SPI::Configuration config) override
 设置 SPI 配置参数。Sets SPI configuration parameters.
 
ErrorCode MemRead (uint16_t reg, RawData read_data, OperationRW &op, bool in_isr=false) override
 SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.
 
ErrorCode MemWrite (uint16_t reg, ConstRawData write_data, OperationRW &op, bool in_isr=false) override
 SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.
 
ErrorCode Transfer (size_t size, OperationRW &op, bool in_isr=false) override
 进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).
 
uint32_t GetMaxBusSpeed () const override
 获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.
 
Prescaler GetMaxPrescaler () const override
 获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.
 
RawData GetRxBuffer ()
 
RawData GetTxBuffer ()
 
- Public Member Functions inherited from LibXR::SPI
 SPI (RawData rx_buffer, RawData tx_buffer)
 构造函数。Constructor.
 
virtual ErrorCode Read (RawData read_data, OperationRW &op, bool in_isr=false)
 进行 SPI 读取操作。Performs SPI read operation.
 
virtual ErrorCode Write (ConstRawData write_data, OperationRW &op, bool in_isr=false)
 进行 SPI 写入操作。Performs SPI write operation.
 
uint32_t GetBusSpeed () const
 获取 SPI 设备的当前总线速度。Gets the current bus speed of the SPI device.
 
Prescaler CalcPrescaler (uint32_t target_max_bus_speed, uint32_t target_min_bus_speed, bool increase)
 计算 SPI 分频系数。Calculates the SPI prescaler.
 
RawData GetRxBuffer ()
 获取接收数据的缓冲区。Gets the buffer for storing received data.
 
RawData GetTxBuffer ()
 获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
 
void SwitchBuffer ()
 切换缓冲区。Switches the buffer.
 
void SetActiveLength (size_t len)
 设置缓冲区的有效数据长度。Sets the length of valid data in the buffer.
 
size_t GetActiveLength () const
 获取缓冲区的有效数据长度。Gets the length of valid data in the buffer.
 
ConfigurationGetConfig ()
 获取 SPI 配置参数。Gets the SPI configuration parameters.
 
bool IsDoubleBuffer () const
 检查是否使用双缓冲区。Checks if double buffering is enabled.
 

Private Member Functions

bool Acquire ()
 
void Release ()
 
ErrorCode InitializeHardware ()
 
ErrorCode ConfigurePins ()
 
ErrorCode ResolveClockSource (uint32_t &source_hz)
 
ErrorCode InstallInterrupt ()
 
ErrorCode InitDmaBackend ()
 
void HandleInterrupt ()
 
void FinishAsync (bool in_isr, ErrorCode ec)
 
bool CanUseDma (size_t size) const
 
ErrorCode EnsureReadyAndAcquire ()
 
ErrorCode ReturnAsyncStartResult (ErrorCode ec, bool started)
 
ErrorCode StartAsyncTransfer (const uint8_t *tx, uint8_t *rx, size_t size, bool enable_rx, RawData read_back, bool mem_read, OperationRW &op, bool &started)
 
void ConfigureTransferRegisters (size_t size)
 
ErrorCode ExecuteChunk (const uint8_t *tx, uint8_t *rx, size_t size, bool enable_rx)
 
ErrorCode ExecuteTransfer (const uint8_t *tx, uint8_t *rx, size_t size, bool enable_rx)
 
bool UseLocalDoubleBuffer () const
 
void SwitchBufferLocal ()
 

Static Private Member Functions

static void SpiIsrEntry (void *arg)
 
static ErrorCode FinalizeSyncResult (OperationRW &op, bool in_isr, ErrorCode ec)
 
static ErrorCode CompleteZeroSize (OperationRW &op, bool in_isr)
 

Private Attributes

spi_host_device_t host_
 
spi_dev_t * hw_ = nullptr
 
int sclk_pin_
 
int miso_pin_
 
int mosi_pin_
 
uint32_t source_clock_hz_ = 0
 
Flag::Atomic busy_ {}
 
bool initialized_ = false
 
uint32_t dma_enable_min_size_ = 3U
 
bool dma_requested_ = true
 
RawData dma_rx_raw_ = {nullptr, 0}
 
RawData dma_tx_raw_ = {nullptr, 0}
 
size_t dbuf_rx_block_size_ = 0
 
size_t dbuf_tx_block_size_ = 0
 
uint8_t dbuf_active_block_ = 0
 
AsyncBlockWait block_wait_ {}
 
bool dbuf_enabled_ = false
 
intr_handle_t intr_handle_ = nullptr
 
bool intr_installed_ = false
 
bool dma_enabled_ = false
 
void * dma_ctx_ = nullptr
 
size_t dma_max_transfer_bytes_ = 0
 
bool async_running_ = false
 
size_t async_dma_size_ = 0
 
bool async_dma_rx_enabled_ = false
 
bool mem_read_ = false
 
RawData read_back_ = {nullptr, 0}
 
OperationRW rw_op_
 

Static Private Attributes

static constexpr size_t MAX_POLLING_TRANSFER_BYTES = SOC_SPI_MAXIMUM_BUFFER_SIZE
 
static constexpr size_t MAX_DMA_TRANSFER_BYTES = SPI_LL_DMA_MAX_BIT_LEN / 8U
 

Additional Inherited Members

- Public Types inherited from LibXR::SPI
enum class  ClockPolarity : uint8_t { LOW = 0 , HIGH = 1 }
 定义 SPI 时钟极性。Defines the SPI clock polarity. More...
 
enum class  ClockPhase : uint8_t { EDGE_1 = 0 , EDGE_2 = 1 }
 定义 SPI 时钟相位。Defines the SPI clock phase. More...
 
enum class  Prescaler : uint8_t {
  DIV_1 = 0 , DIV_2 = 1 , DIV_4 = 2 , DIV_8 = 3 ,
  DIV_16 = 4 , DIV_32 = 5 , DIV_64 = 6 , DIV_128 = 7 ,
  DIV_256 = 8 , DIV_512 = 9 , DIV_1024 = 10 , DIV_2048 = 11 ,
  DIV_4096 = 12 , DIV_8192 = 13 , DIV_16384 = 14 , DIV_32768 = 15 ,
  DIV_65536 = 16 , UNKNOWN = 0xFF
}
 
using OperationRW = WriteOperation
 定义读写操作类型的别名。Defines an alias for the read/write operation type.
 
- Static Public Member Functions inherited from LibXR::SPI
static constexpr uint32_t PrescalerToDiv (Prescaler prescaler)
 将分频系数转换为除数。Converts a prescaler to a divisor.
 

Detailed Description

Definition at line 18 of file esp_spi.hpp.

Constructor & Destructor Documentation

◆ ESP32SPI()

LibXR::ESP32SPI::ESP32SPI ( spi_host_device_t host,
int sclk_pin,
int miso_pin,
int mosi_pin,
RawData dma_rx,
RawData dma_tx,
SPI::Configuration config = SPI::ClockPolarity::LOWSPI::ClockPhase::EDGE_1SPI::Prescaler::DIV_8, false, },
uint32_t dma_enable_min_size = 3U,
bool enable_dma = true )

Definition at line 108 of file esp_spi.cpp.

111 : SPI(dma_rx, dma_tx),
112 host_(host),
113 sclk_pin_(sclk_pin),
114 miso_pin_(miso_pin),
115 mosi_pin_(mosi_pin),
116 dma_enable_min_size_(dma_enable_min_size),
117 dma_requested_(enable_dma),
118 dma_rx_raw_(dma_rx),
119 dma_tx_raw_(dma_tx),
120 dbuf_rx_block_size_(dma_rx.size_ / 2U),
121 dbuf_tx_block_size_(dma_tx.size_ / 2U)
122{
123 ASSERT(host_ != SPI1_HOST);
124 ASSERT(host_ < SPI_HOST_MAX);
125 ASSERT(static_cast<int>(host_) < SOC_SPI_PERIPH_NUM);
126 ASSERT(dma_rx_raw_.addr_ != nullptr);
127 ASSERT(dma_tx_raw_.addr_ != nullptr);
128 ASSERT(dma_rx_raw_.size_ > 0U);
129 ASSERT(dma_tx_raw_.size_ > 0U);
130
131 if (InitializeHardware() != ErrorCode::OK)
132 {
133 ASSERT(false);
134 return;
135 }
136
137 if (ConfigurePins() != ErrorCode::OK)
138 {
139 ASSERT(false);
140 return;
141 }
142
143 if (InstallInterrupt() != ErrorCode::OK)
144 {
145 ASSERT(false);
146 return;
147 }
148
149 if (dma_requested_)
150 {
151 const ErrorCode dma_ans = InitDmaBackend();
152 ASSERT(dma_ans == ErrorCode::OK);
153 if (dma_ans != ErrorCode::OK)
154 {
155 return;
156 }
157 }
158
159 if (SetConfig(config) != ErrorCode::OK)
160 {
161 ASSERT(false);
162 return;
163 }
164}
ErrorCode SetConfig(SPI::Configuration config) override
设置 SPI 配置参数。Sets SPI configuration parameters.
Definition esp_spi.cpp:451
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
SPI(RawData rx_buffer, RawData tx_buffer)
构造函数。Constructor.
Definition spi.hpp:110
ErrorCode
定义错误码枚举
@ OK
操作成功 | Operation successful

Member Function Documentation

◆ Acquire()

bool LibXR::ESP32SPI::Acquire ( )
private

Definition at line 166 of file esp_spi.cpp.

166{ return !busy_.TestAndSet(); }
bool TestAndSet() noexcept
测试并置位:置位并返回旧状态 / Test-and-set: set and return previous state
Definition flag.hpp:66

◆ CanUseDma()

bool LibXR::ESP32SPI::CanUseDma ( size_t size) const
private

Definition at line 537 of file esp_spi.cpp.

538{
539 return dma_requested_ && dma_enabled_ && (dma_ctx_ != nullptr) &&
540 (size > dma_enable_min_size_) && (size <= dma_max_transfer_bytes_);
541}

◆ CompleteZeroSize()

ErrorCode LibXR::ESP32SPI::CompleteZeroSize ( OperationRW & op,
bool in_isr )
staticprivate

Definition at line 565 of file esp_spi.cpp.

566{
567 return FinalizeSyncResult(op, in_isr, ErrorCode::OK);
568}

◆ ConfigurePins()

ErrorCode LibXR::ESP32SPI::ConfigurePins ( )
private

Definition at line 231 of file esp_spi.cpp.

232{
233 if (!initialized_ || (hw_ == nullptr))
234 {
236 }
237
238 const auto& signal = spi_periph_signal[host_];
239
240 if (sclk_pin_ >= 0)
241 {
242 if (!GPIO_IS_VALID_OUTPUT_GPIO(sclk_pin_))
243 {
244 return ErrorCode::ARG_ERR;
245 }
246 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(sclk_pin_));
247 esp_rom_gpio_connect_out_signal(sclk_pin_, signal.spiclk_out, false, false);
248 gpio_input_enable(static_cast<gpio_num_t>(sclk_pin_));
249 esp_rom_gpio_connect_in_signal(sclk_pin_, signal.spiclk_in, false);
250 }
251
252 if (mosi_pin_ >= 0)
253 {
254 if (!GPIO_IS_VALID_OUTPUT_GPIO(mosi_pin_))
255 {
256 return ErrorCode::ARG_ERR;
257 }
258 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(mosi_pin_));
259 esp_rom_gpio_connect_out_signal(mosi_pin_, signal.spid_out, false, false);
260 gpio_input_enable(static_cast<gpio_num_t>(mosi_pin_));
261 esp_rom_gpio_connect_in_signal(mosi_pin_, signal.spid_in, false);
262 }
263
264 if (miso_pin_ >= 0)
265 {
266 if (!GPIO_IS_VALID_GPIO(miso_pin_))
267 {
268 return ErrorCode::ARG_ERR;
269 }
270 gpio_input_enable(static_cast<gpio_num_t>(miso_pin_));
271 esp_rom_gpio_connect_in_signal(miso_pin_, signal.spiq_in, false);
272 }
273
274 return ErrorCode::OK;
275}
@ STATE_ERR
状态错误 | State error
@ ARG_ERR
参数错误 | Argument error

◆ ConfigureTransferRegisters()

void LibXR::ESP32SPI::ConfigureTransferRegisters ( size_t size)
private

Definition at line 579 of file esp_spi.cpp.

580{
581 static constexpr spi_line_mode_t LINE_MODE = {
582 .cmd_lines = 1,
583 .addr_lines = 1,
584 .data_lines = 1,
585 };
586 const size_t bitlen = size * 8U;
587
588 spi_ll_master_set_line_mode(hw_, LINE_MODE);
589 spi_ll_set_mosi_bitlen(hw_, bitlen);
590 spi_ll_set_miso_bitlen(hw_, bitlen);
591 spi_ll_set_command_bitlen(hw_, 0);
592 spi_ll_set_addr_bitlen(hw_, 0);
593 spi_ll_set_command(hw_, 0, 0, false);
594 spi_ll_set_address(hw_, 0, 0, false);
595 hw_->user.usr_command = 0;
596 hw_->user.usr_addr = 0;
597}

◆ EnsureReadyAndAcquire()

ErrorCode LibXR::ESP32SPI::EnsureReadyAndAcquire ( )
private

Definition at line 543 of file esp_spi.cpp.

544{
545 if (!initialized_)
546 {
547 return ErrorCode::INIT_ERR;
548 }
549 if (!Acquire())
550 {
551 return ErrorCode::BUSY;
552 }
553 return ErrorCode::OK;
554}
@ INIT_ERR
初始化错误 | Initialization error
@ BUSY
忙碌 | Busy

◆ ExecuteChunk()

ErrorCode LibXR::ESP32SPI::ExecuteChunk ( const uint8_t * tx,
uint8_t * rx,
size_t size,
bool enable_rx )
private

Definition at line 696 of file esp_spi.cpp.

698{
699 if ((size == 0U) || (size > MAX_POLLING_TRANSFER_BYTES))
700 {
701 return ErrorCode::SIZE_ERR;
702 }
703
704 static constexpr std::array<uint8_t, MAX_POLLING_TRANSFER_BYTES> ZERO = {};
705 const uint8_t* tx_data = (tx != nullptr) ? tx : ZERO.data();
706
707 ConfigureTransferRegisters(size);
708 spi_ll_enable_mosi(hw_, 1);
709 spi_ll_enable_miso(hw_, enable_rx ? 1 : 0);
710 spi_ll_write_buffer(hw_, tx_data, size * 8U);
711 spi_ll_clear_int_stat(hw_);
712 spi_ll_apply_config(hw_);
713 spi_ll_user_start(hw_);
714
715 const uint64_t timeout_us = CalcPollingTimeoutUs(size, GetBusSpeed());
716 const uint64_t start_us = GetNowUs();
717 while (!spi_ll_usr_is_done(hw_))
718 {
719 if ((GetNowUs() - start_us) > timeout_us)
720 {
721 return ErrorCode::TIMEOUT;
722 }
723 }
724
725 if (enable_rx && (rx != nullptr))
726 {
727 spi_ll_read_buffer(hw_, rx, size * 8U);
728 }
729 spi_ll_clear_int_stat(hw_);
730 return ErrorCode::OK;
731}
uint32_t GetBusSpeed() const
获取 SPI 设备的当前总线速度。Gets the current bus speed of the SPI device.
Definition spi.hpp:178
@ TIMEOUT
超时 | Timeout
@ SIZE_ERR
尺寸错误 | Size error

◆ ExecuteTransfer()

ErrorCode LibXR::ESP32SPI::ExecuteTransfer ( const uint8_t * tx,
uint8_t * rx,
size_t size,
bool enable_rx )
private

Definition at line 733 of file esp_spi.cpp.

735{
736 size_t offset = 0U;
737 while (offset < size)
738 {
739 const size_t remain = size - offset;
740 const size_t chunk = std::min(remain, MAX_POLLING_TRANSFER_BYTES);
741 const uint8_t* tx_chunk = (tx != nullptr) ? (tx + offset) : nullptr;
742 uint8_t* rx_chunk = (enable_rx && (rx != nullptr)) ? (rx + offset) : nullptr;
743
744 const ErrorCode ec = ExecuteChunk(tx_chunk, rx_chunk, chunk, enable_rx);
745 if (ec != ErrorCode::OK)
746 {
747 return ec;
748 }
749 offset += chunk;
750 }
751
752 return ErrorCode::OK;
753}

◆ FinalizeSyncResult()

ErrorCode LibXR::ESP32SPI::FinalizeSyncResult ( OperationRW & op,
bool in_isr,
ErrorCode ec )
staticprivate

Definition at line 556 of file esp_spi.cpp.

557{
558 if (op.type != OperationRW::OperationType::BLOCK)
559 {
560 op.UpdateStatus(in_isr, ec);
561 }
562 return ec;
563}

◆ FinishAsync()

void IRAM_ATTR LibXR::ESP32SPI::FinishAsync ( bool in_isr,
ErrorCode ec )
private

Definition at line 375 of file esp_spi.cpp.

376{
377 if (!async_running_)
378 {
379 return;
380 }
381
382#if CONFIG_IDF_TARGET_ESP32
383 // Keep ESP32 SPI DMA workaround state in sync with transfer lifecycle.
384 if (dma_enabled_)
385 {
386 spi_dma_ctx_t* ctx = ToDmaCtx(dma_ctx_);
387 if (ctx != nullptr)
388 {
389 spicommon_dmaworkaround_idle(ctx->tx_dma_chan.chan_id);
390 }
391 }
392#endif
393
394 spi_ll_disable_int(hw_);
395 spi_ll_clear_int_stat(hw_);
396
397 RawData rx = {nullptr, 0U};
398 const RawData read_back = read_back_;
399 const bool mem_read = mem_read_;
400 if ((ec == ErrorCode::OK) && async_dma_rx_enabled_)
401 {
402 rx = GetRxBuffer();
403#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE || SOC_PSRAM_DMA_CAPABLE
404 if (!CacheSyncDmaBuffer(rx.addr_, async_dma_size_, false))
405 {
407 }
408#endif
409 }
410
411 if ((ec == ErrorCode::OK) && (read_back.size_ > 0U))
412 {
413 if (rx.addr_ == nullptr)
414 {
415 rx = GetRxBuffer();
416 }
417 uint8_t* src = static_cast<uint8_t*>(rx.addr_);
418 if (mem_read)
419 {
420 ASSERT(rx.size_ >= (read_back.size_ + 1U));
421 src += 1;
422 }
423 else
424 {
425 ASSERT(rx.size_ >= read_back.size_);
426 }
427 Memory::FastCopy(read_back.addr_, src, read_back.size_);
428 }
429
430 if (ec == ErrorCode::OK)
431 {
432 SwitchBufferLocal();
433 }
434
435 async_running_ = false;
436 async_dma_size_ = 0U;
437 async_dma_rx_enabled_ = false;
438 mem_read_ = false;
439 read_back_ = {nullptr, 0};
440 Release();
441 if (rw_op_.type == OperationRW::OperationType::BLOCK)
442 {
443 (void)block_wait_.TryPost(in_isr, ec);
444 }
445 else
446 {
447 rw_op_.UpdateStatus(in_isr, ec);
448 }
449}
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
OperationType type
@ FAILED
操作失败 | Operation failed

◆ GetMaxBusSpeed()

uint32_t LibXR::ESP32SPI::GetMaxBusSpeed ( ) const
overridevirtual

获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.

Returns
SPI 设备的最大时钟速度(单位:Hz)。The maximum clock speed of the SPI device (in Hz).

Implements LibXR::SPI.

Definition at line 931 of file esp_spi.cpp.

931{ return source_clock_hz_; }

◆ GetMaxPrescaler()

SPI::Prescaler LibXR::ESP32SPI::GetMaxPrescaler ( ) const
overridevirtual

获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.

Returns
SPI 设备的最大分频系数。The maximum prescaler of the SPI device.

Implements LibXR::SPI.

Definition at line 933 of file esp_spi.cpp.

933{ return Prescaler::DIV_65536; }
@ DIV_65536
分频系数为 65536。Division factor is 65536.

◆ GetRxBuffer()

RawData LibXR::ESP32SPI::GetRxBuffer ( )

Definition at line 507 of file esp_spi.cpp.

508{
509 if (UseLocalDoubleBuffer())
510 {
511 auto* base = static_cast<uint8_t*>(dma_rx_raw_.addr_);
512 return {base + static_cast<size_t>(dbuf_active_block_) * dbuf_rx_block_size_,
513 dbuf_rx_block_size_};
514 }
515 return dma_rx_raw_;
516}

◆ GetTxBuffer()

RawData LibXR::ESP32SPI::GetTxBuffer ( )

Definition at line 518 of file esp_spi.cpp.

519{
520 if (UseLocalDoubleBuffer())
521 {
522 auto* base = static_cast<uint8_t*>(dma_tx_raw_.addr_);
523 return {base + static_cast<size_t>(dbuf_active_block_) * dbuf_tx_block_size_,
524 dbuf_tx_block_size_};
525 }
526 return dma_tx_raw_;
527}

◆ HandleInterrupt()

void IRAM_ATTR LibXR::ESP32SPI::HandleInterrupt ( )
private

Definition at line 354 of file esp_spi.cpp.

355{
356 if ((hw_ == nullptr) || !initialized_)
357 {
358 return;
359 }
360
361 if (!async_running_)
362 {
363 spi_ll_clear_int_stat(hw_);
364 return;
365 }
366
367 if (!spi_ll_usr_is_done(hw_))
368 {
369 return;
370 }
371
372 FinishAsync(true, ErrorCode::OK);
373}

◆ InitDmaBackend()

ErrorCode LibXR::ESP32SPI::InitDmaBackend ( )
private

Definition at line 309 of file esp_spi.cpp.

310{
311 if (dma_enabled_)
312 {
313 return ErrorCode::OK;
314 }
315
316 spi_dma_ctx_t* ctx = nullptr;
317 if (spicommon_dma_chan_alloc(host_, SPI_DMA_CH_AUTO, &ctx) != ESP_OK)
318 {
319 return ErrorCode::INIT_ERR;
320 }
321
322 const size_t cfg_max_size = std::max(dma_rx_raw_.size_, dma_tx_raw_.size_);
323 int actual_max_size = 0;
324 if (spicommon_dma_desc_alloc(ctx, static_cast<int>(cfg_max_size), &actual_max_size) !=
325 ESP_OK)
326 {
327 (void)spicommon_dma_chan_free(ctx);
328 return ErrorCode::INIT_ERR;
329 }
330
331 dma_ctx_ = ctx;
332 dma_enabled_ = true;
333 dma_max_transfer_bytes_ =
334 std::min<size_t>({static_cast<size_t>(actual_max_size), dma_rx_raw_.size_,
335 dma_tx_raw_.size_, MAX_DMA_TRANSFER_BYTES});
336
337 if (dma_max_transfer_bytes_ == 0U)
338 {
339 return ErrorCode::INIT_ERR;
340 }
341
342 return ErrorCode::OK;
343}

◆ InitializeHardware()

ErrorCode LibXR::ESP32SPI::InitializeHardware ( )
private

Definition at line 170 of file esp_spi.cpp.

171{
172 if (initialized_)
173 {
174 return ErrorCode::OK;
175 }
176
177 if ((host_ <= SPI1_HOST) || (host_ >= SPI_HOST_MAX) ||
178 (static_cast<int>(host_) >= SOC_SPI_PERIPH_NUM))
179 {
180 return ErrorCode::ARG_ERR;
181 }
182
183 const auto& signal = spi_periph_signal[host_];
184 hw_ = signal.hw;
185 if (hw_ == nullptr)
186 {
188 }
189
190 PERIPH_RCC_ATOMIC()
191 {
192 (void)__DECLARE_RCC_ATOMIC_ENV;
193 spi_ll_enable_bus_clock(host_, true);
194 spi_ll_reset_register(host_);
195 }
196 spi_ll_enable_clock(host_, true);
197 spi_ll_master_init(hw_);
198
199 const spi_line_mode_t line_mode = {
200 .cmd_lines = 1,
201 .addr_lines = 1,
202 .data_lines = 1,
203 };
204 spi_ll_master_set_line_mode(hw_, line_mode);
205 spi_ll_set_half_duplex(hw_, false);
206 spi_ll_set_tx_lsbfirst(hw_, false);
207 spi_ll_set_rx_lsbfirst(hw_, false);
208 spi_ll_set_mosi_delay(hw_, 0, 0);
209 spi_ll_enable_mosi(hw_, 1);
210 spi_ll_enable_miso(hw_, 1);
211 spi_ll_set_dummy(hw_, 0);
212 spi_ll_set_command_bitlen(hw_, 0);
213 spi_ll_set_addr_bitlen(hw_, 0);
214 spi_ll_set_command(hw_, 0, 0, false);
215 spi_ll_set_address(hw_, 0, 0, false);
216 hw_->user.usr_command = 0;
217 hw_->user.usr_addr = 0;
218
219 spi_ll_set_clk_source(hw_, SPI_CLK_SRC_DEFAULT);
220 if (ResolveClockSource(source_clock_hz_) != ErrorCode::OK)
221 {
222 return ErrorCode::INIT_ERR;
223 }
224
225 spi_ll_disable_int(hw_);
226 spi_ll_clear_int_stat(hw_);
227 initialized_ = true;
228 return ErrorCode::OK;
229}
@ NOT_SUPPORT
不支持 | Not supported

◆ InstallInterrupt()

ErrorCode LibXR::ESP32SPI::InstallInterrupt ( )
private

Definition at line 290 of file esp_spi.cpp.

291{
292 if (intr_installed_)
293 {
294 return ErrorCode::OK;
295 }
296
297 const int irq_source = static_cast<int>(spi_periph_signal[host_].irq);
298 if (esp_intr_alloc(irq_source, ESP_INTR_FLAG_IRAM, &ESP32SPI::SpiIsrEntry, this,
299 &intr_handle_) != ESP_OK)
300 {
301 intr_handle_ = nullptr;
302 return ErrorCode::INIT_ERR;
303 }
304
305 intr_installed_ = true;
306 return ErrorCode::OK;
307}

◆ MemRead()

ErrorCode LibXR::ESP32SPI::MemRead ( uint16_t reg,
RawData read_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.

Parameters
reg寄存器地址。Register address.
read_data读取的数据缓冲区。Buffer to store read data.
op操作类型(同步/异步)。Operation mode (sync/async).
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating success or failure.

Implements LibXR::SPI.

Definition at line 808 of file esp_spi.cpp.

809{
810 if (read_data.size_ == 0U)
811 {
812 return CompleteZeroSize(op, in_isr);
813 }
814
815 const ErrorCode lock_ec = EnsureReadyAndAcquire();
816 if (lock_ec != ErrorCode::OK)
817 {
818 return lock_ec;
819 }
820
821 RawData rx = GetRxBuffer();
822 RawData tx = GetTxBuffer();
823 const size_t total = read_data.size_ + 1U;
824
825 ASSERT(rx.size_ >= total);
826 ASSERT(tx.size_ >= total);
827
828 auto* tx_ptr = static_cast<uint8_t*>(tx.addr_);
829 tx_ptr[0] = static_cast<uint8_t>(reg | 0x80U);
830 Memory::FastSet(tx_ptr + 1, 0x00, read_data.size_);
831
832 if (CanUseDma(total))
833 {
834 bool started = false;
835 const ErrorCode ec = StartAsyncTransfer(tx_ptr, static_cast<uint8_t*>(rx.addr_),
836 total, true, read_data, true, op, started);
837 return ReturnAsyncStartResult(ec, started);
838 }
839
840 const ErrorCode ec =
841 ExecuteTransfer(tx_ptr, static_cast<uint8_t*>(rx.addr_), total, true);
842 if (ec == ErrorCode::OK)
843 {
844 auto* rx_ptr = static_cast<uint8_t*>(rx.addr_);
845 Memory::FastCopy(read_data.addr_, rx_ptr + 1, read_data.size_);
846 SwitchBufferLocal();
847 }
848
849 Release();
850 return FinalizeSyncResult(op, in_isr, ec);
851}
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill

◆ MemWrite()

ErrorCode LibXR::ESP32SPI::MemWrite ( uint16_t reg,
ConstRawData write_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.

Parameters
reg寄存器地址。Register address.
write_data写入的数据缓冲区。Buffer containing data to write.
op操作类型(同步/异步)。Operation mode (sync/async).
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating success or failure.

Implements LibXR::SPI.

Definition at line 853 of file esp_spi.cpp.

855{
856 if (write_data.size_ == 0U)
857 {
858 return CompleteZeroSize(op, in_isr);
859 }
860
861 const ErrorCode lock_ec = EnsureReadyAndAcquire();
862 if (lock_ec != ErrorCode::OK)
863 {
864 return lock_ec;
865 }
866
867 RawData tx = GetTxBuffer();
868 const size_t total = write_data.size_ + 1U;
869 ASSERT(tx.size_ >= total);
870
871 auto* tx_ptr = static_cast<uint8_t*>(tx.addr_);
872 tx_ptr[0] = static_cast<uint8_t>(reg & 0x7FU);
873 Memory::FastCopy(tx_ptr + 1, write_data.addr_, write_data.size_);
874
875 if (CanUseDma(total))
876 {
877 bool started = false;
878 const ErrorCode ec = StartAsyncTransfer(tx_ptr, nullptr, total, false, {nullptr, 0},
879 false, op, started);
880 return ReturnAsyncStartResult(ec, started);
881 }
882
883 const ErrorCode ec = ExecuteTransfer(tx_ptr, nullptr, total, false);
884 if (ec == ErrorCode::OK)
885 {
886 SwitchBufferLocal();
887 }
888
889 Release();
890 return FinalizeSyncResult(op, in_isr, ec);
891}

◆ ReadAndWrite()

ErrorCode LibXR::ESP32SPI::ReadAndWrite ( RawData read_data,
ConstRawData write_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

进行 SPI 读写操作。Performs SPI read and write operations.

Parameters
read_data存储读取数据的缓冲区。Buffer to store the read data.
write_data需要写入的数据缓冲区。Buffer containing the data to be written.
op读写操作类型。Type of read/write operation.
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 755 of file esp_spi.cpp.

757{
758 const size_t need = std::max(read_data.size_, write_data.size_);
759 if (need == 0U)
760 {
761 return CompleteZeroSize(op, in_isr);
762 }
763
764 const ErrorCode lock_ec = EnsureReadyAndAcquire();
765 if (lock_ec != ErrorCode::OK)
766 {
767 return lock_ec;
768 }
769
770 RawData rx = GetRxBuffer();
771 RawData tx = GetTxBuffer();
772 ASSERT(rx.size_ >= need);
773 ASSERT(tx.size_ >= need);
774
775 auto* tx_ptr = static_cast<uint8_t*>(tx.addr_);
776 if (write_data.size_ > 0U)
777 {
778 Memory::FastCopy(tx_ptr, write_data.addr_, write_data.size_);
779 }
780 if (need > write_data.size_)
781 {
782 Memory::FastSet(tx_ptr + write_data.size_, 0x00, need - write_data.size_);
783 }
784
785 if (CanUseDma(need))
786 {
787 bool started = false;
788 const ErrorCode ec = StartAsyncTransfer(tx_ptr, static_cast<uint8_t*>(rx.addr_), need,
789 true, read_data, false, op, started);
790 return ReturnAsyncStartResult(ec, started);
791 }
792
793 const ErrorCode ec =
794 ExecuteTransfer(tx_ptr, static_cast<uint8_t*>(rx.addr_), need, true);
795 if (ec == ErrorCode::OK)
796 {
797 if (read_data.size_ > 0U)
798 {
799 Memory::FastCopy(read_data.addr_, rx.addr_, read_data.size_);
800 }
801 SwitchBufferLocal();
802 }
803
804 Release();
805 return FinalizeSyncResult(op, in_isr, ec);
806}

◆ Release()

void LibXR::ESP32SPI::Release ( )
private

Definition at line 168 of file esp_spi.cpp.

168{ busy_.Clear(); }
void Clear() noexcept
清除标志 / Clear the flag
Definition flag.hpp:47

◆ ResolveClockSource()

ErrorCode LibXR::ESP32SPI::ResolveClockSource ( uint32_t & source_hz)
private

Definition at line 277 of file esp_spi.cpp.

278{
279 source_hz = 0;
280 const esp_err_t err =
281 esp_clk_tree_src_get_freq_hz(static_cast<soc_module_clk_t>(SPI_CLK_SRC_DEFAULT),
282 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &source_hz);
283 if ((err != ESP_OK) || (source_hz == 0))
284 {
285 return ErrorCode::INIT_ERR;
286 }
287 return ErrorCode::OK;
288}

◆ ReturnAsyncStartResult()

ErrorCode LibXR::ESP32SPI::ReturnAsyncStartResult ( ErrorCode ec,
bool started )
private

Definition at line 570 of file esp_spi.cpp.

571{
572 if (!started)
573 {
574 Release();
575 }
576 return ec;
577}

◆ SetConfig()

ErrorCode LibXR::ESP32SPI::SetConfig ( SPI::Configuration config)
overridevirtual

设置 SPI 配置参数。Sets SPI configuration parameters.

Parameters
config需要应用的 SPI 配置。The SPI configuration to apply.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 451 of file esp_spi.cpp.

452{
453 if (!initialized_ || (hw_ == nullptr))
454 {
456 }
457 if (busy_.IsSet())
458 {
459 return ErrorCode::BUSY;
460 }
461
462 if (config.prescaler == Prescaler::UNKNOWN)
463 {
464 return ErrorCode::ARG_ERR;
465 }
466 if (config.double_buffer &&
467 ((dbuf_rx_block_size_ == 0U) || (dbuf_tx_block_size_ == 0U)))
468 {
469 return ErrorCode::ARG_ERR;
470 }
471
472 const uint32_t div = PrescalerToDiv(config.prescaler);
473 if ((div == 0) || (source_clock_hz_ == 0))
474 {
475 return ErrorCode::ARG_ERR;
476 }
477
478 const uint32_t target_hz = source_clock_hz_ / div;
479 if (target_hz == 0)
480 {
481 return ErrorCode::ARG_ERR;
482 }
483
484 const uint8_t mode = ResolveSpiMode(config.clock_polarity, config.clock_phase);
485 spi_ll_master_set_mode(hw_, mode);
486
487 const int applied_hz = spi_ll_master_set_clock(hw_, static_cast<int>(source_clock_hz_),
488 static_cast<int>(target_hz), 128);
489 if (applied_hz <= 0)
490 {
491 return ErrorCode::INIT_ERR;
492 }
493
494 spi_ll_apply_config(hw_);
495 GetConfig() = config;
496 dbuf_enabled_ = config.double_buffer;
497 dbuf_active_block_ = 0U;
498
499 return ErrorCode::OK;
500}
bool IsSet() const noexcept
判断是否已置位 / Check whether the flag is set
Definition flag.hpp:55
@ UNKNOWN
未知分频系数。Unknown prescaler.
static constexpr uint32_t PrescalerToDiv(Prescaler prescaler)
将分频系数转换为除数。Converts a prescaler to a divisor.
Definition spi.hpp:70
Configuration & GetConfig()
获取 SPI 配置参数。Gets the SPI configuration parameters.
Definition spi.hpp:396

◆ SpiIsrEntry()

void IRAM_ATTR LibXR::ESP32SPI::SpiIsrEntry ( void * arg)
staticprivate

Definition at line 345 of file esp_spi.cpp.

346{
347 auto* spi = static_cast<ESP32SPI*>(arg);
348 if (spi != nullptr)
349 {
350 spi->HandleInterrupt();
351 }
352}

◆ StartAsyncTransfer()

ErrorCode LibXR::ESP32SPI::StartAsyncTransfer ( const uint8_t * tx,
uint8_t * rx,
size_t size,
bool enable_rx,
RawData read_back,
bool mem_read,
OperationRW & op,
bool & started )
private

Definition at line 599 of file esp_spi.cpp.

602{
603 started = false;
604
605 if (!CanUseDma(size))
606 {
608 }
609 if ((tx == nullptr) || (size == 0U))
610 {
611 return ErrorCode::ARG_ERR;
612 }
613
614 spi_dma_ctx_t* ctx = ToDmaCtx(dma_ctx_);
615 if (ctx == nullptr)
616 {
617 return ErrorCode::INIT_ERR;
618 }
619
620 const bool rx_enabled = enable_rx && (rx != nullptr);
621 ConfigureTransferRegisters(size);
622
623#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE || SOC_PSRAM_DMA_CAPABLE
624 if (!CacheSyncDmaBuffer(tx, size, true))
625 {
626 return ErrorCode::FAILED;
627 }
628#endif
629
630 if (enable_rx && (rx != nullptr))
631 {
632 spicommon_dma_desc_setup_link(ctx->dmadesc_rx, rx, static_cast<int>(size), true);
633 if (DmaReset(ctx->rx_dma_chan) != ESP_OK)
634 {
635 return ErrorCode::INIT_ERR;
636 }
637 spi_hal_hw_prepare_rx(hw_);
638 if (DmaStart(ctx->rx_dma_chan, ctx->dmadesc_rx) != ESP_OK)
639 {
640 return ErrorCode::INIT_ERR;
641 }
642 }
643#if CONFIG_IDF_TARGET_ESP32
644 else
645 {
646 // Keep ESP32 full-duplex TX-only DMA behavior aligned with IDF workaround.
647 spi_ll_dma_rx_enable(hw_, true);
648 (void)DmaStart(ctx->rx_dma_chan, nullptr);
649 }
650#endif
651
652 spicommon_dma_desc_setup_link(ctx->dmadesc_tx, tx, static_cast<int>(size), false);
653 if (DmaReset(ctx->tx_dma_chan) != ESP_OK)
654 {
655 return ErrorCode::INIT_ERR;
656 }
657 spi_hal_hw_prepare_tx(hw_);
658 if (DmaStart(ctx->tx_dma_chan, ctx->dmadesc_tx) != ESP_OK)
659 {
660 return ErrorCode::INIT_ERR;
661 }
662
663#if CONFIG_IDF_TARGET_ESP32
664 spicommon_dmaworkaround_transfer_active(ctx->tx_dma_chan.chan_id);
665#endif
666
667 rw_op_ = op;
668 read_back_ = read_back;
669 mem_read_ = mem_read;
670 async_dma_size_ = size;
671 async_dma_rx_enabled_ = rx_enabled;
672 if (op.type == OperationRW::OperationType::BLOCK)
673 {
674 block_wait_.Start(*op.data.sem_info.sem);
675 }
676 started = true;
677
678 // On ESP32 classic, enable data lines only after DMA descriptors/channels are
679 // ready.
680 spi_ll_enable_mosi(hw_, 1);
681 spi_ll_enable_miso(hw_, rx_enabled ? 1 : 0);
682 spi_ll_clear_int_stat(hw_);
683 spi_ll_enable_int(hw_);
684 async_running_ = true;
685 spi_ll_apply_config(hw_);
686 spi_ll_user_start(hw_);
687
688 op.MarkAsRunning();
689 if (op.type == OperationRW::OperationType::BLOCK)
690 {
691 return block_wait_.Wait(op.data.sem_info.timeout);
692 }
693 return ErrorCode::OK;
694}

◆ SwitchBufferLocal()

void LibXR::ESP32SPI::SwitchBufferLocal ( )
private

Definition at line 529 of file esp_spi.cpp.

530{
531 if (UseLocalDoubleBuffer())
532 {
533 dbuf_active_block_ ^= 1U;
534 }
535}

◆ Transfer()

ErrorCode LibXR::ESP32SPI::Transfer ( size_t size,
OperationRW & op,
bool in_isr = false )
overridevirtual

进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).

Parameters
size需要传输的数据大小。The size of the data to be transferred.
op读写操作类型。Type of read/write operation.
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 893 of file esp_spi.cpp.

894{
895 if (size == 0U)
896 {
897 return CompleteZeroSize(op, in_isr);
898 }
899
900 const ErrorCode lock_ec = EnsureReadyAndAcquire();
901 if (lock_ec != ErrorCode::OK)
902 {
903 return lock_ec;
904 }
905
906 RawData rx = GetRxBuffer();
907 RawData tx = GetTxBuffer();
908 ASSERT(rx.size_ >= size);
909 ASSERT(tx.size_ >= size);
910
911 if (CanUseDma(size))
912 {
913 bool started = false;
914 const ErrorCode ec = StartAsyncTransfer(static_cast<const uint8_t*>(tx.addr_),
915 static_cast<uint8_t*>(rx.addr_), size, true,
916 {nullptr, 0}, false, op, started);
917 return ReturnAsyncStartResult(ec, started);
918 }
919
920 const ErrorCode ec = ExecuteTransfer(static_cast<const uint8_t*>(tx.addr_),
921 static_cast<uint8_t*>(rx.addr_), size, true);
922 if (ec == ErrorCode::OK)
923 {
924 SwitchBufferLocal();
925 }
926
927 Release();
928 return FinalizeSyncResult(op, in_isr, ec);
929}

◆ UseLocalDoubleBuffer()

bool LibXR::ESP32SPI::UseLocalDoubleBuffer ( ) const
private

Definition at line 502 of file esp_spi.cpp.

503{
504 return dbuf_enabled_ && (dbuf_rx_block_size_ > 0U) && (dbuf_tx_block_size_ > 0U);
505}

Field Documentation

◆ async_dma_rx_enabled_

bool LibXR::ESP32SPI::async_dma_rx_enabled_ = false
private

Definition at line 125 of file esp_spi.hpp.

◆ async_dma_size_

size_t LibXR::ESP32SPI::async_dma_size_ = 0
private

Definition at line 124 of file esp_spi.hpp.

◆ async_running_

bool LibXR::ESP32SPI::async_running_ = false
private

Definition at line 123 of file esp_spi.hpp.

◆ block_wait_

AsyncBlockWait LibXR::ESP32SPI::block_wait_ {}
private

Definition at line 116 of file esp_spi.hpp.

116{};

◆ busy_

Flag::Atomic LibXR::ESP32SPI::busy_ {}
private

Definition at line 107 of file esp_spi.hpp.

107{};

◆ dbuf_active_block_

uint8_t LibXR::ESP32SPI::dbuf_active_block_ = 0
private

Definition at line 115 of file esp_spi.hpp.

◆ dbuf_enabled_

bool LibXR::ESP32SPI::dbuf_enabled_ = false
private

Definition at line 117 of file esp_spi.hpp.

◆ dbuf_rx_block_size_

size_t LibXR::ESP32SPI::dbuf_rx_block_size_ = 0
private

Definition at line 113 of file esp_spi.hpp.

◆ dbuf_tx_block_size_

size_t LibXR::ESP32SPI::dbuf_tx_block_size_ = 0
private

Definition at line 114 of file esp_spi.hpp.

◆ dma_ctx_

void* LibXR::ESP32SPI::dma_ctx_ = nullptr
private

Definition at line 121 of file esp_spi.hpp.

◆ dma_enable_min_size_

uint32_t LibXR::ESP32SPI::dma_enable_min_size_ = 3U
private

Definition at line 109 of file esp_spi.hpp.

◆ dma_enabled_

bool LibXR::ESP32SPI::dma_enabled_ = false
private

Definition at line 120 of file esp_spi.hpp.

◆ dma_max_transfer_bytes_

size_t LibXR::ESP32SPI::dma_max_transfer_bytes_ = 0
private

Definition at line 122 of file esp_spi.hpp.

◆ dma_requested_

bool LibXR::ESP32SPI::dma_requested_ = true
private

Definition at line 110 of file esp_spi.hpp.

◆ dma_rx_raw_

RawData LibXR::ESP32SPI::dma_rx_raw_ = {nullptr, 0}
private

Definition at line 111 of file esp_spi.hpp.

111{nullptr, 0};

◆ dma_tx_raw_

RawData LibXR::ESP32SPI::dma_tx_raw_ = {nullptr, 0}
private

Definition at line 112 of file esp_spi.hpp.

112{nullptr, 0};

◆ host_

spi_host_device_t LibXR::ESP32SPI::host_
private

Definition at line 101 of file esp_spi.hpp.

◆ hw_

spi_dev_t* LibXR::ESP32SPI::hw_ = nullptr
private

Definition at line 102 of file esp_spi.hpp.

◆ initialized_

bool LibXR::ESP32SPI::initialized_ = false
private

Definition at line 108 of file esp_spi.hpp.

◆ intr_handle_

intr_handle_t LibXR::ESP32SPI::intr_handle_ = nullptr
private

Definition at line 118 of file esp_spi.hpp.

◆ intr_installed_

bool LibXR::ESP32SPI::intr_installed_ = false
private

Definition at line 119 of file esp_spi.hpp.

◆ MAX_DMA_TRANSFER_BYTES

size_t LibXR::ESP32SPI::MAX_DMA_TRANSFER_BYTES = SPI_LL_DMA_MAX_BIT_LEN / 8U
staticconstexprprivate

Definition at line 55 of file esp_spi.hpp.

◆ MAX_POLLING_TRANSFER_BYTES

size_t LibXR::ESP32SPI::MAX_POLLING_TRANSFER_BYTES = SOC_SPI_MAXIMUM_BUFFER_SIZE
staticconstexprprivate

Definition at line 54 of file esp_spi.hpp.

◆ mem_read_

bool LibXR::ESP32SPI::mem_read_ = false
private

Definition at line 126 of file esp_spi.hpp.

◆ miso_pin_

int LibXR::ESP32SPI::miso_pin_
private

Definition at line 104 of file esp_spi.hpp.

◆ mosi_pin_

int LibXR::ESP32SPI::mosi_pin_
private

Definition at line 105 of file esp_spi.hpp.

◆ read_back_

RawData LibXR::ESP32SPI::read_back_ = {nullptr, 0}
private

Definition at line 127 of file esp_spi.hpp.

127{nullptr, 0};

◆ rw_op_

OperationRW LibXR::ESP32SPI::rw_op_
private

Definition at line 128 of file esp_spi.hpp.

◆ sclk_pin_

int LibXR::ESP32SPI::sclk_pin_
private

Definition at line 103 of file esp_spi.hpp.

◆ source_clock_hz_

uint32_t LibXR::ESP32SPI::source_clock_hz_ = 0
private

Definition at line 106 of file esp_spi.hpp.


The documentation for this class was generated from the following files: