Skip to content

Commit 2542447

Browse files
committed
C++: I2C API
1 parent a62689a commit 2542447

File tree

24 files changed

+1353
-19
lines changed

24 files changed

+1353
-19
lines changed
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
idf_component_register(SRCS "esp_exception.cpp"
2-
INCLUDE_DIRS "include")
1+
idf_component_register(SRCS "esp_exception.cpp" "i2c_cxx.cpp"
2+
INCLUDE_DIRS "include"
3+
REQUIRES driver)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
COMPONENT_ADD_INCLUDEDIRS := include
2+
3+
COMPONENT_SRCDIRS := ./ driver
4+

examples/cxx/experimental/experimental_cpp_component/esp_exception.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
#ifdef __cpp_exceptions
216

317
#include "esp_exception.hpp"
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifdef __cpp_exceptions
16+
17+
#include "i2c_cxx.hpp"
18+
19+
using namespace std;
20+
21+
namespace idf {
22+
23+
#define I2C_CHECK_THROW(err) CHECK_THROW_SPECIFIC((err), I2CException)
24+
25+
I2CException::I2CException(esp_err_t error) : ESPException(error) { }
26+
27+
I2CTransferException::I2CTransferException(esp_err_t error) : I2CException(error) { }
28+
29+
I2CBus::I2CBus(i2c_port_t i2c_number) : i2c_num(i2c_number) { }
30+
31+
I2CBus::~I2CBus() { }
32+
33+
I2CMaster::I2CMaster(i2c_port_t i2c_number,
34+
int scl_gpio,
35+
int sda_gpio,
36+
uint32_t clock_speed,
37+
bool scl_pullup,
38+
bool sda_pullup)
39+
: I2CBus(i2c_number)
40+
{
41+
i2c_config_t conf = {};
42+
conf.mode = I2C_MODE_MASTER;
43+
conf.scl_io_num = scl_gpio;
44+
conf.scl_pullup_en = scl_pullup;
45+
conf.sda_io_num = sda_gpio;
46+
conf.sda_pullup_en = sda_pullup;
47+
conf.master.clk_speed = clock_speed;
48+
I2C_CHECK_THROW(i2c_param_config(i2c_num, &conf));
49+
I2C_CHECK_THROW(i2c_driver_install(i2c_num, conf.mode, 0, 0, 0));
50+
}
51+
52+
I2CMaster::~I2CMaster()
53+
{
54+
i2c_driver_delete(i2c_num);
55+
}
56+
57+
void I2CMaster::sync_write(uint8_t i2c_addr, const vector<uint8_t> &data)
58+
{
59+
I2CWrite writer(data);
60+
61+
writer.do_transfer(i2c_num, i2c_addr);
62+
}
63+
64+
std::vector<uint8_t> I2CMaster::sync_read(uint8_t i2c_addr, size_t n_bytes)
65+
{
66+
I2CRead reader(n_bytes);
67+
68+
return reader.do_transfer(i2c_num, i2c_addr);
69+
}
70+
71+
vector<uint8_t> I2CMaster::sync_transfer(uint8_t i2c_addr,
72+
const std::vector<uint8_t> &write_data,
73+
size_t read_n_bytes)
74+
{
75+
if (!read_n_bytes) throw I2CException(ESP_ERR_INVALID_ARG);
76+
77+
I2CComposed composed_transfer;
78+
composed_transfer.add_write(write_data);
79+
composed_transfer.add_read(read_n_bytes);
80+
81+
return composed_transfer.do_transfer(i2c_num, i2c_addr)[0];
82+
}
83+
84+
I2CSlave::I2CSlave(i2c_port_t i2c_number,
85+
int scl_gpio,
86+
int sda_gpio,
87+
uint8_t slave_addr,
88+
size_t rx_buf_len,
89+
size_t tx_buf_len,
90+
bool scl_pullup,
91+
bool sda_pullup)
92+
: I2CBus(i2c_number)
93+
{
94+
i2c_config_t conf = {};
95+
conf.mode = I2C_MODE_SLAVE;
96+
conf.scl_io_num = scl_gpio;
97+
conf.scl_pullup_en = scl_pullup;
98+
conf.sda_io_num = sda_gpio;
99+
conf.sda_pullup_en = sda_pullup;
100+
conf.slave.addr_10bit_en = 0;
101+
conf.slave.slave_addr = slave_addr;
102+
I2C_CHECK_THROW(i2c_param_config(i2c_num, &conf));
103+
I2C_CHECK_THROW(i2c_driver_install(i2c_num, conf.mode, rx_buf_len, tx_buf_len, 0));
104+
}
105+
106+
I2CSlave::~I2CSlave()
107+
{
108+
i2c_driver_delete(i2c_num);
109+
}
110+
111+
int I2CSlave::write_raw(const uint8_t *data, size_t data_len, chrono::milliseconds timeout)
112+
{
113+
return i2c_slave_write_buffer(i2c_num, data, data_len, (TickType_t) timeout.count() / portTICK_RATE_MS);
114+
}
115+
116+
int I2CSlave::read_raw(uint8_t *buffer, size_t buffer_len, chrono::milliseconds timeout)
117+
{
118+
return i2c_slave_read_buffer(i2c_num, buffer, buffer_len, (TickType_t) timeout.count() / portTICK_RATE_MS);
119+
}
120+
121+
I2CWrite::I2CWrite(const vector<uint8_t> &bytes, chrono::milliseconds driver_timeout)
122+
: I2CTransfer<void>(driver_timeout), bytes(bytes) { }
123+
124+
void I2CWrite::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
125+
{
126+
I2C_CHECK_THROW(i2c_master_start(handle));
127+
I2C_CHECK_THROW(i2c_master_write_byte(handle, i2c_addr << 1 | I2C_MASTER_WRITE, true));
128+
I2C_CHECK_THROW(i2c_master_write(handle, bytes.data(), bytes.size(), true));
129+
}
130+
131+
void I2CWrite::process_result() { }
132+
133+
I2CRead::I2CRead(size_t size, chrono::milliseconds driver_timeout)
134+
: I2CTransfer<vector<uint8_t> >(driver_timeout), bytes(size) { }
135+
136+
void I2CRead::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
137+
{
138+
I2C_CHECK_THROW(i2c_master_start(handle));
139+
I2C_CHECK_THROW(i2c_master_write_byte(handle, i2c_addr << 1 | I2C_MASTER_READ, true));
140+
I2C_CHECK_THROW(i2c_master_read(handle, bytes.data(), bytes.size(), I2C_MASTER_LAST_NACK));
141+
}
142+
143+
vector<uint8_t> I2CRead::process_result()
144+
{
145+
return bytes;
146+
}
147+
148+
I2CComposed::I2CComposed(chrono::milliseconds driver_timeout)
149+
: I2CTransfer<vector<vector<uint8_t> > >(driver_timeout), transfer_list() { }
150+
151+
void I2CComposed::CompTransferNodeRead::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
152+
{
153+
I2C_CHECK_THROW(i2c_master_write_byte(handle, i2c_addr << 1 | I2C_MASTER_READ, true));
154+
I2C_CHECK_THROW(i2c_master_read(handle, bytes.data(), bytes.size(), I2C_MASTER_LAST_NACK));
155+
}
156+
157+
void I2CComposed::CompTransferNodeRead::process_result(std::vector<std::vector<uint8_t> > &read_results)
158+
{
159+
read_results.push_back(bytes);
160+
}
161+
162+
void I2CComposed::CompTransferNodeWrite::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
163+
{
164+
I2C_CHECK_THROW(i2c_master_write_byte(handle, i2c_addr << 1 | I2C_MASTER_WRITE, true));
165+
I2C_CHECK_THROW(i2c_master_write(handle, bytes.data(), bytes.size(), true));
166+
}
167+
168+
void I2CComposed::add_read(size_t size)
169+
{
170+
if (!size) throw I2CException(ESP_ERR_INVALID_ARG);
171+
172+
transfer_list.push_back(make_shared<CompTransferNodeRead>(size));
173+
}
174+
175+
void I2CComposed::add_write(std::vector<uint8_t> bytes)
176+
{
177+
if (bytes.empty()) throw I2CException(ESP_ERR_INVALID_ARG);
178+
179+
transfer_list.push_back(make_shared<CompTransferNodeWrite>(bytes));
180+
}
181+
182+
void I2CComposed::queue_cmd(i2c_cmd_handle_t handle, uint8_t i2c_addr)
183+
{
184+
for (auto it = transfer_list.begin(); it != transfer_list.end(); it++) {
185+
I2C_CHECK_THROW(i2c_master_start(handle));
186+
(*it)->queue_cmd(handle, i2c_addr);
187+
}
188+
}
189+
190+
std::vector<std::vector<uint8_t> > I2CComposed::process_result()
191+
{
192+
std::vector<std::vector<uint8_t> > results;
193+
for (auto it = transfer_list.begin(); it != transfer_list.end(); it++) {
194+
(*it)->process_result(results);
195+
}
196+
return results;
197+
}
198+
199+
} // idf
200+
201+
#endif // __cpp_exceptions

examples/cxx/experimental/experimental_cpp_component/include/esp_exception.hpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#ifndef ESP_EXCEPTION_HPP_
16-
#define ESP_EXCEPTION_HPP_
15+
#pragma once
1716

1817
#ifdef __cpp_exceptions
1918

@@ -35,10 +34,21 @@ struct ESPException : public std::exception {
3534
/**
3635
* Convenience macro to help converting IDF error codes into ESPException.
3736
*/
38-
#define CHECK_THROW(error_) if (error_ != ESP_OK) throw idf::ESPException(error_);
37+
#define CHECK_THROW(error_) \
38+
do { \
39+
esp_err_t result = error_; \
40+
if (result != ESP_OK) throw idf::ESPException(result); \
41+
} while (0)
42+
43+
/**
44+
* Convenience macro to help converting IDF error codes into a child of ESPException.
45+
*/
46+
#define CHECK_THROW_SPECIFIC(error_, exception_type_) \
47+
do { \
48+
esp_err_t result = error_; \
49+
if (result != ESP_OK) throw idf::exception_type_(result); \
50+
} while (0)
3951

4052
} // namespace idf
4153

4254
#endif // __cpp_exceptions
43-
44-
#endif // ESP_EXCEPTION_HPP_

0 commit comments

Comments
 (0)